diff --git a/.gitignore b/.gitignore index d35b250f77b..f1052671c3f 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ syntax: glob *.log.* */gamelogs */gamelogsJson +*/gamesHistory # Mage.Client Mage.Client/plugins/images diff --git a/.travis.yml b/.travis.yml index f665f8924cd..91b52ed33ab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ git: before_install: - echo "MAVEN_OPTS='-Xmx2g'" > ~/.mavenrc script: - - mvn test -B -Dlog4j.configuration=file:${TRAVIS_BUILD_DIR}/.travis/log4j.properties + - mvn test -B -Dxmage.dataCollectors.printGameLogs=false -Dlog4j.configuration=file:${TRAVIS_BUILD_DIR}/.travis/log4j.properties cache: directories: - $HOME/.m2 \ No newline at end of file diff --git a/Mage.Client/pom.xml b/Mage.Client/pom.xml index d27d1ff605e..6f7b308bc65 100644 --- a/Mage.Client/pom.xml +++ b/Mage.Client/pom.xml @@ -87,14 +87,6 @@ jetlang 0.2.23 - - - - com.amazonaws - aws-java-sdk-s3 - 1.12.78 - - com.jgoodies diff --git a/Mage.Client/src/main/java/mage/client/constants/Constants.java b/Mage.Client/src/main/java/mage/client/constants/Constants.java index 8b051f6c985..e40bdc36a8b 100644 --- a/Mage.Client/src/main/java/mage/client/constants/Constants.java +++ b/Mage.Client/src/main/java/mage/client/constants/Constants.java @@ -63,6 +63,9 @@ public final class Constants { public static final String RESOURCE_SYMBOL_FOLDER_SVG = "svg"; public static final String RESOURCE_SYMBOL_FOLDER_PNG = "png"; + // download rarity icons to large folder by default + public static final String RESOURCE_PATH_SYMBOLS_RARITY_DEFAULT_PATH = RESOURCE_PATH_SYMBOLS + File.separator + RESOURCE_SYMBOL_FOLDER_LARGE; + public enum ResourceSymbolSize { SMALL, // TODO: delete SMALL, MEDIUM and LARGE as outdated (svg or generated png works fine) MEDIUM, @@ -74,12 +77,12 @@ public final class Constants { // resources - sets public static final String RESOURCE_PATH_SETS = File.separator + "sets"; public static final String RESOURCE_SET_FOLDER_SMALL = "small"; - public static final String RESOURCE_SET_FOLDER_MEDIUM = ""; // empty, medium images laydown in "sets" folder, TODO: delete that and auto gen, use png for html, not gif + public static final String RESOURCE_SET_FOLDER_LARGE = "large"; public static final String RESOURCE_SET_FOLDER_SVG = "svg"; public enum ResourceSetSize { SMALL, - MEDIUM, + LARGE, SVG } diff --git a/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorPool.java b/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorPool.java index 3f611168e97..904eea401a4 100644 --- a/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorPool.java +++ b/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorPool.java @@ -44,7 +44,7 @@ public class DeckGeneratorPool { // List of cards so far in the deck private final List deckCards = new ArrayList<>(); // List of reserve cards found to fix up undersized decks - private final List reserveSpells = new ArrayList<>(); + private final Map reserveSpells = new HashMap<>(); private final Deck deck; /** @@ -170,12 +170,13 @@ public class DeckGeneratorPool { * @param card the card to add. */ public void addCard(Card card) { - Object cnt = cardCounts.get((card.getName())); - if (cnt == null) - cardCounts.put(card.getName(), 0); - int existingCount = cardCounts.get((card.getName())); - cardCounts.put(card.getName(), existingCount + 1); + int count = cardCounts.getOrDefault(card.getName(), 0); + cardCounts.put(card.getName(), count + 1); deckCards.add(card); + + if (deckCards.stream().distinct().collect(Collectors.toList()).size() != deckCards.size()) { + System.out.println("wtf " + card.getName()); + } } public void clearCards(boolean isClearReserve) { @@ -198,8 +199,8 @@ public class DeckGeneratorPool { // Only cards with CMC < 7 and don't already exist in the deck // can be added to our reserve pool as not to overwhelm the curve // with high CMC cards and duplicates. - if (cardCMC < 7 && getCardCount(card.getName()) == 0) { - this.reserveSpells.add(card); + if (cardCMC < 7 && getCardCount(card.getName()) == 0 && !this.reserveSpells.containsKey(card.getName())) { + this.reserveSpells.put(card.getName(), card); return true; } return false; @@ -416,48 +417,38 @@ public class DeckGeneratorPool { * @return a fixed list of cards for this deck. */ private List getFixedSpells() { - int spellSize = deckCards.size(); + int spellsSize = deckCards.size(); int nonLandSize = (deckSize - landCount); - // Less spells than needed - if (spellSize < nonLandSize) { - - int spellsNeeded = nonLandSize - spellSize; - - // If we haven't got enough spells in reserve to fulfil the amount we need, skip adding any. - if (reserveSpells.size() >= spellsNeeded) { - - List spellsToAdd = new ArrayList<>(spellsNeeded); - - // Initial reservoir - for (int i = 0; i < spellsNeeded; i++) - spellsToAdd.add(reserveSpells.get(i)); - - for (int i = spellsNeeded + 1; i < reserveSpells.size() - 1; i++) { - int j = RandomUtil.nextInt(i); - Card randomCard = reserveSpells.get(j); - if (isValidSpellCard(randomCard) && j < spellsToAdd.size()) { - spellsToAdd.set(j, randomCard); - } + // fewer spells than needed - add + if (spellsSize < nonLandSize) { + int needExtraSpells = nonLandSize - spellsSize; + List possibleSpells = new ArrayList<>(reserveSpells.values()); + while (needExtraSpells > 0) { + Card card = RandomUtil.randomFromCollection(possibleSpells); + if (card == null) { + break; } - // Add randomly selected spells needed - deckCards.addAll(spellsToAdd); + if (isValidSpellCard(card)) { + needExtraSpells--; + deckCards.add(card); + } + possibleSpells.remove(card); } } - // More spells than needed - else if (spellSize > (deckSize - landCount)) { - int spellsRemoved = (spellSize) - (deckSize - landCount); - for (int i = 0; i < spellsRemoved; ++i) { - deckCards.remove(RandomUtil.nextInt(deckCards.size())); + // more spells than needed - remove + if (spellsSize > nonLandSize) { + int removeCount = spellsSize - nonLandSize; + for (int i = 0; i < removeCount; ++i) { + deckCards.remove(RandomUtil.randomFromCollection(deckCards)); } } - // Check we have exactly the right amount of cards for a deck. if (deckCards.size() != nonLandSize) { - logger.info("Can't generate full deck for selected settings - try again or choose more sets and less colors"); + logger.info("Can't generate full deck for selected settings - try again or choose more sets and less colors (wrong non land cards amount)"); } - // Return the fixed amount + return deckCards; } @@ -619,48 +610,75 @@ public class DeckGeneratorPool { if (needCommandersCount > 0 && !genPool.cardCounts.isEmpty()) { throw new IllegalArgumentException("Wrong code usage: generateSpells with creatures and commanders must be called as first"); } - List cardPool = CardRepository.instance.findCards(criteria); + List cardsPool = CardRepository.instance.findCards(criteria).stream() + .map(CardInfo::createMockCard) + .filter(genPool::isValidSpellCard) + .collect(Collectors.toList()); + List commandersPool = cardsPool.stream() + .filter(genPool::isValidCommander) + .collect(Collectors.toList()); + List deckCMCs = genPool.getCMCsForSpellCount(needCardsCount); - int count = 0; + int usedCardsCount = 0; int validCommanders = 0; int reservesAdded = 0; - if (cardPool.size() > 0 && cardPool.size() >= needCardsCount) { + if (cardsPool.size() > 0 && cardsPool.size() >= needCardsCount) { int tries = 0; + List possibleCards = new ArrayList<>(cardsPool); + List possibleCommanders = new ArrayList<>(commandersPool); while (true) { tries++; // can't finish deck, stop and use reserved cards later if (tries > DeckGenerator.MAX_TRIES) { - logger.info("Can't generate full deck for selected settings - try again or choose more sets and less colors"); + logger.info("Can't generate full deck for selected settings - try again or choose more sets and less colors (max tries exceeded)"); break; } // can finish deck - but make sure it has commander - if (count >= needCardsCount) { + if (usedCardsCount >= needCardsCount) { if (validCommanders < needCommandersCount) { // reset deck search from scratch (except reserved cards) - count = 0; + usedCardsCount = 0; validCommanders = 0; deckCMCs = genPool.getCMCsForSpellCount(needCardsCount); - genPool.clearCards(false); + genPool.clearCards(true); + possibleCards = new ArrayList<>(cardsPool); + possibleCommanders = new ArrayList<>(commandersPool); continue; } break; } - Card card = cardPool.get(RandomUtil.nextInt(cardPool.size())).createMockCard(); + if (possibleCards.isEmpty()) { + throw new IllegalStateException("Not enough cards to generate deck (possible cards is empty)"); + } + + // choose commander first + Card card = null; + if (validCommanders < needCommandersCount && !possibleCommanders.isEmpty()) { + card = RandomUtil.randomFromCollection(possibleCommanders); + } + + // choose other cards after commander + if (card == null) { + card = RandomUtil.randomFromCollection(possibleCards); + } + if (!genPool.isValidSpellCard(card)) { + possibleCards.remove(card); + possibleCommanders.remove(card); continue; } int cardCMC = card.getManaValue(); for (DeckGeneratorCMC.CMC deckCMC : deckCMCs) { if (cardCMC >= deckCMC.min && cardCMC <= deckCMC.max) { - int currentAmount = deckCMC.getAmount(); - if (currentAmount > 0) { - deckCMC.setAmount(currentAmount - 1); + int needAmount = deckCMC.getAmount(); + if (needAmount > 0) { + deckCMC.setAmount(needAmount - 1); genPool.addCard(card.copy()); - count++; + usedCardsCount++; // make sure it has compatible commanders if (genPool.isValidCommander(card)) { validCommanders++; @@ -674,7 +692,7 @@ public class DeckGeneratorPool { } } } else { - throw new IllegalStateException("Not enough cards to generate deck."); + throw new IllegalStateException("Not enough cards to generate deck (cards pool too small)"); } } diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.java b/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.java index 326b38bbea9..af9528f5e77 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.java @@ -19,7 +19,6 @@ import mage.client.dialog.AddLandDialog; import mage.client.dialog.PreferencesDialog; import mage.client.plugins.impl.Plugins; import mage.client.util.Event; -import mage.client.util.GUISizeHelper; import mage.client.util.Listener; import mage.client.util.audio.AudioManager; import mage.components.CardInfoPane; @@ -31,7 +30,6 @@ import mage.util.XmageThreadFactory; import mage.view.CardView; import mage.view.SimpleCardView; import org.apache.log4j.Logger; -import org.mage.card.arcane.ManaSymbols; import javax.swing.*; import javax.swing.border.Border; @@ -534,7 +532,8 @@ public class DeckEditorPanel extends javax.swing.JPanel { } } }); - refreshDeck(true); + + refreshDeck(true, false); // auto-import dropped files from OS if (mode == DeckEditorMode.FREE_BUILDING) { @@ -673,20 +672,28 @@ public class DeckEditorPanel extends javax.swing.JPanel { private void refreshDeck() { if (this.isVisible()) { // TODO: test auto-close deck with active lands dialog, e.g. on timeout - refreshDeck(false); + refreshDeck(false, false); } } - private void refreshDeck(boolean useLayout) { + private void refreshDeck(boolean useLayout, boolean useDeckValidation) { try { - setCursor(new Cursor(Cursor.WAIT_CURSOR)); + MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR)); this.txtDeckName.setText(deck.getName()); deckArea.loadDeck(deck, useLayout, bigCard); + if (useDeckValidation) { + validateDeck(); + } } finally { - setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); } } + private void validateDeck() { + this.deckLegalityDisplay.setVisible(true); + this.deckLegalityDisplay.validateDeck(deck); + } + private void setTimeout(int s) { int minute = s / 60; int second = s - (minute * 60); @@ -762,7 +769,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { if (newDeck != null) { deck = newDeck; - refreshDeck(); + refreshDeck(false, true); } // save last deck import folder @@ -818,7 +825,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { Deck deckToAppend = Deck.load(DeckImporter.importDeckFromFile(tempDeckPath, errorMessages, false), true, true); processAndShowImportErrors(errorMessages); this.deck = Deck.append(deckToAppend, this.deck); - refreshDeck(); + refreshDeck(false, true); } catch (GameException e1) { JOptionPane.showMessageDialog(MageFrame.getDesktop(), e1.getMessage(), "Error loading deck", JOptionPane.ERROR_MESSAGE); } finally { @@ -922,7 +929,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { if (newDeck != null) { deck = newDeck; - refreshDeck(); + refreshDeck(false, true); return true; } @@ -1441,7 +1448,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { if (newDeck != null) { deck = newDeck; - refreshDeck(true); + refreshDeck(true, true); } // save last deck history @@ -1474,7 +1481,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { // in deck editor mode - clear all cards deck = new Deck(); } - refreshDeck(); + refreshDeck(false, true); }//GEN-LAST:event_btnNewActionPerformed private void btnExitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnExitActionPerformed @@ -1483,7 +1490,9 @@ public class DeckEditorPanel extends javax.swing.JPanel { private void btnAddLandActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAddLandActionPerformed AddLandDialog dialog = new AddLandDialog(); - dialog.showDialog(deck, mode, this::refreshDeck); + dialog.showDialog(deck, mode, () -> { + this.refreshDeck(false, true); + }); }//GEN-LAST:event_btnAddLandActionPerformed private void btnGenDeckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnGenDeckActionPerformed @@ -1501,7 +1510,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { } finally { MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); } - refreshDeck(); + refreshDeck(false, true); }//GEN-LAST:event_btnGenDeckActionPerformed private void btnSubmitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSubmitActionPerformed @@ -1548,8 +1557,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { }//GEN-LAST:event_btnExportActionPerformed private void btnLegalityActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnLegalityActionPerformed - this.deckLegalityDisplay.setVisible(true); - this.deckLegalityDisplay.validateDeck(deck); + validateDeck(); }//GEN-LAST:event_btnLegalityActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/Mage.Client/src/main/java/mage/client/draft/DraftPickLogger.java b/Mage.Client/src/main/java/mage/client/draft/DraftPickLogger.java index db585e1a227..90c094fd055 100644 --- a/Mage.Client/src/main/java/mage/client/draft/DraftPickLogger.java +++ b/Mage.Client/src/main/java/mage/client/draft/DraftPickLogger.java @@ -75,7 +75,7 @@ public class DraftPickLogger { private void appendToDraftLog(String data) { if (logging) { try { - Files.write(logPath, data.getBytes(), StandardOpenOption.APPEND); + Files.write(logPath, data.getBytes(), StandardOpenOption.CREATE, StandardOpenOption.APPEND); } catch (IOException ex) { LOGGER.error(null, ex); } diff --git a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java index 3fb8dcea16f..cc1be98996a 100644 --- a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java +++ b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java @@ -257,10 +257,7 @@ public class CallbackClientImpl implements CallbackClient { if (panel != null) { Session session = SessionHandler.getSession(); if (session.isJsonLogActive()) { - UUID gameId = callback.getObjectId(); appendJsonEvent("GAME_OVER", callback.getObjectId(), message); - String logFileName = "game-" + gameId + ".json"; - S3Uploader.upload(logFileName, gameId.toString()); } panel.endMessage(callback.getMessageId(), message.getGameView(), message.getOptions(), message.getMessage()); } diff --git a/Mage.Client/src/main/java/mage/client/remote/S3Uploader.java b/Mage.Client/src/main/java/mage/client/remote/S3Uploader.java deleted file mode 100644 index 85968f6ea03..00000000000 --- a/Mage.Client/src/main/java/mage/client/remote/S3Uploader.java +++ /dev/null @@ -1,46 +0,0 @@ -package mage.client.remote; - -import com.amazonaws.AmazonClientException; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.services.s3.transfer.TransferManager; -import com.amazonaws.services.s3.transfer.Upload; -import org.apache.log4j.Logger; - -import java.io.File; - -public class S3Uploader { - - private static final Logger logger = Logger.getLogger(S3Uploader.class); - - public static Boolean upload(String filePath, String keyName) throws Exception { - String existingBucketName = System.getenv("S3_BUCKET") != null ? System.getenv("S3_BUCKET") - : "xmage-game-logs-dev"; - - String accessKeyId = System.getenv("AWS_ACCESS_ID"); - String secretKeyId = System.getenv("AWS_SECRET_KEY"); - - if (accessKeyId == null || accessKeyId.isEmpty() - || secretKeyId == null || secretKeyId.isEmpty() - || existingBucketName.isEmpty()) { - logger.info("Aborting json log sync."); - return false; - } - - String path = new File("./" + filePath).getCanonicalPath(); - logger.info("Syncing " + path + " to bucket: " + existingBucketName + " with AWS Access Id: " + accessKeyId); - - BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKeyId, secretKeyId); - TransferManager tm = new TransferManager(awsCreds); - Upload upload = tm.upload(existingBucketName, "/game/" + keyName + ".json", new File(path)); - - try { - upload.waitForUploadResult(); - logger.info("Sync Complete For " + path + " to bucket: " + existingBucketName + " with AWS Access Id: " + accessKeyId); - new File(path); - return true; - } catch (AmazonClientException amazonClientException) { - logger.fatal("Unable to upload file, upload was aborted.", amazonClientException); - return false; - } - } -} diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java index 302fe95ffbb..0cb2e6e4242 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java @@ -896,7 +896,7 @@ public class TablesPanel extends javax.swing.JPanel { formatFilterList.add(RowFilter.regexFilter("^Limited", TablesTableModel.COLUMN_DECK_TYPE)); } if (btnFormatOther.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Momir Basic|^Constructed - Pauper|^Constructed - Frontier|^Constructed - Extended|^Constructed - Eternal|^Constructed - Historical|^Constructed - Super|^Constructed - Freeform|^Australian Highlander|^European Highlander|^Canadian Highlander|^Constructed - Old|^Constructed - Historic", TablesTableModel.COLUMN_DECK_TYPE)); + formatFilterList.add(RowFilter.regexFilter("^Momir Basic|^Constructed - Pauper|^Constructed - Frontier|^Constructed - Extended|^Constructed - Eternal|^Constructed - Historical|^Constructed - Super|^Constructed - Freeform|^Constructed - Freeform Unlimited|^Australian Highlander|^European Highlander|^Canadian Highlander|^Constructed - Old|^Constructed - Historic", TablesTableModel.COLUMN_DECK_TYPE)); } // skill diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java b/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java index dd77bf28980..e9d05e19d23 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java @@ -89,11 +89,6 @@ public final class ManaSymbols { public static void loadImages() { logger.info("Symbols: loading..."); - // TODO: delete files rename jpg->gif (it was for backward compatibility for one of the old version?) - renameSymbols(getResourceSymbolsPath(ResourceSymbolSize.SMALL)); - renameSymbols(getResourceSymbolsPath(ResourceSymbolSize.MEDIUM)); - renameSymbols(getResourceSymbolsPath(ResourceSymbolSize.LARGE)); - //renameSymbols(getSymbolsPath(ResourceSymbolSize.SVG)); // not need // TODO: remove medium sets files to "medium" folder like symbols above? // prepare svg's css settings @@ -145,9 +140,9 @@ public final class ManaSymbols { Map rarityImages = new EnumMap<>(Rarity.class); setImages.put(set, rarityImages); - // load medium size + // load large size for (Rarity rarityCode : codes) { - File file = new File(getResourceSetsPath(ResourceSetSize.MEDIUM) + set + '-' + rarityCode.getCode() + ".jpg"); + File file = new File(getResourceSetsPath(ResourceSetSize.LARGE) + set + '-' + rarityCode.getCode() + ".png"); try { Image image = UI.getImageIcon(file.getAbsolutePath()).getImage(); int width = image.getWidth(null); @@ -167,7 +162,7 @@ public final class ManaSymbols { // generate small size try { - File file = new File(getResourceSetsPath(ResourceSetSize.MEDIUM)); + File file = new File(getResourceSetsPath(ResourceSetSize.LARGE)); if (!file.exists()) { file.mkdirs(); } @@ -175,11 +170,11 @@ public final class ManaSymbols { for (Rarity code : codes) { File newFile = new File(pathRoot + '-' + code + ".png"); if (!(MageFrame.isSkipSmallSymbolGenerationForExisting() && newFile.exists())) {// skip if option enabled and file already exists - file = new File(getResourceSetsPath(ResourceSetSize.MEDIUM) + set + '-' + code + ".png"); + file = new File(getResourceSetsPath(ResourceSetSize.LARGE) + set + '-' + code + ".png"); if (file.exists()) { continue; } - file = new File(getResourceSetsPath(ResourceSetSize.MEDIUM) + set + '-' + code + ".jpg"); + file = new File(getResourceSetsPath(ResourceSetSize.LARGE) + set + '-' + code + ".png"); Image image = UI.getImageIcon(file.getAbsolutePath()).getImage(); try { int width = image.getWidth(null); @@ -239,7 +234,7 @@ public final class ManaSymbols { } } - private static File getSymbolFileNameAsGIF(String symbol, int size) { + private static File getSymbolFileNameAsPNG(String symbol, int size) { ResourceSymbolSize needSize = null; if (size <= 15) { @@ -250,15 +245,15 @@ public final class ManaSymbols { needSize = ResourceSymbolSize.LARGE; } - return new File(getResourceSymbolsPath(needSize) + symbol + ".gif"); + return new File(getResourceSymbolsPath(needSize) + symbol + ".png"); } - private static BufferedImage loadSymbolAsGIF(String symbol, int resizeToWidth, int resizeToHeight) { - File file = getSymbolFileNameAsGIF(symbol, resizeToWidth); - return loadSymbolAsGIF(file, resizeToWidth, resizeToHeight); + private static BufferedImage loadSymbolAsPNG(String symbol, int resizeToWidth, int resizeToHeight) { + File file = getSymbolFileNameAsPNG(symbol, resizeToWidth); + return loadSymbolAsPNG(file, resizeToWidth, resizeToHeight); } - private static BufferedImage loadSymbolAsGIF(File sourceFile, int resizeToWidth, int resizeToHeight) { + private static BufferedImage loadSymbolAsPNG(File sourceFile, int resizeToWidth, int resizeToHeight) { BufferedImage image = null; @@ -315,9 +310,9 @@ public final class ManaSymbols { // gif (if svg fails) if (image == null) { - file = getSymbolFileNameAsGIF(symbol, size); + file = getSymbolFileNameAsPNG(symbol, size); if (file.exists()) { - image = loadSymbolAsGIF(file, size, size); + image = loadSymbolAsPNG(file, size, size); } } if (image == null) { @@ -352,29 +347,6 @@ public final class ManaSymbols { return errorInfo.isEmpty(); } - private static void renameSymbols(String path) { - File file = new File(path); - if (!file.exists()) { - return; - } - - final PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:**/*.jpg"); - try { - Files.walkFileTree(Paths.get(path), new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - if (matcher.matches(file)) { - Path gifPath = file.resolveSibling(file.getFileName().toString().replaceAll("\\.jpg$", ".gif")); - Files.move(file, gifPath, StandardCopyOption.REPLACE_EXISTING); - } - return FileVisitResult.CONTINUE; - } - }); - } catch (IOException e) { - logger.error("Couldn't rename mana symbols on " + path, e); - } - } - private static String getResourceSymbolsPath(ResourceSymbolSize needSize) { // return real path to symbols (default or user defined) @@ -420,8 +392,8 @@ public final class ManaSymbols { case SMALL: path = path + Constants.RESOURCE_SET_FOLDER_SMALL; break; - case MEDIUM: - path = path + Constants.RESOURCE_SET_FOLDER_MEDIUM; + case LARGE: + path = path + Constants.RESOURCE_SET_FOLDER_LARGE; break; case SVG: path = path + Constants.RESOURCE_SET_FOLDER_SVG; diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/CardPluginImpl.java b/Mage.Client/src/main/java/org/mage/plugins/card/CardPluginImpl.java index e3288ff43c7..acdd0aec2d5 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/CardPluginImpl.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/CardPluginImpl.java @@ -663,7 +663,9 @@ public class CardPluginImpl implements CardPlugin { // mana symbols (low quality) jobs = new GathererSymbols(); for (DownloadJob job : jobs) { - downloader.add(job); + // TODO: gatherer removed mana symbols icons after 2025, see https://github.com/magefree/mage/issues/13797 + // remove GathererSymbols code after few releases as unused (2025.06.28) + // downloader.add(job); } // set code symbols (low quality) diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/Downloader.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/Downloader.java index ad44256a076..57ca99791f9 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/Downloader.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/Downloader.java @@ -46,8 +46,10 @@ public class Downloader extends AbstractLaternaBean { public Downloader() { // prepare 10 threads and start to waiting new download jobs from queue + // TODO: gatherer website has download rate limits, so limit max threads as temporary solution + int maxThreads = 3; PoolFiberFactory f = new PoolFiberFactory(pool); - for (int i = 0, numThreads = 10; i < numThreads; i++) { + for (int i = 0, numThreads = maxThreads; i < numThreads; i++) { Fiber fiber = f.create(); fiber.start(); fibers.add(fiber); diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java index f12baabcae2..7a5c97ab04d 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java @@ -16,7 +16,9 @@ import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir; /** * Download: set code symbols download from wizards web size *

- * Warning, it's outdated source with low quality images. TODO: must migrate to scryfall like mana icons + * Warning, it's outdated source with low quality images. + * TODO: must migrate to scryfall like mana icons, + * see https://github.com/magefree/mage/issues/13261 */ public class GathererSets implements Iterable { @@ -41,9 +43,10 @@ public class GathererSets implements Iterable { private static File outDir; - private static final int DAYS_BEFORE_RELEASE_TO_DOWNLOAD = +14; // Try to load the symbolsBasic eralies 14 days before release date + private static final int DAYS_BEFORE_RELEASE_TO_DOWNLOAD = +14; // Try to load the symbolsBasic 14 days before release date private static final Logger logger = Logger.getLogger(GathererSets.class); + // TODO: find all possible sets from ExpansionRepository instead custom private static final String[] symbolsBasic = {"10E", "9ED", "8ED", "7ED", "6ED", "5ED", "4ED", "3ED", "2ED", "LEB", "LEA", "HOP", "ARN", "ATQ", "LEG", "DRK", "FEM", "HML", @@ -61,14 +64,16 @@ public class GathererSets implements Iterable { "TSP", "TSB", "PLC", "FUT", "LRW", "MOR", "SHM", "EVE", - "MED", "ME2", "ME3", "ME4", + "ME2", "ME3", "ME4", "POR", "P02", "PTK", "ARC", "DD3EVG", - "W16", "W17", + "W16", "W17", // "PALP" -- Gatherer does not have the set Asia Pacific Land Program // "ATH" -- has cards from many sets, symbol does not exist on gatherer // "CP", "DPA", "PELP", "PGPX", "PGRU", "H17", "JR", "SWS", // need to fix - "H09", "PD2", "PD3", "UNH", "CM1", "V11", "A25", "UST", "IMA", "DD2", "EVG", "DDC", "DDE", "DDD", "CHR", "G18", "GVL", "S00", "S99", "UGL" // ok + "H09", "PD2", "PD3", "UNH", "CM1", "V11", "A25", "UST", "IMA", "DD2", + "EVG", "DDC", "DDE", "DDD", "CHR", "G18", "GVL", "S00", "S99", "UGL", + "BTD" // ok // current testing }; @@ -98,21 +103,25 @@ public class GathererSets implements Iterable { "GNT", "UMA", "GRN", "RNA", "WAR", "MH1", "M20", - "C19", "ELD", "MB1", "GN2", "J20", "THB", "UND", "C20", "IKO", "M21", + "C19", "ELD", "MB1", "GN2", "THB", "UND", "C20", "IKO", "M21", "JMP", "2XM", "ZNR", "KLR", "CMR", "KHC", "KHM", "TSR", "STX", "STA", "C21", "MH2", "AFR", "AFC", "J21", "MID", "MIC", "VOW", "VOC", "YMID", - "NEC", "YNEO", "NEO", "SNC", "NCC", "CLB", "2X2", "DMU", "DMC", "YDMU", "40K", "GN3", - "UNF", "BRO", "BRC", "BOT", "30A", "J22", "SCD", "DMR", "ONE", "ONC", + "NEC", "YNEO", "NEO", "SNC", "NCC", "CLB", "2X2", "DMU", "DMC", "40K", "GN3", + "UNF", "BRO", "BRC", "BOT", "J22", "DMR", "ONE", "ONC", "MOM", "MOC", "MUL", "MAT", "LTR", "CMM", "WOE", "WHO", "RVR", "WOT", "WOC", "SPG", "LCI", "LCC", "REX", "PIP", "MKM", "MKC", "CLU", "OTJ", - "OTC", "OTP", "BIG", "MH3", "M3C", "ACR", "BLB" + "OTC", "OTP", "BIG", "MH3", "M3C", "ACR", "BLB", "BLC", "DSK", "DSC", + "MB2", "FDN", "INR", "J25", "DRC", "DFT", "TDC", "TDM", "FCA", "FIC", + "FIN", "SIS", "SIR", "SLD", "AKR", "MD1", "ANB", "LTC", "BRR", "HA1", + "HA2", "HA3", "HA4", "HA5", "ZNC", "EOE", "EOC", "SPE", "TLA" // "HHO", "ANA" -- do not exist on gatherer }; private static final String[] symbolsOnlyMyth = { - "DRB", "V09", "V10", "V12", "V13", "V14", "V15", "V16", "V17", "EXP", "MED" + "DRB", "V09", "V10", "V12", "V13", "V14", "V15", "V16", "V17", "EXP", "MED", "ZNE" // "HTR16" does not exist }; + private static final String[] symbolsOnlySpecial = { "MPS", "MP2" }; @@ -130,6 +139,7 @@ public class GathererSets implements Iterable { codeReplacements.put("APC", "AP"); codeReplacements.put("ARN", "AN"); codeReplacements.put("ATQ", "AQ"); + codeReplacements.put("BTD", "BD"); codeReplacements.put("CMA", "CM1"); codeReplacements.put("CHR", "CH"); codeReplacements.put("DVD", "DD3_DVD"); @@ -165,14 +175,16 @@ public class GathererSets implements Iterable { codeReplacements.put("UGIN", "FRF_UGIN"); codeReplacements.put("UGL", "UG"); codeReplacements.put("ULG", "GU"); + codeReplacements.put("UNF", "UNFS"); codeReplacements.put("USG", "UZ"); codeReplacements.put("VIS", "VI"); codeReplacements.put("WTH", "WL"); + codeReplacements.put("YMID", "Y22"); + codeReplacements.put("YNEO", "Y22NEO"); } public GathererSets() { - - outDir = new File(getImagesDir() + Constants.RESOURCE_PATH_SYMBOLS); + outDir = new File(getImagesDir() + Constants.RESOURCE_PATH_SYMBOLS_RARITY_DEFAULT_PATH); if (!outDir.exists()) { outDir.mkdirs(); @@ -287,9 +299,9 @@ public class GathererSets implements Iterable { canDownload = false; if (exp != null && exp.getReleaseDate().before(compareDate)) { canDownload = true; - jobs.add(generateDownloadJob(symbol, "C", "C")); - jobs.add(generateDownloadJob(symbol, "U", "U")); - jobs.add(generateDownloadJob(symbol, "R", "R")); + jobs.add(generateDownloadJob(symbol, "C", "common")); + jobs.add(generateDownloadJob(symbol, "U", "uncommon")); + jobs.add(generateDownloadJob(symbol, "R", "rare")); } CheckSearchResult(symbol, exp, canDownload, true, true, true, false); } @@ -299,10 +311,10 @@ public class GathererSets implements Iterable { canDownload = false; if (exp != null && exp.getReleaseDate().before(compareDate)) { canDownload = true; - jobs.add(generateDownloadJob(symbol, "C", "C")); - jobs.add(generateDownloadJob(symbol, "U", "U")); - jobs.add(generateDownloadJob(symbol, "R", "R")); - jobs.add(generateDownloadJob(symbol, "M", "M")); + jobs.add(generateDownloadJob(symbol, "C", "common")); + jobs.add(generateDownloadJob(symbol, "U", "uncommon")); + jobs.add(generateDownloadJob(symbol, "R", "rare")); + jobs.add(generateDownloadJob(symbol, "M", "mythic")); } CheckSearchResult(symbol, exp, canDownload, true, true, true, true); } @@ -312,7 +324,7 @@ public class GathererSets implements Iterable { canDownload = false; if (exp != null && exp.getReleaseDate().before(compareDate)) { canDownload = true; - jobs.add(generateDownloadJob(symbol, "M", "M")); + jobs.add(generateDownloadJob(symbol, "M", "mythic")); } CheckSearchResult(symbol, exp, canDownload, false, false, false, true); } @@ -322,7 +334,7 @@ public class GathererSets implements Iterable { canDownload = false; if (exp != null && exp.getReleaseDate().before(compareDate)) { canDownload = true; - jobs.add(generateDownloadJob(symbol, "M", "S")); + jobs.add(generateDownloadJob(symbol, "M", "special")); } CheckSearchResult(symbol, exp, canDownload, false, false, false, true); } @@ -334,11 +346,22 @@ public class GathererSets implements Iterable { } private DownloadJob generateDownloadJob(String set, String rarity, String urlRarity) { - File dst = new File(outDir, set + '-' + rarity + ".jpg"); + File dst = new File(outDir, set + '-' + rarity + ".png"); if (codeReplacements.containsKey(set)) { set = codeReplacements.get(set); } - String url = "https://gatherer.wizards.com/Handlers/Image.ashx?type=symbol&set=" + set + "&size=small&rarity=" + urlRarity; + // example: + // - small: https://gatherer-static.wizards.com/set_symbols/FIN/small-common-FIN.png + // - big: https://gatherer-static.wizards.com/set_symbols/FIN/large-rare-FIN.png + + String useSet = set.toUpperCase(Locale.ENGLISH); + String useSize = "large"; // allow: small, large + String url = String.format("https://gatherer-static.wizards.com/set_symbols/%s/%s-%s-%s.png", + useSet, + useSize, + urlRarity, + useSet + ); return new DownloadJob(set + '-' + rarity, url, toFile(dst), false); } } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSymbols.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSymbols.java index b3704e3820d..1bd36368647 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSymbols.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSymbols.java @@ -75,7 +75,7 @@ public class GathererSymbols implements Iterable { continue; } String symbol = sym.replaceAll("/", ""); - File dst = new File(dir, symbol + ".gif"); + File dst = new File(dir, symbol + ".png"); // workaround for miss icons on Gatherer (no cards with it, so no icons) // TODO: comment and try download without workaround, keep fix for symbols with "Resource not found" error diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java index 7bbdd07853b..5a23faff7d7 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java @@ -588,7 +588,10 @@ public class ScryfallImageSupportCards { add("FIN"); // Final Fantasy add("FIC"); // Final Fantasy Commander add("FCA"); // Final Fantasy: Through the Ages + add("EOE"); // Edge of Eternities + add("EOC"); // Edge of Eternities Commander add("SPE"); // Marvel's Spider-Man Eternal + add("TLA"); // Avatar: The Last Airbender // Custom sets using Scryfall images - must provide a direct link for each card in directDownloadLinks add("CALC"); // Custom Alchemized versions of existing cards diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java index 19aecedcf0e..0248b50c5e0 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java @@ -352,6 +352,9 @@ public class ScryfallImageSupportTokens { put("ELD/Rat", "https://api.scryfall.com/cards/teld/6/en?format=image"); put("ELD/Wolf", "https://api.scryfall.com/cards/teld/14/en?format=image"); + // UND + put("UND/Goblin", "https://api.scryfall.com/cards/tund/2?format=image"); + // THB put("THB/Elemental", "https://api.scryfall.com/cards/tthb/8/en?format=image"); put("THB/Goat", "https://api.scryfall.com/cards/tthb/1/en?format=image"); @@ -829,12 +832,18 @@ public class ScryfallImageSupportTokens { put("SLD/Food/3", "https://api.scryfall.com/cards/sld/2011?format=image"); put("SLD/Food/4", "https://api.scryfall.com/cards/sld/2012?format=image"); put("SLD/Food/5", "https://api.scryfall.com/cards/sld/2013?format=image"); + put("SLD/Food/6", "https://api.scryfall.com/cards/sld/2064?format=image"); put("SLD/Goblin", "https://api.scryfall.com/cards/sld/219?format=image"); put("SLD/Hydra", "https://api.scryfall.com/cards/sld/1334?format=image"); put("SLD/Icingdeath, Frost Tongue", "https://api.scryfall.com/cards/sld/1018?format=image"); put("SLD/Marit Lage", "https://api.scryfall.com/cards/sld/1681?format=image"); put("SLD/Mechtitan", "https://api.scryfall.com/cards/sld/1969?format=image"); + put("SLD/Myr", "https://api.scryfall.com/cards/sld/2101?format=image"); put("SLD/Saproling", "https://api.scryfall.com/cards/sld/1139?format=image"); + put("SLD/Shapeshifter/1", "https://api.scryfall.com/cards/sld/1906?format=image"); + put("SLD/Shapeshifter/2", "https://api.scryfall.com/cards/sld/1907?format=image"); + put("SLD/Shapeshifter/3", "https://api.scryfall.com/cards/sld/1908?format=image"); + put("SLD/Shapeshifter/4", "https://api.scryfall.com/cards/sld/1909?format=image"); put("SLD/Shrine", "https://api.scryfall.com/cards/sld/1835?format=image"); put("SLD/Spirit/1", "https://api.scryfall.com/cards/sld/1341?format=image"); put("SLD/Spirit/2", "https://api.scryfall.com/cards/sld/1852?format=image"); @@ -843,6 +852,8 @@ public class ScryfallImageSupportTokens { put("SLD/Treasure/2", "https://api.scryfall.com/cards/sld/1736/en?format=image"); put("SLD/Treasure/3", "https://api.scryfall.com/cards/sld/1507/en?format=image"); put("SLD/Treasure/4", "https://api.scryfall.com/cards/sld/153/en?format=image"); + put("SLD/Treasure/5", "https://api.scryfall.com/cards/sld/2065/en?format=image"); + put("SLD/Treasure/6", "https://api.scryfall.com/cards/sld/2094/en?format=image"); put("SLD/Walker/1", "https://api.scryfall.com/cards/sld/148/en?format=image"); put("SLD/Walker/2", "https://api.scryfall.com/cards/sld/149/en?format=image"); put("SLD/Walker/3", "https://api.scryfall.com/cards/sld/150/en?format=image"); @@ -1843,6 +1854,12 @@ public class ScryfallImageSupportTokens { put("40K/Tyranid Gargoyle", "https://api.scryfall.com/cards/t40k/9/en?format=image"); put("40K/Tyranid Warrior", "https://api.scryfall.com/cards/t40k/19/en?format=image"); + // UNF + put("UNF/Clown Robot/1", "https://api.scryfall.com/cards/tunf/2?format=image"); + put("UNF/Clown Robot/2", "https://api.scryfall.com/cards/tunf/3?format=image"); + put("UNF/Storm Crow", "https://api.scryfall.com/cards/tunf/5?format=image"); + put("UNF/Squirrel", "https://api.scryfall.com/cards/tunf/8?format=image"); + // BRO put("BRO/Bear", "https://api.scryfall.com/cards/tbro/2/en?format=image"); put("BRO/Construct/1", "https://api.scryfall.com/cards/tbro/5/en?format=image"); @@ -2026,6 +2043,7 @@ public class ScryfallImageSupportTokens { // DIS put("DIS/Emblem Momir", "https://api.scryfall.com/cards/pmoa/61/en?format=image"); + put("DIS/Elemental", "https://api.scryfall.com/cards/togw/9?format=image"); // MUL put("MUL/Elemental", "https://api.scryfall.com/cards/tmul/2/en?format=image"); @@ -2162,26 +2180,20 @@ public class ScryfallImageSupportTokens { put("WOE/Young Hero", "https://api.scryfall.com/cards/twoe/16/en?format=image"); // WOC - put("WOC/Cat/1", "https://api.scryfall.com/cards/twoc/6/en?format=image"); - put("WOC/Cat/2", "https://api.scryfall.com/cards/twoc/5/en?format=image"); - put("WOC/Elephant", "https://api.scryfall.com/cards/twoc/13/en?format=image"); put("WOC/Faerie", "https://api.scryfall.com/cards/twoc/10/en?format=image"); put("WOC/Faerie Rogue/1", "https://api.scryfall.com/cards/twoc/11/en?format=image"); put("WOC/Faerie Rogue/2", "https://api.scryfall.com/cards/twoc/16/en?format=image"); - put("WOC/Human Monk", "https://api.scryfall.com/cards/twoc/14/en?format=image"); put("WOC/Human Soldier", "https://api.scryfall.com/cards/twoc/7/en?format=image"); put("WOC/Monster", "https://api.scryfall.com/cards/twoc/1/en?format=image"); - put("WOC/Ox", "https://api.scryfall.com/cards/twoc/8/en?format=image"); put("WOC/Pegasus", "https://api.scryfall.com/cards/twoc/9/en?format=image"); put("WOC/Pirate", "https://api.scryfall.com/cards/twoc/12/en?format=image"); put("WOC/Royal", "https://api.scryfall.com/cards/twoc/2/en?format=image"); put("WOC/Saproling", "https://api.scryfall.com/cards/twoc/15/en?format=image"); - put("WOC/Sorcerer", "https://api.scryfall.com/cards/twoc/3/en?format=image"); - put("WOC/Spirit", "https://api.scryfall.com/cards/twoc/17/en?format=image"); - put("WOC/Virtuous", "https://api.scryfall.com/cards/twoc/3/en?format=image"); + put("WOC/Virtuous", "https://api.scryfall.com/cards/twoc/2/en?format=image"); // WHO put("WHO/Alien", "https://api.scryfall.com/cards/twho/2?format=image"); + put("WHO/Alien Angel", "https://api.scryfall.com/cards/twho/11?format=image"); put("WHO/Alien Insect", "https://api.scryfall.com/cards/twho/19/en?format=image"); put("WHO/Alien Rhino", "https://api.scryfall.com/cards/twho/3/en?format=image"); put("WHO/Alien Salamander", "https://api.scryfall.com/cards/twho/16?format=image"); @@ -2536,12 +2548,14 @@ public class ScryfallImageSupportTokens { put("DSK/Everywhere", "https://api.scryfall.com/cards/tdsk/16?format=image"); put("DSK/Glimmer", "https://api.scryfall.com/cards/tdsk/4?format=image"); put("DSK/Gremlin", "https://api.scryfall.com/cards/tdsk/11?format=image"); + put("DSK/Horror", "https://api.scryfall.com/cards/tdsk/10?format=image"); put("DSK/Insect/1", "https://api.scryfall.com/cards/tdsk/13?format=image"); put("DSK/Insect/2", "https://api.scryfall.com/cards/tdsk/5?format=image"); put("DSK/Primo, the Indivisible", "https://api.scryfall.com/cards/tdsk/14?format=image"); put("DSK/Shard", "https://api.scryfall.com/cards/tdsk/2?format=image"); put("DSK/Spider", "https://api.scryfall.com/cards/tdsk/12?format=image"); - put("DSK/Spirit", "https://api.scryfall.com/cards/tdsk/8?format=image"); + put("DSK/Spirit/1", "https://api.scryfall.com/cards/tdsk/6?format=image"); + put("DSK/Spirit/2", "https://api.scryfall.com/cards/tdsk/8?format=image"); put("DSK/Treasure", "https://api.scryfall.com/cards/tdsk/15?format=image"); // DSC @@ -2698,7 +2712,8 @@ public class ScryfallImageSupportTokens { put("TDC/Gold", "https://api.scryfall.com/cards/ttdc/29/en?format=image"); put("TDC/Human", "https://api.scryfall.com/cards/ttdc/5/en?format=image"); put("TDC/Inkling", "https://api.scryfall.com/cards/ttdc/28?format=image"); - put("TDC/Insect", "https://api.scryfall.com/cards/ttdc/22/en?format=image"); + put("TDC/Insect/1", "https://api.scryfall.com/cards/ttdc/22/en?format=image"); + put("TDC/Insect/2", "https://api.scryfall.com/cards/ttdc/23/en?format=image"); put("TDC/Karox Bladewing", "https://api.scryfall.com/cards/ttdc/19?format=image"); put("TDC/Myr", "https://api.scryfall.com/cards/ttdc/30/en?format=image"); put("TDC/Plant", "https://api.scryfall.com/cards/ttdc/24/en?format=image"); @@ -2710,6 +2725,7 @@ public class ScryfallImageSupportTokens { put("TDC/Spider", "https://api.scryfall.com/cards/ttdc/25?format=image"); put("TDC/Spirit", "https://api.scryfall.com/cards/ttdc/6/en?format=image"); put("TDC/Thopter", "https://api.scryfall.com/cards/ttdc/33/en?format=image"); + put("TDC/Wall", "https://api.scryfall.com/cards/ttdc/7/en?format=image"); // ACR put("ACR/Assassin", "https://api.scryfall.com/cards/tacr/4?format=image"); @@ -2723,7 +2739,51 @@ public class ScryfallImageSupportTokens { put("DD2/Elemental Shaman", "https://api.scryfall.com/cards/tdd2/1?format=image"); // FIN + put("FIN/Hero/1", "https://api.scryfall.com/cards/tfin/2/en?format=image"); + put("FIN/Hero/2", "https://api.scryfall.com/cards/tfin/3/en?format=image"); + put("FIN/Hero/3", "https://api.scryfall.com/cards/tfin/4/en?format=image"); + put("FIN/Hero/4", "https://api.scryfall.com/cards/tfin/5/en?format=image"); + put("FIN/Hero/5", "https://api.scryfall.com/cards/tfin/6/en?format=image"); + put("FIN/Hero/6", "https://api.scryfall.com/cards/tfin/7/en?format=image"); + put("FIN/Hero/7", "https://api.scryfall.com/cards/tfin/8/en?format=image"); + put("FIN/Hero/8", "https://api.scryfall.com/cards/tfin/9/en?format=image"); + put("FIN/Hero/9", "https://api.scryfall.com/cards/tfin/26/en?format=image"); + put("FIN/Hero/10", "https://api.scryfall.com/cards/tfin/27/en?format=image"); + put("FIN/Hero/11", "https://api.scryfall.com/cards/tfin/28/en?format=image"); + put("FIN/Hero/12", "https://api.scryfall.com/cards/tfin/29/en?format=image"); + put("FIN/Hero/13", "https://api.scryfall.com/cards/tfin/30/en?format=image"); + put("FIN/Hero/14", "https://api.scryfall.com/cards/tfin/31/en?format=image"); + put("FIN/Hero/15", "https://api.scryfall.com/cards/tfin/32/en?format=image"); + put("FIN/Hero/16", "https://api.scryfall.com/cards/tfin/33/en?format=image"); + put("FIN/Knight", "https://api.scryfall.com/cards/tfin/10/en?format=image"); + put("FIN/Moogle/1", "https://api.scryfall.com/cards/tfin/11/en?format=image"); + put("FIN/Moogle/2", "https://api.scryfall.com/cards/tfin/34/en?format=image"); + put("FIN/Robot", "https://api.scryfall.com/cards/tfin/12/en?format=image"); + put("FIN/Horror", "https://api.scryfall.com/cards/tfin/13/en?format=image"); + put("FIN/Wizard/1", "https://api.scryfall.com/cards/tfin/14/en?format=image"); + put("FIN/Wizard/2", "https://api.scryfall.com/cards/tfin/15/en?format=image"); + put("FIN/Wizard/3", "https://api.scryfall.com/cards/tfin/35/en?format=image"); + put("FIN/Bird/1", "https://api.scryfall.com/cards/tfin/16/en?format=image"); + put("FIN/Bird/2", "https://api.scryfall.com/cards/tfin/17/en?format=image"); + put("FIN/Frog", "https://api.scryfall.com/cards/tfin/18/en?format=image"); + put("FIN/Angelo", "https://api.scryfall.com/cards/tfin/19/en?format=image"); + put("FIN/Darkstar", "https://api.scryfall.com/cards/tfin/20/en?format=image"); + put("FIN/Elemental", "https://api.scryfall.com/cards/tfin/21/en?format=image"); put("FIN/Food", "https://api.scryfall.com/cards/tfin/22?format=image"); + put("FIN/Treasure/1", "https://api.scryfall.com/cards/tfin/23/en?format=image"); + put("FIN/Treasure/2", "https://api.scryfall.com/cards/tfin/36/en?format=image"); + put("FIN/Emblem Sephiroth", "https://api.scryfall.com/cards/tfin/24/en?format=image"); + + // FIC + put("FIC/Human Soldier", "https://api.scryfall.com/cards/tfic/1/en?format=image"); + put("FIC/Soldier", "https://api.scryfall.com/cards/tfic/2/en?format=image"); + put("FIC/Spirit", "https://api.scryfall.com/cards/tfic/3/en?format=image"); + put("FIC/Bird", "https://api.scryfall.com/cards/tfic/4/en?format=image"); + put("FIC/Squid", "https://api.scryfall.com/cards/tfic/5/en?format=image"); + put("FIC/Zombie", "https://api.scryfall.com/cards/tfic/6/en?format=image"); + put("FIC/Rebel", "https://api.scryfall.com/cards/tfic/7/en?format=image"); + put("FIC/The Blackjack", "https://api.scryfall.com/cards/tfic/8/en?format=image"); + put("FIC/Clue", "https://api.scryfall.com/cards/tfic/9/en?format=image"); // JVC put("JVC/Elemental Shaman", "https://api.scryfall.com/cards/tjvc/4?format=image"); @@ -2756,6 +2816,7 @@ public class ScryfallImageSupportTokens { // UGL put("UGL/Goblin", "https://api.scryfall.com/cards/tugl/4?format=image"); put("UGL/Pegasus", "https://api.scryfall.com/cards/tugl/1?format=image"); + put("UGL/Rabid Sheep", "https://api.scryfall.com/cards/tugl/5?format=image"); put("UGL/Soldier", "https://api.scryfall.com/cards/tugl/2?format=image"); put("UGL/Squirrel", "https://api.scryfall.com/cards/tugl/6?format=image"); put("UGL/Zombie", "https://api.scryfall.com/cards/tugl/3?format=image"); diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java index a8fb8ddc6c1..704395e0378 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java @@ -157,7 +157,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements @Override public boolean isNeedCancel() { - return this.needCancel || (this.errorCount > MAX_ERRORS_COUNT_BEFORE_CANCEL) || Thread.interrupted(); + return this.needCancel || (this.errorCount > MAX_ERRORS_COUNT_BEFORE_CANCEL) || Thread.currentThread().isInterrupted(); } private void setNeedCancel(boolean needCancel) { diff --git a/Mage.Common/pom.xml b/Mage.Common/pom.xml index 36fe0dc82ca..d2935eb53cc 100644 --- a/Mage.Common/pom.xml +++ b/Mage.Common/pom.xml @@ -66,7 +66,6 @@ org.apache.commons commons-lang3 - test diff --git a/Mage.Common/src/main/java/mage/cards/action/impl/EmptyCallback.java b/Mage.Common/src/main/java/mage/cards/action/impl/EmptyCallback.java deleted file mode 100644 index 3da223590e6..00000000000 --- a/Mage.Common/src/main/java/mage/cards/action/impl/EmptyCallback.java +++ /dev/null @@ -1,63 +0,0 @@ -package mage.cards.action.impl; - -import mage.cards.action.ActionCallback; -import mage.cards.action.TransferData; - -import java.awt.*; -import java.awt.event.MouseEvent; -import java.awt.event.MouseWheelEvent; - -/** - * Callback that does nothing on any action - * - * @author nantuko84 - */ -public class EmptyCallback implements ActionCallback { - - @Override - public void mouseMoved(MouseEvent e, TransferData data) { - } - - @Override - public void mouseDragged(MouseEvent e, TransferData data) { - - } - - @Override - public void mouseEntered(MouseEvent e, TransferData data) { - } - - @Override - public void mouseExited(MouseEvent e, TransferData data) { - } - - @Override - public void mouseWheelMoved(int mouseWheelRotation, TransferData data) { - } - - @Override - public void hideOpenComponents() { - } - - @Override - public void mouseClicked(MouseEvent e, TransferData data, boolean doubleClick) { - } - - @Override - public void mousePressed(MouseEvent e, TransferData data) { - } - - @Override - public void mouseReleased(MouseEvent e, TransferData data) { - } - - @Override - public void popupMenuCard(MouseEvent e, TransferData data) { - - } - - @Override - public void popupMenuPanel(MouseEvent e, Component sourceComponent) { - - } -} diff --git a/Mage.Common/src/main/java/mage/filters/MageBufferedImageOp.java b/Mage.Common/src/main/java/mage/filters/MageBufferedImageOp.java deleted file mode 100644 index f6adc23d756..00000000000 --- a/Mage.Common/src/main/java/mage/filters/MageBufferedImageOp.java +++ /dev/null @@ -1,72 +0,0 @@ -package mage.filters; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.image.BufferedImage; -import java.awt.image.BufferedImageOp; -import java.awt.image.ColorModel; - -/** - * Mage abstract class that implements single-input/single-output - * operations performed on {@link java.awt.image.BufferedImage}. - * - * @author nantuko - */ -public abstract class MageBufferedImageOp implements BufferedImageOp { - - /** - * Creates compatible image for @param src image. - */ - @Override - public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dest) { - if (dest == null) { - dest = src.getColorModel(); - } - return new BufferedImage(dest, dest.createCompatibleWritableRaster(src.getWidth(), src.getHeight()), dest.isAlphaPremultiplied(), null); - } - - @Override - public RenderingHints getRenderingHints() { - return null; - } - - @Override - public Rectangle2D getBounds2D(BufferedImage src) { - return new Rectangle(0, 0, src.getWidth(), src.getHeight()); - } - - @Override - public Point2D getPoint2D(Point2D srcPt, Point2D destPt) { - if (destPt == null) { - destPt = new Point2D.Double(); - } - destPt.setLocation(srcPt.getX(), srcPt.getY()); - return destPt; - } - - /** - * Gets ARGB pixels from image. Solves the performance - * issue of BufferedImage.getRGB method. - */ - public int[] getRGB(BufferedImage image, int x, int y, int width, int height, int[] pixels) { - int type = image.getType(); - if (type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB) { - return (int[]) image.getRaster().getDataElements(x, y, width, height, pixels); - } - return image.getRGB(x, y, width, height, pixels, 0, width); - } - - /** - * Sets ARGB pixels in image. Solves the performance - * issue of BufferedImage.setRGB method. - */ - public void setRGB(BufferedImage image, int x, int y, int width, int height, int[] pixels) { - int type = image.getType(); - if (type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB) { - image.getRaster().setDataElements(x, y, width, height, pixels); - } else { - image.setRGB(x, y, width, height, pixels, 0, width); - } - } -} diff --git a/Mage.Common/src/main/java/mage/utils/ActionWithUUIDResult.java b/Mage.Common/src/main/java/mage/utils/ActionWithUUIDResult.java deleted file mode 100644 index 1133a0bde24..00000000000 --- a/Mage.Common/src/main/java/mage/utils/ActionWithUUIDResult.java +++ /dev/null @@ -1,11 +0,0 @@ -package mage.utils; - -import mage.view.TableView; - -/** - * Used to write less code for ActionWithResult anonymous classes with UUID return type. - * - * @author noxx - */ -public abstract class ActionWithUUIDResult extends ActionWithNullNegativeResult { -} diff --git a/Mage.Common/src/main/java/mage/utils/testers/AmountTestableResult.java b/Mage.Common/src/main/java/mage/utils/testers/AmountTestableResult.java new file mode 100644 index 00000000000..5b92ba19745 --- /dev/null +++ b/Mage.Common/src/main/java/mage/utils/testers/AmountTestableResult.java @@ -0,0 +1,59 @@ +package mage.utils.testers; + +import java.util.List; + +/** + * Part of testable game dialogs + * + * @author JayDi85 + */ +public class AmountTestableResult extends BaseTestableResult { + + Integer amount = null; + + boolean aiAssertEnabled = false; + int aiAssertMinAmount = 0; + int aiAssertMaxAmount = 0; + + public void onFinish(String resDebugSource, boolean status, List info, int amount) { + this.onFinish(resDebugSource, status, info); + this.amount = amount; + } + + @Override + public String getResAssert() { + if (!this.aiAssertEnabled) { + return null; + } + + // not finished + if (this.amount == null) { + return null; + } + + if (!this.getResStatus()) { + return String.format("Wrong status: need %s, but get %s", + true, // res must be true all the time + this.getResStatus() + ); + } + + // wrong amount + if (this.amount < this.aiAssertMinAmount || this.amount > this.aiAssertMaxAmount) { + return String.format("Wrong amount: need [%d, %d], but get %d", + this.aiAssertMinAmount, + this.aiAssertMaxAmount, + this.amount + ); + } + + // all fine + return ""; + } + + @Override + public void onClear() { + super.onClear(); + this.amount = null; + } +} diff --git a/Mage.Common/src/main/java/mage/utils/testers/AnnounceXTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/AnnounceXTestableDialog.java index bd346448472..5d3b6d5fd41 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/AnnounceXTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/AnnounceXTestableDialog.java @@ -3,6 +3,7 @@ package mage.utils.testers; import mage.abilities.Ability; import mage.game.Game; import mage.players.Player; +import mage.util.DebugUtil; import java.util.ArrayList; import java.util.Arrays; @@ -25,22 +26,33 @@ class AnnounceXTestableDialog extends BaseTestableDialog { public AnnounceXTestableDialog(boolean isYou, boolean isMana, int min, int max) { super(String.format("player.announceX(%s)", isYou ? "you" : "AI"), - String.format("%s from %d to %d", isMana ? "mana" : "cost", min, max), ""); + String.format("%s from %d to %d", isMana ? "mana" : "cost", min, max), "", + new AmountTestableResult()); this.isYou = isYou; this.isMana = isMana; this.min = min; this.max = max; } + private AnnounceXTestableDialog aiMustChoose(int minAmount, int maxAmount) { + // require min/max cause AI logic uses random choices + AmountTestableResult res = ((AmountTestableResult) this.getResult()); + res.aiAssertEnabled = true; + res.aiAssertMinAmount = minAmount; + res.aiAssertMaxAmount = maxAmount; + return this; + } + @Override - public List showDialog(Player player, Ability source, Game game, Player opponent) { + public void showDialog(Player player, Ability source, Game game, Player opponent) { Player choosingPlayer = this.isYou ? player : opponent; String message = "message with html"; - int chooseRes; - chooseRes = choosingPlayer.announceX(this.min, this.max, message, game, source, this.isMana); - List result = new ArrayList<>(); - result.add(getGroup() + " - " + this.getName() + " selected " + chooseRes); - return result; + String chooseDebugSource = DebugUtil.getMethodNameWithSource(0, "class"); + int chooseRes = choosingPlayer.announceX(this.min, this.max, message, game, source, this.isMana); + List res = new ArrayList<>(); + res.add(getGroup() + " - " + this.getName() + " selected " + chooseRes); + + ((AmountTestableResult) this.getResult()).onFinish(chooseDebugSource, true, res, chooseRes); } static public void register(TestableDialogsRunner runner) { @@ -48,17 +60,17 @@ class AnnounceXTestableDialog extends BaseTestableDialog { List isManas = Arrays.asList(false, true); for (boolean isYou : isYous) { for (boolean isMana : isManas) { - runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 0, 0)); - runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 0, 1)); - runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 0, 3)); - runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 0, 50)); - runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 0, 500)); - runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 1, 1)); - runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 1, 3)); - runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 1, 50)); - runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 3, 3)); - runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 3, 10)); - runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 10, 10)); + runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 0, 0).aiMustChoose(0, 0)); + runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 0, 1).aiMustChoose(0, 1)); + runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 0, 3).aiMustChoose(0, 3)); + runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 0, 50).aiMustChoose(0, 50)); + runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 0, 500).aiMustChoose(0, 500)); + runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 1, 1).aiMustChoose(1, 1)); + runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 1, 3).aiMustChoose(1, 3)); + runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 1, 50).aiMustChoose(1, 50)); + runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 3, 3).aiMustChoose(3, 3)); + runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 3, 10).aiMustChoose(3, 10)); + runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 10, 10).aiMustChoose(10, 10)); } } } diff --git a/Mage.Common/src/main/java/mage/utils/testers/BaseTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/BaseTestableDialog.java index 0ee78b67e51..2ae8d4cae79 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/BaseTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/BaseTestableDialog.java @@ -1,11 +1,12 @@ package mage.utils.testers; -import mage.constants.SubType; -import mage.filter.common.FilterCreaturePermanent; +import mage.constants.ComparisonType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetPermanentOrPlayer; /** @@ -15,14 +16,27 @@ import mage.target.common.TargetPermanentOrPlayer; */ abstract class BaseTestableDialog implements TestableDialog { + private Integer regNumber; // dialog number in runner (use it to find results and debugging) private final String group; private final String name; private final String description; + private final TestableResult result; - public BaseTestableDialog(String group, String name, String description) { + public BaseTestableDialog(String group, String name, String description, TestableResult result) { this.group = group; this.name = name; this.description = description; + this.result = result; + } + + @Override + public void setRegNumber(Integer regNumber) { + this.regNumber = regNumber; + } + + @Override + public Integer getRegNumber() { + return this.regNumber; } @Override @@ -41,13 +55,23 @@ abstract class BaseTestableDialog implements TestableDialog { } @Override - final public void showResult(Player player, Game game, String result) { + public void prepare() { + this.result.onClear(); + } + + @Override + final public void showResult(Player player, Game game) { // show message with result - game.informPlayer(player, result); + game.informPlayer(player, String.join("
", getResult().getResDetails())); // reset game and gui (in most use cases it must return to player's priority) game.firePriorityEvent(player.getId()); } + @Override + public TestableResult getResult() { + return this.result; + } + static Target createAnyTarget(int min, int max) { return createAnyTarget(min, max, false); } @@ -56,19 +80,18 @@ abstract class BaseTestableDialog implements TestableDialog { return new TargetPermanentOrPlayer(min, max).withNotTarget(notTarget); } - static Target createCreatureTarget(int min, int max) { - return createCreatureTarget(min, max, false); - } + private static final FilterPermanent impossibleFilter = new FilterPermanent(); - private static Target createCreatureTarget(int min, int max, boolean notTarget) { - return new TargetCreaturePermanent(min, max).withNotTarget(notTarget); + static { + impossibleFilter.add(new ManaValuePredicate(ComparisonType.OR_LESS, -1)); } static Target createImpossibleTarget(int min, int max) { - return createImpossibleTarget(min, max, false); + return new TargetPermanent(min, max, impossibleFilter); } - private static Target createImpossibleTarget(int min, int max, boolean notTarget) { - return new TargetCreaturePermanent(min, max, new FilterCreaturePermanent(SubType.TROOPER, "rare type"), notTarget); + @Override + public String toString() { + return this.getGroup() + " - " + this.getName() + " - " + this.getDescription(); } } diff --git a/Mage.Common/src/main/java/mage/utils/testers/BaseTestableResult.java b/Mage.Common/src/main/java/mage/utils/testers/BaseTestableResult.java new file mode 100644 index 00000000000..6b3856e6f95 --- /dev/null +++ b/Mage.Common/src/main/java/mage/utils/testers/BaseTestableResult.java @@ -0,0 +1,57 @@ +package mage.utils.testers; + +import java.util.ArrayList; +import java.util.List; + +/** + * Part of testable game dialogs + * + * @author JayDi85 + */ +public class BaseTestableResult implements TestableResult { + + boolean isFinished = false; + String resDebugSource = ""; // source code line to find starting place to debug + boolean resStatus = false; + List resInfo = new ArrayList<>(); + + @Override + public String getResDebugSource() { + return this.resDebugSource; + } + + @Override + public boolean getResStatus() { + return this.resStatus; + } + + @Override + public List getResDetails() { + return this.resInfo; + } + + @Override + public String getResAssert() { + return null; // TODO: implement + } + + @Override + public void onFinish(String resDebugSource, boolean resStatus, List resDetails) { + this.isFinished = true; + this.resDebugSource = resDebugSource; + this.resStatus = resStatus; + this.resInfo = resDetails; + } + + @Override + public boolean isFinished() { + return this.isFinished; + } + + @Override + public void onClear() { + this.isFinished = false; + this.resStatus = false; + this.resInfo.clear(); + } +} diff --git a/Mage.Common/src/main/java/mage/utils/testers/ChoiceTestableResult.java b/Mage.Common/src/main/java/mage/utils/testers/ChoiceTestableResult.java new file mode 100644 index 00000000000..acf520e29e2 --- /dev/null +++ b/Mage.Common/src/main/java/mage/utils/testers/ChoiceTestableResult.java @@ -0,0 +1,29 @@ +package mage.utils.testers; + +import java.util.List; + +/** + * Part of testable game dialogs + * + * @author JayDi85 + */ +public class ChoiceTestableResult extends BaseTestableResult { + + String choice = null; + + public void onFinish(String resDebugSource, boolean status, List info, String choice) { + this.onFinish(resDebugSource, status, info); + this.choice = choice; + } + + @Override + public String getResAssert() { + return null; // TODO: implement + } + + @Override + public void onClear() { + super.onClear(); + this.choice = null; + } +} diff --git a/Mage.Common/src/main/java/mage/utils/testers/ChooseAmountTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/ChooseAmountTestableDialog.java index 6a7847ec4fc..37bb11eb381 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/ChooseAmountTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/ChooseAmountTestableDialog.java @@ -7,6 +7,7 @@ import mage.players.Player; import mage.target.TargetAmount; import mage.target.Targets; import mage.target.common.TargetAnyTargetAmount; +import mage.util.DebugUtil; import java.util.ArrayList; import java.util.Arrays; @@ -32,27 +33,39 @@ class ChooseAmountTestableDialog extends BaseTestableDialog { public ChooseAmountTestableDialog(boolean isYou, String name, int distributeAmount, int targetsMin, int targetsMax) { super(String.format("player.chooseTarget(%s, amount)", isYou ? "you" : "AI"), name, - String.format("%d between %d-%d targets", distributeAmount, targetsMin, targetsMax)); + String.format("%d between %d-%d targets", distributeAmount, targetsMin, targetsMax), + new TargetTestableResult()); this.isYou = isYou; this.distributeAmount = distributeAmount; this.targetsMin = targetsMin; this.targetsMax = targetsMax; } + private ChooseAmountTestableDialog aiMustChoose(boolean resStatus, int targetsCount) { + // TODO: AI use default distribution, improve someday + TargetTestableResult res = ((TargetTestableResult) this.getResult()); + res.aiAssertEnabled = true; + res.aiAssertResStatus = resStatus; + res.aiAssertTargetsCount = targetsCount; + return this; + } + @Override - public List showDialog(Player player, Ability source, Game game, Player opponent) { + public void showDialog(Player player, Ability source, Game game, Player opponent) { TargetAmount choosingTarget = new TargetAnyTargetAmount(this.distributeAmount, this.targetsMin, this.targetsMax); Player choosingPlayer = this.isYou ? player : opponent; // TODO: add "damage" word in ability text, so chooseTargetAmount an show diff dialog (due inner logic - distribute damage or 1/1) + String chooseDebugSource = DebugUtil.getMethodNameWithSource(0, "class"); boolean chooseRes = choosingPlayer.chooseTargetAmount(Outcome.Benefit, choosingTarget, source, game); - List result = new ArrayList<>(); + List res = new ArrayList<>(); if (chooseRes) { - Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "TRUE", new Targets(choosingTarget), source, game, result); + Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "TRUE", new Targets(choosingTarget), source, game, res); } else { - Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, result); + Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, res); } - return result; + + ((TargetTestableResult) this.getResult()).onFinish(chooseDebugSource, chooseRes, res, choosingTarget); } static public void register(TestableDialogsRunner runner) { @@ -61,53 +74,55 @@ class ChooseAmountTestableDialog extends BaseTestableDialog { List isYous = Arrays.asList(false, true); + // current AI will choose 1 target and assign all values to it (except with outcome.Damage) + // TODO: add use cases for damage effects? for (boolean isYou : isYous) { // up to - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 0, 0, 0)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 0, 0, 1)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 0, 0, 3)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 0, 0, 5)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 0, 0, 0).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 0, 0, 1).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 0, 0, 3).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 0, 0, 5).aiMustChoose(false, 0)); // - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to, invalid", 1, 0, 0)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 1, 0, 1)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 1, 0, 3)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 1, 0, 5)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to, invalid", 1, 0, 0).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 1, 0, 1).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 1, 0, 3).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 1, 0, 5).aiMustChoose(true, 1)); // - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to, invalid", 2, 0, 0)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 2, 0, 1)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 2, 0, 3)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 2, 0, 5)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to, invalid", 2, 0, 0).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 2, 0, 1).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 2, 0, 3).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 2, 0, 5).aiMustChoose(true, 1)); // - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to, invalid", 3, 0, 0)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 3, 0, 1)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 3, 0, 3)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 3, 0, 5)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to, invalid", 3, 0, 0).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 3, 0, 1).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 3, 0, 3).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 3, 0, 5).aiMustChoose(true, 1)); // - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to, invalid", 5, 0, 0)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 5, 0, 1)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 5, 0, 3)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 5, 0, 5)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to, invalid", 5, 0, 0).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 5, 0, 1).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 5, 0, 3).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 5, 0, 5).aiMustChoose(true, 1)); // need target - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 0, 1, 1)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 0, 1, 3)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 0, 1, 5)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 0, 1, 1).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 0, 1, 3).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 0, 1, 5).aiMustChoose(false, 0)); // - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 1, 1, 1)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 1, 1, 3)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 1, 1, 5)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 1, 1, 1).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 1, 1, 3).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 1, 1, 5).aiMustChoose(true, 1)); // - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 2, 1, 1)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 2, 1, 3)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 2, 1, 5)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 2, 1, 1).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 2, 1, 3).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 2, 1, 5).aiMustChoose(true, 1)); // - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 3, 1, 1)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 3, 1, 3)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 3, 1, 5)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 3, 1, 1).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 3, 1, 3).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 3, 1, 5).aiMustChoose(true, 1)); // - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 5, 1, 1)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 5, 1, 3)); - runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 5, 1, 5)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 5, 1, 1).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 5, 1, 3).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 5, 1, 5).aiMustChoose(true, 1)); } } } diff --git a/Mage.Common/src/main/java/mage/utils/testers/ChooseCardsTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/ChooseCardsTestableDialog.java index 8837d9b92ce..e0dbc8e45dd 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/ChooseCardsTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/ChooseCardsTestableDialog.java @@ -13,6 +13,7 @@ import mage.players.Player; import mage.target.TargetCard; import mage.target.Targets; import mage.target.common.TargetCardInHand; +import mage.util.DebugUtil; import java.util.ArrayList; import java.util.Arrays; @@ -36,16 +37,17 @@ class ChooseCardsTestableDialog extends BaseTestableDialog { public ChooseCardsTestableDialog(boolean isTargetChoice, boolean notTarget, boolean isYou, String name, TargetCard target) { super(String.format("%s(%s, %s, cards)", - isTargetChoice ? "player.chooseTarget" : "player.choose", - isYou ? "you" : "AI", - notTarget ? "not target" : "target"), name, target.toString()); + isTargetChoice ? "player.chooseTarget" : "player.choose", + isYou ? "you" : "AI", + notTarget ? "not target" : "target"), name, target.toString(), + new TargetTestableResult()); this.isTargetChoice = isTargetChoice; this.target = target.withNotTarget(notTarget); this.isYou = isYou; } @Override - public List showDialog(Player player, Ability source, Game game, Player opponent) { + public void showDialog(Player player, Ability source, Game game, Player opponent) { TargetCard choosingTarget = this.target.copy(); Player choosingPlayer = this.isYou ? player : opponent; @@ -56,19 +58,23 @@ class ChooseCardsTestableDialog extends BaseTestableDialog { Cards choosingCards = new CardsImpl(all.stream().limit(100).collect(Collectors.toList())); boolean chooseRes; + String chooseDebugSource; if (this.isTargetChoice) { + chooseDebugSource = DebugUtil.getMethodNameWithSource(0, "class"); chooseRes = choosingPlayer.chooseTarget(Outcome.Benefit, choosingCards, choosingTarget, source, game); } else { + chooseDebugSource = DebugUtil.getMethodNameWithSource(0, "class"); chooseRes = choosingPlayer.choose(Outcome.Benefit, choosingCards, choosingTarget, source, game); } - List result = new ArrayList<>(); + List res = new ArrayList<>(); if (chooseRes) { - Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "TRUE", new Targets(choosingTarget), source, game, result); + Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "TRUE", new Targets(choosingTarget), source, game, res); } else { - Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, result); + Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, res); } - return result; + + ((TargetTestableResult) this.getResult()).onFinish(chooseDebugSource, chooseRes, res, choosingTarget); } static public void register(TestableDialogsRunner runner) { diff --git a/Mage.Common/src/main/java/mage/utils/testers/ChooseChoiceTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/ChooseChoiceTestableDialog.java index 7e90c6cb124..e87451a54ae 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/ChooseChoiceTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/ChooseChoiceTestableDialog.java @@ -5,6 +5,7 @@ import mage.choices.*; import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; +import mage.util.DebugUtil; import java.util.ArrayList; import java.util.Arrays; @@ -24,28 +25,36 @@ class ChooseChoiceTestableDialog extends BaseTestableDialog { Choice choice; public ChooseChoiceTestableDialog(boolean isYou, String name, Choice choice) { - super(String.format("player.choose(%s, choice)", isYou ? "you" : "AI"), name, choice.getClass().getSimpleName()); + super(String.format("player.choose(%s, choice)", isYou ? "you" : "AI"), + name, + choice.getClass().getSimpleName(), + new ChoiceTestableResult() + ); this.isYou = isYou; this.choice = choice; } @Override - public List showDialog(Player player, Ability source, Game game, Player opponent) { + public void showDialog(Player player, Ability source, Game game, Player opponent) { Player choosingPlayer = this.isYou ? player : opponent; Choice dialog = this.choice.copy(); + String chooseDebugSource = DebugUtil.getMethodNameWithSource(0, "class"); boolean chooseRes = choosingPlayer.choose(Outcome.Benefit, dialog, game); - List result = new ArrayList<>(); - result.add(getGroup() + " - " + this.getName() + " - " + (chooseRes ? "TRUE" : "FALSE")); - result.add(""); + List res = new ArrayList<>(); + res.add(getGroup() + " - " + this.getName() + " - " + (chooseRes ? "TRUE" : "FALSE")); + res.add(""); + String choice; if (dialog.isKeyChoice()) { String key = dialog.getChoiceKey(); - result.add(String.format("* selected key: %s (%s)", key, dialog.getKeyChoices().getOrDefault(key, null))); + choice = dialog.getKeyChoices().getOrDefault(key, null); + res.add(String.format("* selected key: %s (%s)", key, choice)); } else { - result.add(String.format("* selected value: %s", dialog.getChoice())); + choice = dialog.getChoice(); + res.add(String.format("* selected value: %s", choice)); } - return result; + ((ChoiceTestableResult) this.getResult()).onFinish(chooseDebugSource, chooseRes, res, choice); } static public void register(TestableDialogsRunner runner) { diff --git a/Mage.Common/src/main/java/mage/utils/testers/ChoosePileTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/ChoosePileTestableDialog.java index 68bc9bbb265..f25b2fae670 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/ChoosePileTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/ChoosePileTestableDialog.java @@ -6,6 +6,7 @@ import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; import mage.util.CardUtil; +import mage.util.DebugUtil; import java.util.ArrayList; import java.util.Arrays; @@ -28,14 +29,18 @@ class ChoosePileTestableDialog extends BaseTestableDialog { int pileSize2; public ChoosePileTestableDialog(boolean isYou, int pileSize1, int pileSize2) { - super(String.format("player.choosePile(%s)", isYou ? "you" : "AI"), "pile sizes: " + pileSize1 + " and " + pileSize2, ""); + super(String.format("player.choosePile(%s)", isYou ? "you" : "AI"), + "pile sizes: " + pileSize1 + " and " + pileSize2, + "", + new BaseTestableResult() + ); this.isYou = isYou; this.pileSize1 = pileSize1; this.pileSize2 = pileSize2; } @Override - public List showDialog(Player player, Ability source, Game game, Player opponent) { + public void showDialog(Player player, Ability source, Game game, Player opponent) { // TODO: it's ok to show broken title - must add html support in windows's title someday String mainMessage = "main message with html" + CardUtil.getSourceLogName(game, source); @@ -47,11 +52,13 @@ class ChoosePileTestableDialog extends BaseTestableDialog { List pile2 = all.stream().limit(this.pileSize2).collect(Collectors.toList()); Player choosingPlayer = this.isYou ? player : opponent; + String chooseDebugSource = DebugUtil.getMethodNameWithSource(0, "class"); boolean chooseRes = choosingPlayer.choosePile(Outcome.Benefit, mainMessage, pile1, pile2, game); - List result = new ArrayList<>(); - result.add(getGroup() + " - " + this.getName() + " - " + (chooseRes ? "TRUE" : "FALSE")); - result.add(" * selected pile: " + (chooseRes ? "pile 1" : "pile 2")); - return result; + List res = new ArrayList<>(); + res.add(getGroup() + " - " + this.getName() + " - " + (chooseRes ? "TRUE" : "FALSE")); + res.add(" * selected pile: " + (chooseRes ? "pile 1" : "pile 2")); + + this.getResult().onFinish(chooseDebugSource, chooseRes, res); } static public void register(TestableDialogsRunner runner) { diff --git a/Mage.Common/src/main/java/mage/utils/testers/ChooseTargetTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/ChooseTargetTestableDialog.java index 65284618774..017aa055b27 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/ChooseTargetTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/ChooseTargetTestableDialog.java @@ -6,6 +6,7 @@ import mage.game.Game; import mage.players.Player; import mage.target.Target; import mage.target.Targets; +import mage.util.DebugUtil; import java.util.ArrayList; import java.util.Arrays; @@ -31,10 +32,14 @@ class ChooseTargetTestableDialog extends BaseTestableDialog { public ChooseTargetTestableDialog(boolean isPlayerChoice, boolean isTargetChoice, boolean notTarget, boolean isYou, String name, Target target) { super(String.format("%s%s(%s, %s)", - isPlayerChoice ? "player.choose" : "target.choose", - isTargetChoice ? "Target" : "", // chooseTarget or choose - isYou ? "you" : "AI", - notTarget ? "not target" : "target"), name, target.toString()); + isPlayerChoice ? "player.choose" : "target.choose", + isTargetChoice ? "Target" : "", // chooseTarget or choose + isYou ? "you" : "AI", + notTarget ? "not target" : "target"), + name, + target.toString(), + new TargetTestableResult() + ); this.isPlayerChoice = isPlayerChoice; this.isTargetChoice = isTargetChoice; this.target = target.withNotTarget(notTarget); @@ -42,34 +47,48 @@ class ChooseTargetTestableDialog extends BaseTestableDialog { } @Override - public List showDialog(Player player, Ability source, Game game, Player opponent) { + public void showDialog(Player player, Ability source, Game game, Player opponent) { Target choosingTarget = this.target.copy(); Player choosingPlayer = this.isYou ? player : opponent; boolean chooseRes; + String chooseDebugSource; if (this.isPlayerChoice) { // player.chooseXXX if (this.isTargetChoice) { + chooseDebugSource = DebugUtil.getMethodNameWithSource(0, "class"); chooseRes = choosingPlayer.chooseTarget(Outcome.Benefit, choosingTarget, source, game); } else { + chooseDebugSource = DebugUtil.getMethodNameWithSource(0, "class"); chooseRes = choosingPlayer.choose(Outcome.Benefit, choosingTarget, source, game); } } else { // target.chooseXXX if (this.isTargetChoice) { + chooseDebugSource = DebugUtil.getMethodNameWithSource(0, "class"); chooseRes = choosingTarget.chooseTarget(Outcome.Benefit, choosingPlayer.getId(), source, game); } else { + chooseDebugSource = DebugUtil.getMethodNameWithSource(0, "class"); chooseRes = choosingTarget.choose(Outcome.Benefit, choosingPlayer.getId(), source, game); } } - List result = new ArrayList<>(); + List res = new ArrayList<>(); if (chooseRes) { - Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "TRUE", new Targets(choosingTarget), source, game, result); + Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "TRUE", new Targets(choosingTarget), source, game, res); } else { - Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, result); + Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, res); } - return result; + + ((TargetTestableResult) this.getResult()).onFinish(chooseDebugSource, chooseRes, res, choosingTarget); + } + + private ChooseTargetTestableDialog aiMustChoose(boolean resStatus, int targetsCount) { + TargetTestableResult res = ((TargetTestableResult) this.getResult()); + res.aiAssertEnabled = true; + res.aiAssertResStatus = resStatus; + res.aiAssertTargetsCount = targetsCount; + return this; } static public void register(TestableDialogsRunner runner) { @@ -84,37 +103,29 @@ class ChooseTargetTestableDialog extends BaseTestableDialog { for (boolean isYou : isYous) { for (boolean isTargetChoice : isTargetChoices) { for (boolean isPlayerChoice : isPlayerChoices) { - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 0 e.g. X=0", createAnyTarget(0, 0))); // simulate X=0 - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 1", createAnyTarget(1, 1))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 3", createAnyTarget(3, 3))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 5", createAnyTarget(5, 5))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any max", createAnyTarget(0, Integer.MAX_VALUE))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 0-1", createAnyTarget(0, 1))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 0-3", createAnyTarget(0, 3))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 0-5", createAnyTarget(0, 5))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 1-3", createAnyTarget(1, 3))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 2-3", createAnyTarget(2, 3))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 1-5", createAnyTarget(1, 5))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 2-5", createAnyTarget(2, 5))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 3-5", createAnyTarget(3, 5))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 4-5", createAnyTarget(4, 5))); // impossible on 3 targets + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 0 e.g. X=0", createAnyTarget(0, 0)).aiMustChoose(false, 0)); // simulate X=0 + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 1", createAnyTarget(1, 1)).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 3", createAnyTarget(3, 3)).aiMustChoose(true, 3)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 5", createAnyTarget(5, 5)).aiMustChoose(true, 5)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any max", createAnyTarget(0, Integer.MAX_VALUE)).aiMustChoose(true, 6 + 1)); // 6 own cards + 1 own player + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 0-1", createAnyTarget(0, 1)).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 0-3", createAnyTarget(0, 3)).aiMustChoose(true, 3)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 0-5", createAnyTarget(0, 5)).aiMustChoose(true, 5)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 1-3", createAnyTarget(1, 3)).aiMustChoose(true, 3)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 2-3", createAnyTarget(2, 3)).aiMustChoose(true, 3)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 1-5", createAnyTarget(1, 5)).aiMustChoose(true, 5)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 2-5", createAnyTarget(2, 5)).aiMustChoose(true, 5)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 3-5", createAnyTarget(3, 5)).aiMustChoose(true, 5)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 4-5", createAnyTarget(4, 5)).aiMustChoose(true, 5)); // - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 0, e.g. X=0", createImpossibleTarget(0, 0))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 1", createImpossibleTarget(1, 1))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 3", createImpossibleTarget(3, 3))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 0-1", createImpossibleTarget(0, 1))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 0-3", createImpossibleTarget(0, 3))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 1-3", createImpossibleTarget(1, 3))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 2-3", createImpossibleTarget(2, 3))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible max", createImpossibleTarget(0, Integer.MAX_VALUE))); - // - /* - runner.registerDialog(new PlayerChooseTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "creatures 0, e.g. X=0", createCreatureTarget(0, 0))); // simulate X=0 - runner.registerDialog(new PlayerChooseTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "creatures 1", createCreatureTarget(1, 1))); - runner.registerDialog(new PlayerChooseTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "creatures 3", createCreatureTarget(3, 3))); - runner.registerDialog(new PlayerChooseTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "creatures 5", createCreatureTarget(5, 5))); - runner.registerDialog(new PlayerChooseTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "creatures max", createCreatureTarget(0, Integer.MAX_VALUE))); - */ + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 0, e.g. X=0", createImpossibleTarget(0, 0)).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 1", createImpossibleTarget(1, 1)).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 3", createImpossibleTarget(3, 3)).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 0-1", createImpossibleTarget(0, 1)).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 0-3", createImpossibleTarget(0, 3)).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 1-3", createImpossibleTarget(1, 3)).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 2-3", createImpossibleTarget(2, 3)).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible max", createImpossibleTarget(0, Integer.MAX_VALUE)).aiMustChoose(false, 0)); } } } diff --git a/Mage.Common/src/main/java/mage/utils/testers/ChooseUseTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/ChooseUseTestableDialog.java index 3e8137af32b..80a1e7a8f69 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/ChooseUseTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/ChooseUseTestableDialog.java @@ -5,6 +5,7 @@ import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; import mage.util.CardUtil; +import mage.util.DebugUtil; import java.util.ArrayList; import java.util.Arrays; @@ -27,7 +28,11 @@ class ChooseUseTestableDialog extends BaseTestableDialog { String messageAdditional; public ChooseUseTestableDialog(boolean isYou, String name, String trueText, String falseText, String messageMain, String messageAdditional) { - super(String.format("player.chooseUse(%s)", isYou ? "you" : "AI"), name + buildName(trueText, falseText, messageMain, messageAdditional), ""); + super(String.format("player.chooseUse(%s)", isYou ? "you" : "AI"), + name + buildName(trueText, falseText, messageMain, messageAdditional), + "", + new BaseTestableResult() + ); this.isYou = isYou; this.trueText = trueText; this.falseText = falseText; @@ -42,8 +47,9 @@ class ChooseUseTestableDialog extends BaseTestableDialog { } @Override - public List showDialog(Player player, Ability source, Game game, Player opponent) { + public void showDialog(Player player, Ability source, Game game, Player opponent) { Player choosingPlayer = this.isYou ? player : opponent; + String chooseDebugSource = DebugUtil.getMethodNameWithSource(0, "class"); boolean chooseRes = choosingPlayer.chooseUse( Outcome.Benefit, messageMain, @@ -53,9 +59,10 @@ class ChooseUseTestableDialog extends BaseTestableDialog { source, game ); - List result = new ArrayList<>(); - result.add(chooseRes ? "TRUE" : "FALSE"); - return result; + List res = new ArrayList<>(); + res.add(chooseRes ? "TRUE" : "FALSE"); + + this.getResult().onFinish(chooseDebugSource, chooseRes, res); } static public void register(TestableDialogsRunner runner) { diff --git a/Mage.Common/src/main/java/mage/utils/testers/GetAmountTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/GetAmountTestableDialog.java index 0a66bac8f9d..2007af09a56 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/GetAmountTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/GetAmountTestableDialog.java @@ -3,6 +3,7 @@ package mage.utils.testers; import mage.abilities.Ability; import mage.game.Game; import mage.players.Player; +import mage.util.DebugUtil; import java.util.ArrayList; import java.util.Arrays; @@ -26,37 +27,53 @@ class GetAmountTestableDialog extends BaseTestableDialog { public GetAmountTestableDialog(boolean isYou, int min, int max) { super(String.format("player.getAmount(%s)", isYou ? "you" : "AI"), - String.format("from %d to %d", min, max), ""); + String.format("from %d to %d", min, max), + "", + new AmountTestableResult() + ); this.isYou = isYou; this.min = min; this.max = max; } + private GetAmountTestableDialog aiMustChoose(int minAmount, int maxAmount) { + // require min/max cause AI logic uses random choices + AmountTestableResult res = ((AmountTestableResult) this.getResult()); + res.aiAssertEnabled = true; + res.aiAssertMinAmount = minAmount; + res.aiAssertMaxAmount = maxAmount; + return this; + } + @Override - public List showDialog(Player player, Ability source, Game game, Player opponent) { + public void showDialog(Player player, Ability source, Game game, Player opponent) { Player choosingPlayer = this.isYou ? player : opponent; String message = "message with html"; - int chooseRes; - chooseRes = choosingPlayer.getAmount(this.min, this.max, message, source, game); - List result = new ArrayList<>(); - result.add(getGroup() + " - " + this.getName() + " selected " + chooseRes); - return result; + String chooseDebugSource = DebugUtil.getMethodNameWithSource(0, "class"); + int chooseRes = choosingPlayer.getAmount(this.min, this.max, message, source, game); + List res = new ArrayList<>(); + res.add(getGroup() + " - " + this.getName() + " selected " + chooseRes); + + ((AmountTestableResult) this.getResult()).onFinish(chooseDebugSource, true, res, chooseRes); } static public void register(TestableDialogsRunner runner) { List isYous = Arrays.asList(false, true); for (boolean isYou : isYous) { - runner.registerDialog(new GetAmountTestableDialog(isYou, 0, 0)); - runner.registerDialog(new GetAmountTestableDialog(isYou, 0, 1)); - runner.registerDialog(new GetAmountTestableDialog(isYou, 0, 3)); - runner.registerDialog(new GetAmountTestableDialog(isYou, 0, 50)); - runner.registerDialog(new GetAmountTestableDialog(isYou, 0, 500)); - runner.registerDialog(new GetAmountTestableDialog(isYou, 1, 1)); - runner.registerDialog(new GetAmountTestableDialog(isYou, 1, 3)); - runner.registerDialog(new GetAmountTestableDialog(isYou, 1, 50)); - runner.registerDialog(new GetAmountTestableDialog(isYou, 3, 3)); - runner.registerDialog(new GetAmountTestableDialog(isYou, 3, 10)); - runner.registerDialog(new GetAmountTestableDialog(isYou, 10, 10)); + // TODO: add good and bad effects: + // - on good: choose random big value + // - on bad: choose lower value + runner.registerDialog(new GetAmountTestableDialog(isYou, 0, 0).aiMustChoose(0, 0)); + runner.registerDialog(new GetAmountTestableDialog(isYou, 0, 1).aiMustChoose(0, 1)); + runner.registerDialog(new GetAmountTestableDialog(isYou, 0, 3).aiMustChoose(0, 3)); + runner.registerDialog(new GetAmountTestableDialog(isYou, 0, 50).aiMustChoose(0, 50)); + runner.registerDialog(new GetAmountTestableDialog(isYou, 0, 500).aiMustChoose(0, 500)); + runner.registerDialog(new GetAmountTestableDialog(isYou, 1, 1).aiMustChoose(1, 1)); + runner.registerDialog(new GetAmountTestableDialog(isYou, 1, 3).aiMustChoose(1, 3)); + runner.registerDialog(new GetAmountTestableDialog(isYou, 1, 50).aiMustChoose(1, 50)); + runner.registerDialog(new GetAmountTestableDialog(isYou, 3, 3).aiMustChoose(3, 3)); + runner.registerDialog(new GetAmountTestableDialog(isYou, 3, 10).aiMustChoose(3, 10)); + runner.registerDialog(new GetAmountTestableDialog(isYou, 10, 10).aiMustChoose(10, 10)); } } } diff --git a/Mage.Common/src/main/java/mage/utils/testers/GetMultiAmountTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/GetMultiAmountTestableDialog.java index 2c1f9046f3a..8f5f89be557 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/GetMultiAmountTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/GetMultiAmountTestableDialog.java @@ -5,12 +5,14 @@ import mage.constants.MultiAmountType; import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; +import mage.util.DebugUtil; import mage.util.MultiAmountMessage; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; +import java.util.stream.IntStream; /** * Part of testable game dialogs @@ -36,7 +38,9 @@ class GetMultiAmountTestableDialog extends BaseTestableDialog { public GetMultiAmountTestableDialog(boolean isYou, String info, int totalMin, int totalMax, List> options) { super(String.format("player.getMultiAmount(%s)", isYou ? "you" : "AI"), String.format("%s, %d options from [%d-%d]", info, options.size(), totalMin, totalMax), - ""); + "", + new MultiAmountTestableResult() + ); this.isYou = isYou; this.totalMin = totalMin; this.totalMax = totalMax; @@ -48,13 +52,35 @@ class GetMultiAmountTestableDialog extends BaseTestableDialog { } } + private GetMultiAmountTestableDialog aiMustChoose(Integer... needValues) { + // TODO: AI use default distribution: + // - bad effect: min possible values + // - good effect: max possible and distributed values + MultiAmountTestableResult res = ((MultiAmountTestableResult) this.getResult()); + res.aiAssertEnabled = true; + res.aiAssertValues = Arrays.stream(needValues).collect(Collectors.toList()); + return this; + } + + private GetMultiAmountTestableDialog aiMustChooseMany(Integer options, Integer perOption) { + List need = new ArrayList<>(); + IntStream.rangeClosed(1, options).forEach(x -> { + need.add(perOption); + }); + + MultiAmountTestableResult res = ((MultiAmountTestableResult) this.getResult()); + res.aiAssertEnabled = true; + res.aiAssertValues = need; + return this; + } + @Override - public List showDialog(Player player, Ability source, Game game, Player opponent) { + public void showDialog(Player player, Ability source, Game game, Player opponent) { Player choosingPlayer = this.isYou ? player : opponent; //String message = "message with html"; - List chooseRes; List options = this.amountOptions.stream().map(MultiAmountMessage::copy).collect(Collectors.toList()); - chooseRes = choosingPlayer.getMultiAmountWithIndividualConstraints( + String chooseDebugSource = DebugUtil.getMethodNameWithSource(0, "class"); + List chooseRes = choosingPlayer.getMultiAmountWithIndividualConstraints( Outcome.Benefit, options, this.totalMin, @@ -63,24 +89,24 @@ class GetMultiAmountTestableDialog extends BaseTestableDialog { game ); - List result = new ArrayList<>(); - result.add(getGroup() + " - " + this.getName()); + List res = new ArrayList<>(); + res.add(getGroup() + " - " + this.getName()); int selectedIndex = -1; int selectedTotal = 0; for (Integer selectedValue : chooseRes) { selectedIndex++; selectedTotal += selectedValue; MultiAmountMessage option = this.amountOptions.get(selectedIndex); - result.add(String.format("%d from [%d-%d, def %d]", + res.add(String.format("%d from [%d-%d, def %d]", selectedValue, option.min, option.max, option.defaultValue )); } - result.add("total selected: " + selectedTotal); + res.add("total selected: " + selectedTotal); - return result; + ((MultiAmountTestableResult) this.getResult()).onFinish(chooseDebugSource, true, res, chooseRes); } static public void register(TestableDialogsRunner runner) { @@ -88,28 +114,29 @@ class GetMultiAmountTestableDialog extends BaseTestableDialog { for (boolean isYou : isYous) { // make sure default values are valid due min/max settings + // TODO: add bad effect for AI (must test default distribution) + // single target - runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "one, 0 def", 0, 1, genSameOptions(1, 0, 1, 0))); - runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "one, 0 def", 0, 3, genSameOptions(1, 0, 3, 0))); - runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "one, 1 def", 1, 1, genSameOptions(1, 1, 1, 1))); - runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "one, 1 def", 1, 3, genSameOptions(1, 1, 3, 1))); - runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "one, 5 def", 0, 10, genSameOptions(1, 0, 10, 5))); - runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "one, 10 def", 10, 10, genSameOptions(1, 0, 10, 10))); + runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "one, 0 def", 0, 1, genSameOptions(1, 0, 1, 0)).aiMustChoose(1)); + runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "one, 0 def", 0, 3, genSameOptions(1, 0, 3, 0)).aiMustChoose(3)); + runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "one, 1 def", 1, 1, genSameOptions(1, 1, 1, 1)).aiMustChoose(1)); + runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "one, 1 def", 1, 3, genSameOptions(1, 1, 3, 1)).aiMustChoose(3)); + runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "one, 5 def", 0, 10, genSameOptions(1, 0, 10, 5)).aiMustChoose(10)); + runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "one, 10 def", 10, 10, genSameOptions(1, 0, 10, 10)).aiMustChoose(10)); // multiple targets - runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "many, 0 def", 0, 5, genSameOptions(3, 0, 3, 0))); - runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "many, 0 def", 0, 5, genSameOptions(3, 0, 3, 0))); - runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "many, 1 def", 1, 5, genSameOptions(3, 1, 3, 1))); - runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "many, 1 def", 1, 5, genSameOptions(3, 1, 3, 1))); - runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "many, 20 def", 0, 60, genSameOptions(3, 0, 60, 20))); - runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "many, 20 def", 60, 60, genSameOptions(3, 0, 60, 20))); + runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "many, 0 def", 0, 5, genSameOptions(3, 0, 3, 0)).aiMustChoose(2, 2, 1)); + runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "many, 1 def", 1, 5, genSameOptions(3, 1, 3, 1)).aiMustChoose(2, 2, 1)); + runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "many, 20 def", 0, 60, genSameOptions(3, 0, 60, 20)).aiMustChoose(20, 20, 20)); + runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "many, 20 def", 60, 60, genSameOptions(3, 0, 60, 20)).aiMustChoose(20, 20, 20)); // big lists - runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "big list", 0, 100, genSameOptions(20, 0, 100, 0))); + runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "big list", 0, 100, genSameOptions(20, 0, 100, 0)).aiMustChooseMany(20, 5)); + runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "big list", 0, 100, genSameOptions(100, 0, 100, 0)).aiMustChooseMany(100, 1)); } } - private static List> genSameOptions(int amount, int min, int max, int def) { + private static List> genSameOptions(int options, int min, int max, int def) { List> res = new ArrayList<>(); - for (int i = 0; i < amount; i++) { + for (int i = 0; i < options; i++) { // min, max, default res.add(Arrays.asList(min, max, def)); } diff --git a/Mage.Common/src/main/java/mage/utils/testers/MultiAmountTestableResult.java b/Mage.Common/src/main/java/mage/utils/testers/MultiAmountTestableResult.java new file mode 100644 index 00000000000..53ae9a4f5ab --- /dev/null +++ b/Mage.Common/src/main/java/mage/utils/testers/MultiAmountTestableResult.java @@ -0,0 +1,54 @@ +package mage.utils.testers; + +import java.util.ArrayList; +import java.util.List; + +/** + * Part of testable game dialogs + * + * @author JayDi85 + */ +public class MultiAmountTestableResult extends BaseTestableResult { + + List selectedValues; + + boolean aiAssertEnabled = false; + List aiAssertValues = new ArrayList<>(); + + public void onFinish(String resDebugSource, boolean status, List info, List selectedValues) { + this.onFinish(resDebugSource, status, info); + this.selectedValues = selectedValues; + } + + @Override + public String getResAssert() { + if (!this.aiAssertEnabled) { + return null; + } + + // not finished + if (this.selectedValues == null) { + return null; + } + + // wrong selection + String selected = this.selectedValues.toString(); + String need = this.aiAssertValues.toString(); + + if (!selected.equals(need)) { + return String.format("Wrong selection: need %s, but get %s", + need, + selected + ); + } + + // all fine + return ""; + } + + @Override + public void onClear() { + super.onClear(); + this.selectedValues = null; + } +} diff --git a/Mage.Common/src/main/java/mage/utils/testers/TargetTestableResult.java b/Mage.Common/src/main/java/mage/utils/testers/TargetTestableResult.java new file mode 100644 index 00000000000..1f49cb8d831 --- /dev/null +++ b/Mage.Common/src/main/java/mage/utils/testers/TargetTestableResult.java @@ -0,0 +1,61 @@ +package mage.utils.testers; + +import mage.target.Target; + +import java.util.List; + +/** + * Part of testable game dialogs + * + * @author JayDi85 + */ +public class TargetTestableResult extends BaseTestableResult { + + Target target = null; + + boolean aiAssertEnabled = false; + boolean aiAssertResStatus = false; + int aiAssertTargetsCount = 0; + + public void onFinish(String resDebugSource, boolean status, List info, Target target) { + this.onFinish(resDebugSource, status, info); + this.target = target; + } + + @Override + public String getResAssert() { + if (!this.aiAssertEnabled) { + return null; + } + + // not finished + if (this.target == null) { + return null; + } + + // wrong choose + if (this.getResStatus() != this.aiAssertResStatus) { + return String.format("Wrong status: need %s, but get %s", + this.aiAssertResStatus, + this.getResStatus() + ); + } + + // wrong targets + if (this.target.getTargets().size() != this.aiAssertTargetsCount) { + return String.format("Wrong targets count: need %d, but get %d", + this.aiAssertTargetsCount, + this.target.getTargets().size() + ); + } + + // all fine + return ""; + } + + @Override + public void onClear() { + super.onClear(); + this.target = null; + } +} diff --git a/Mage.Common/src/main/java/mage/utils/testers/TestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/TestableDialog.java index 1479ee9f306..d5e86740ff8 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/TestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/TestableDialog.java @@ -4,8 +4,6 @@ import mage.abilities.Ability; import mage.game.Game; import mage.players.Player; -import java.util.List; - /** * Part of testable game dialogs *

@@ -17,7 +15,11 @@ import java.util.List; * * @author JayDi85 */ -interface TestableDialog { +public interface TestableDialog { + + void setRegNumber(Integer regNumber); + + Integer getRegNumber(); String getGroup(); @@ -25,7 +27,20 @@ interface TestableDialog { String getDescription(); - List showDialog(Player player, Ability source, Game game, Player opponent); + TestableResult getResult(); - void showResult(Player player, Game game, String result); + /** + * Prepare dialog before show, e.g. clear prev results + */ + void prepare(); + + /** + * Show game dialog to the user and save result + */ + void showDialog(Player player, Ability source, Game game, Player opponent); + + /** + * Show result dialog to the user + */ + void showResult(Player player, Game game); } diff --git a/Mage.Common/src/main/java/mage/utils/testers/TestableDialogsRunner.java b/Mage.Common/src/main/java/mage/utils/testers/TestableDialogsRunner.java index 3c2cfb3840d..0970d8ecc94 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/TestableDialogsRunner.java +++ b/Mage.Common/src/main/java/mage/utils/testers/TestableDialogsRunner.java @@ -8,8 +8,10 @@ import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; -import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; /** @@ -55,7 +57,7 @@ import java.util.stream.Collectors; */ public class TestableDialogsRunner { - private final List dialogs = new ArrayList<>(); + private final Map dialogs = new LinkedHashMap<>(); static final int LAST_SELECTED_GROUP_ID = 997; static final int LAST_SELECTED_DIALOG_ID = 998; @@ -79,12 +81,14 @@ public class TestableDialogsRunner { } void registerDialog(TestableDialog dialog) { - this.dialogs.add(dialog); + Integer regNumber = this.dialogs.size() + 1; + dialog.setRegNumber(regNumber); + this.dialogs.put(regNumber, dialog); } public void selectAndShowTestableDialog(Player player, Ability source, Game game, Player opponent) { // select group or fast links - List groups = this.dialogs.stream() + List groups = this.dialogs.values().stream() .map(TestableDialog::getGroup) .distinct() .sorted() @@ -129,8 +133,9 @@ public class TestableDialogsRunner { // all fine, can show it and finish lastSelectedGroup = needGroup; lastSelectedDialog = needDialog; - List resInfo = needDialog.showDialog(player, source, game, opponent); - needDialog.showResult(player, game, String.join("
", resInfo)); + needDialog.prepare(); + needDialog.showDialog(player, source, game, opponent); + needDialog.showResult(player, game); } private Choice prepareSelectGroupChoice(List groups) { @@ -199,5 +204,9 @@ public class TestableDialogsRunner { } return choice; } + + public Collection getDialogs() { + return this.dialogs.values(); + } } diff --git a/Mage.Common/src/main/java/mage/utils/testers/TestableResult.java b/Mage.Common/src/main/java/mage/utils/testers/TestableResult.java new file mode 100644 index 00000000000..7615aad678a --- /dev/null +++ b/Mage.Common/src/main/java/mage/utils/testers/TestableResult.java @@ -0,0 +1,43 @@ +package mage.utils.testers; + +import java.util.List; + +/** + * Part of testable game dialogs, must contain dialogs result + * + * @author JayDi85 + */ +public interface TestableResult { + + /** + * Get source code line with called dialog, use it as starting debug point + */ + String getResDebugSource(); + + /** + * Dialog's result + */ + boolean getResStatus(); + + /** + * Dialog's detail result + */ + List getResDetails(); + + /** + * Save new result after show dialog + */ + void onFinish(String chooseDebugSource, boolean resStatus, List resDetails); + + boolean isFinished(); + + void onClear(); + + /** + * Assert dialog result + * - null - not ready (dev must setup wanted result) + * - empty - good + * - not empty - fail (return error message) + */ + String getResAssert(); +} diff --git a/Mage.Common/src/main/java/mage/view/ChatMessage.java b/Mage.Common/src/main/java/mage/view/ChatMessage.java index adf541553cb..02a5b6db31c 100644 --- a/Mage.Common/src/main/java/mage/view/ChatMessage.java +++ b/Mage.Common/src/main/java/mage/view/ChatMessage.java @@ -25,7 +25,12 @@ public class ChatMessage implements Serializable { } public enum MessageType { - USER_INFO, STATUS, GAME, TALK, WHISPER_FROM, WHISPER_TO + USER_INFO, // system messages + STATUS, // system messages + GAME, // game logs + TALK, // public chat + WHISPER_FROM, // private chat income + WHISPER_TO // private chat outcome } public enum SoundToPlay { diff --git a/Mage.Common/src/main/java/mage/view/GameView.java b/Mage.Common/src/main/java/mage/view/GameView.java index 59d47955831..4b6d06c7c95 100644 --- a/Mage.Common/src/main/java/mage/view/GameView.java +++ b/Mage.Common/src/main/java/mage/view/GameView.java @@ -67,6 +67,7 @@ public class GameView implements Serializable { // TODO: implement and support in admin tools private int totalErrorsCount; private int totalEffectsCount; + private int gameCycle; public GameView(GameState state, Game game, UUID createdForPlayerId, UUID watcherUserId) { Player createdForPlayer = null; @@ -214,6 +215,7 @@ public class GameView implements Serializable { this.rollbackTurnsAllowed = game.getOptions().rollbackTurnsAllowed; this.totalErrorsCount = game.getTotalErrorsCount(); this.totalEffectsCount = game.getTotalEffectsCount(); + this.gameCycle = game.getState().getApplyEffectsCounter(); } private void checkPaid(UUID uuid, StackAbility stackAbility) { @@ -358,4 +360,8 @@ public class GameView implements Serializable { public int getTotalEffectsCount() { return this.totalEffectsCount; } + + public int getGameCycle() { + return this.gameCycle; + } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java index 99168e5ea3b..50468b91552 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java @@ -5,11 +5,13 @@ import mage.abilities.Ability; import mage.abilities.common.CanBeYourCommanderAbility; import mage.abilities.common.CommanderChooseColorAbility; import mage.abilities.keyword.CompanionAbility; +import mage.abilities.keyword.StationLevelAbility; import mage.cards.Card; import mage.cards.decks.Constructed; import mage.cards.decks.Deck; import mage.cards.decks.DeckValidatorErrorType; import mage.constants.CardType; +import mage.constants.SubType; import mage.filter.FilterMana; import mage.util.CardUtil; import mage.util.ManaUtil; @@ -51,9 +53,19 @@ public abstract class AbstractCommander extends Constructed { protected abstract boolean checkBanned(Map counts); protected boolean checkCommander(Card commander, Set commanders) { - return commander.hasCardTypeForDeckbuilding(CardType.CREATURE) && commander.isLegendary() - || commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance()) - || (validators.stream().anyMatch(validator -> validator.specialCheck(commander)) && commanders.size() == 2); + if (commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance())) { + return true; + } + if (commander.isLegendary() + && (commander.hasCardTypeForDeckbuilding(CardType.CREATURE) + || commander.hasSubTypeForDeckbuilding(SubType.VEHICLE) + || commander.hasSubTypeForDeckbuilding(SubType.SPACECRAFT) + && CardUtil + .castStream(commander.getAbilities(), StationLevelAbility.class) + .anyMatch(StationLevelAbility::hasPT))) { + return true; + } + return commanders.size() == 2 && validators.stream().anyMatch(validator -> validator.specialCheck(commander)); } protected boolean checkPartners(Set commanders) { diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformUnlimited.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformUnlimited.java new file mode 100644 index 00000000000..8dfcfc03f78 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformUnlimited.java @@ -0,0 +1,34 @@ +package mage.deck; + +import mage.cards.decks.Deck; +import mage.cards.decks.DeckValidator; +import mage.cards.decks.DeckValidatorErrorType; + +/** + * @author resech + */ +public class FreeformUnlimited extends DeckValidator { + + public FreeformUnlimited() { + this("Constructed - Freeform Unlimited", null); + } + + public FreeformUnlimited(String name, String shortName) { + super(name, shortName); + } + + @Override + public int getDeckMinSize() { + return 0; + } + + @Override + public int getSideboardMinSize() { + return 0; + } + + @Override + public boolean validate(Deck deck) { + return true; + } +} diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Historic.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Historic.java index 26a3595c5c6..e6dd75163cb 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Historic.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Historic.java @@ -32,7 +32,6 @@ public class Historic extends Constructed { banned.add("Agent of Treachery"); banned.add("Brainstorm"); banned.add("Channel"); - banned.add("Counterspell"); banned.add("Dark Ritual"); banned.add("Demonic Tutor"); banned.add("Fires of Invention"); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Standard.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Standard.java index ec41f96cae2..0796aaf056d 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Standard.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Standard.java @@ -19,10 +19,13 @@ public class Standard extends Constructed { setCodes.addAll(makeLegalSets()); - banned.add("The Meathook Massacre"); - banned.add("Fable of the Mirror-Breaker"); - banned.add("Reckoner Bankbuster"); - banned.add("Invoke Despair"); + banned.add("Abuelo's Awakening"); + banned.add("Cori-Steel Cutter"); + banned.add("Heartfire Hero"); + banned.add("Hopeless Nightmare"); + banned.add("Monstrous Rage"); + banned.add("This Town Ain't Big Enough"); + banned.add("Up the Beanstalk"); } static List makeLegalSets() { diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java index 14ba9d0ea2b..f25152f9a90 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java @@ -23,6 +23,7 @@ import mage.game.stack.StackAbility; import mage.game.stack.StackObject; import mage.player.ai.ma.optimizers.TreeOptimizer; import mage.player.ai.ma.optimizers.impl.*; +import mage.player.ai.score.GameStateEvaluator2; import mage.player.ai.util.CombatInfo; import mage.player.ai.util.CombatUtil; import mage.players.Player; @@ -113,6 +114,13 @@ public class ComputerPlayer6 extends ComputerPlayer { this.actionCache = player.actionCache; } + /** + * Change simulation timeout - used for AI stability tests only + */ + public void setMaxThinkTimeSecs(int maxThinkTimeSecs) { + this.maxThinkTimeSecs = maxThinkTimeSecs; + } + @Override public ComputerPlayer6 copy() { return new ComputerPlayer6(this); @@ -205,10 +213,8 @@ public class ComputerPlayer6 extends ComputerPlayer { logger.trace("Add Action [" + depth + "] " + node.getAbilities().toString() + " a: " + alpha + " b: " + beta); } Game game = node.getGame(); - if (!COMPUTER_DISABLE_TIMEOUT_IN_GAME_SIMULATIONS - && Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.debug("interrupted"); + if (!COMPUTER_DISABLE_TIMEOUT_IN_GAME_SIMULATIONS && Thread.currentThread().isInterrupted()) { + logger.debug("AI game sim interrupted by timeout"); return GameStateEvaluator2.evaluate(playerId, game).getTotalScore(); } // Condition to stop deeper simulation @@ -399,7 +405,7 @@ public class ComputerPlayer6 extends ComputerPlayer { if (effect != null && stackObject.getControllerId().equals(playerId)) { Target target = effect.getTarget(); - if (!target.isChoiceCompleted(game)) { + if (!target.isChoiceCompleted(getId(), (StackAbility) stackObject, game)) { for (UUID targetId : target.possibleTargets(stackObject.getControllerId(), stackObject.getStackAbility(), game)) { Game sim = game.createSimulationForAI(); StackAbility newAbility = (StackAbility) stackObject.copy(); @@ -430,6 +436,8 @@ public class ComputerPlayer6 extends ComputerPlayer { * @return */ protected Integer addActionsTimed() { + // TODO: all actions added and calculated one by one, + // multithreading do not supported here // run new game simulation in parallel thread FutureTask task = new FutureTask<>(() -> addActions(root, maxDepth, Integer.MIN_VALUE, Integer.MAX_VALUE)); threadPoolSimulations.execute(task); @@ -445,15 +453,23 @@ public class ComputerPlayer6 extends ComputerPlayer { } } catch (TimeoutException | InterruptedException e) { // AI thinks too long - logger.info("ai simulating - timed out"); + // how-to fix: look at stack info - it can contain bad ability with infinite choose dialog + logger.warn(""); + logger.warn("AI player thinks too long (report it to github):"); + logger.warn(" - player: " + getName()); + logger.warn(" - battlefield size: " + root.game.getBattlefield().getAllPermanents().size()); + logger.warn(" - stack: " + root.game.getStack()); + logger.warn(" - game: " + root.game); + printFreezeNode(root); + logger.warn(""); task.cancel(true); } catch (ExecutionException e) { // game error - logger.error("AI simulation catch game error: " + e, e); + logger.error("AI player catch game error in simulation - " + getName() + " - " + root.game + ": " + e, e); task.cancel(true); // real games: must catch and log // unit tests: must raise again for fast fail - if (this.isTestsMode()) { + if (this.isTestMode() && this.isFastFailInTestMode()) { throw new IllegalStateException("One of the simulated games raise the error: " + e, e); } } catch (Throwable e) { @@ -465,11 +481,33 @@ public class ComputerPlayer6 extends ComputerPlayer { return 0; } + private void printFreezeNode(SimulationNode2 root) { + // print simple tree - there are possible multiple child nodes, but ignore it - same for abilities + List chain = new ArrayList<>(); + SimulationNode2 node = root; + while (node != null) { + if (node.abilities != null && !node.abilities.isEmpty()) { + Ability ability = node.abilities.get(0); + String sourceInfo = CardUtil.getSourceIdName(node.game, ability); + chain.add(String.format("%s: %s", + (sourceInfo.isEmpty() ? "unknown" : sourceInfo), + ability + )); + } + node = node.children == null || node.children.isEmpty() ? null : node.children.get(0); + } + logger.warn("Possible freeze chain:"); + if (root != null && chain.isEmpty()) { + logger.warn(" - unknown use case"); // maybe can't finish any calc, maybe related to target options, I don't know + } + chain.forEach(s -> { + logger.warn(" - " + s); + }); + } + protected int simulatePriority(SimulationNode2 node, Game game, int depth, int alpha, int beta) { - if (!COMPUTER_DISABLE_TIMEOUT_IN_GAME_SIMULATIONS - && Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.info("interrupted"); + if (!COMPUTER_DISABLE_TIMEOUT_IN_GAME_SIMULATIONS && Thread.currentThread().isInterrupted()) { + logger.debug("AI game sim interrupted by timeout"); return GameStateEvaluator2.evaluate(playerId, game).getTotalScore(); } node.setGameValue(game.getState().getValue(true).hashCode()); @@ -497,9 +535,7 @@ public class ComputerPlayer6 extends ComputerPlayer { int bestValSubNodes = Integer.MIN_VALUE; for (Ability action : allActions) { actionNumber++; - if (!COMPUTER_DISABLE_TIMEOUT_IN_GAME_SIMULATIONS - && Thread.interrupted()) { - Thread.currentThread().interrupt(); + if (!COMPUTER_DISABLE_TIMEOUT_IN_GAME_SIMULATIONS && Thread.currentThread().isInterrupted()) { logger.info("Sim Prio [" + depth + "] -- interrupted"); break; } @@ -848,10 +884,12 @@ public class ComputerPlayer6 extends ComputerPlayer { if (targets.isEmpty()) { return super.chooseTarget(outcome, cards, target, source, game); } - if (!target.isChoiceCompleted(game)) { + + UUID abilityControllerId = target.getAffectedAbilityControllerId(getId()); + if (!target.isChoiceCompleted(abilityControllerId, source, game)) { for (UUID targetId : targets) { target.addTarget(targetId, source, game); - if (target.isChoiceCompleted(game)) { + if (target.isChoiceCompleted(abilityControllerId, source, game)) { targets.clear(); return true; } @@ -866,10 +904,12 @@ public class ComputerPlayer6 extends ComputerPlayer { if (targets.isEmpty()) { return super.choose(outcome, cards, target, source, game); } - if (!target.isChoiceCompleted(game)) { + + UUID abilityControllerId = target.getAffectedAbilityControllerId(getId()); + if (!target.isChoiceCompleted(abilityControllerId, source, game)) { for (UUID targetId : targets) { target.add(targetId, game); - if (target.isChoiceCompleted(game)) { + if (target.isChoiceCompleted(abilityControllerId, source, game)) { targets.clear(); return true; } diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java index f78cceee8f1..09af732d422 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java @@ -3,6 +3,7 @@ package mage.player.ai; import mage.abilities.Ability; import mage.constants.RangeOfInfluence; import mage.game.Game; +import mage.player.ai.score.GameStateEvaluator2; import org.apache.log4j.Logger; import java.util.Date; @@ -111,8 +112,6 @@ public class ComputerPlayer7 extends ComputerPlayer6 { protected void calculateActions(Game game) { if (!getNextAction(game)) { - //logger.info("--- calculating possible actions for " + this.getName() + " on " + game.toString()); - Date startTime = new Date(); currentScore = GameStateEvaluator2.evaluate(playerId, game).getTotalScore(); Game sim = createSimulation(game); SimulationNode2.resetCount(); @@ -143,17 +142,9 @@ public class ComputerPlayer7 extends ComputerPlayer6 { } } } else { - logger.info('[' + game.getPlayer(playerId).getName() + "][pre] Action: skip"); + // nothing to choose or freeze/infinite game + logger.info("AI player can't find next action: " + getName()); } - Date endTime = new Date(); - this.setLastThinkTime((endTime.getTime() - startTime.getTime())); - - /* - logger.warn("Last think time: " + this.getLastThinkTime() - + "; actions: " + actions.size() - + "; hand: " + this.getHand().size() - + "; permanents: " + game.getBattlefield().getAllPermanents().size()); - */ } else { logger.debug("Next Action exists!"); } diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/util/CombatUtil.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/util/CombatUtil.java index 873b4c5bbcd..32bc78c75b7 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/util/CombatUtil.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/util/CombatUtil.java @@ -13,7 +13,7 @@ import mage.game.permanent.Permanent; import mage.game.turn.CombatDamageStep; import mage.game.turn.EndOfCombatStep; import mage.game.turn.Step; -import mage.player.ai.GameStateEvaluator2; +import mage.player.ai.score.GameStateEvaluator2; import mage.players.Player; import org.apache.log4j.Logger; diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index ace8620e6b2..20a8114e4f2 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -1,20 +1,12 @@ package mage.player.ai; -import mage.ApprovingObject; -import mage.ConditionalMana; -import mage.MageObject; -import mage.Mana; +import mage.*; import mage.abilities.*; import mage.abilities.costs.mana.*; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; -import mage.abilities.keyword.*; import mage.abilities.mana.ActivatedManaAbilityImpl; import mage.abilities.mana.ManaOptions; import mage.cards.Card; import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.cards.RateCard; import mage.cards.decks.Deck; import mage.cards.decks.DeckValidator; @@ -24,31 +16,20 @@ import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.choices.Choice; import mage.constants.*; -import mage.counters.CounterType; -import mage.filter.FilterCard; -import mage.filter.FilterPermanent; -import mage.filter.StaticFilters; -import mage.filter.common.*; -import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.filter.common.FilterLandCard; import mage.game.Game; -import mage.game.combat.CombatGroup; import mage.game.draft.Draft; -import mage.game.events.GameEvent; import mage.game.match.Match; import mage.game.permanent.Permanent; -import mage.game.stack.Spell; -import mage.game.stack.StackObject; import mage.game.tournament.Tournament; -import mage.player.ai.simulators.CombatGroupSimulator; -import mage.player.ai.simulators.CombatSimulator; -import mage.player.ai.simulators.CreatureSimulator; import mage.players.ManaPoolItem; import mage.players.Player; import mage.players.PlayerImpl; import mage.players.net.UserData; import mage.players.net.UserGroup; -import mage.target.*; -import mage.target.common.*; +import mage.target.Target; +import mage.target.TargetAmount; +import mage.target.TargetCard; import mage.util.*; import org.apache.log4j.Logger; @@ -57,21 +38,21 @@ import java.util.*; import java.util.Map.Entry; /** - * AI: basic server side bot with simple actions support (game, draft, construction/sideboarding) + * AI: basic server side bot with simple actions support (game, draft, construction/sideboarding). + * Full and minimum implementation of all choose dialogs to allow AI to start and finish a real game. + * Used as parent class for any AI implementations. *

- * TODO: combine choose and chooseTarget to single logic to use shared code * * @author BetaSteward_at_googlemail.com, JayDi85 */ public class ComputerPlayer extends PlayerImpl { - private static final Logger log = Logger.getLogger(ComputerPlayer.class); - private long lastThinkTime = 0; // msecs for last AI actions calc + private static final Logger logger = Logger.getLogger(ComputerPlayer.class); - protected int PASSIVITY_PENALTY = 5; // Penalty value for doing nothing if some actions are available + protected static final int PASSIVITY_PENALTY = 5; // Penalty value for doing nothing if some actions are available // debug only: set TRUE to debug simulation's code/games (on false sim thread will be stopped after few secs by timeout) - protected boolean COMPUTER_DISABLE_TIMEOUT_IN_GAME_SIMULATIONS = true; // DebugUtil.AI_ENABLE_DEBUG_MODE; + public static final boolean COMPUTER_DISABLE_TIMEOUT_IN_GAME_SIMULATIONS = false; // DebugUtil.AI_ENABLE_DEBUG_MODE; // AI agents uses game simulation thread for all calcs and it's high CPU consumption // More AI threads - more parallel AI games can be calculate @@ -80,16 +61,13 @@ public class ComputerPlayer extends PlayerImpl { // How-to use: // * 1 for debug or stable // * 5 for good performance on average computer - // * use your's CPU cores for best performance + // * use yours CPU cores for best performance // TODO: add server config to control max AI threads (with CPU cores by default) // TODO: rework AI implementation to use multiple sims calculation instead one by one - final static int COMPUTER_MAX_THREADS_FOR_SIMULATIONS = 1;//DebugUtil.AI_ENABLE_DEBUG_MODE ? 1 : 5; + final static int COMPUTER_MAX_THREADS_FOR_SIMULATIONS = 5;//DebugUtil.AI_ENABLE_DEBUG_MODE ? 1 : 5; - private final transient Map unplayable = new TreeMap<>(); - private final transient List playableNonInstant = new ArrayList<>(); - private final transient List playableInstant = new ArrayList<>(); - private final transient List playableAbilities = new ArrayList<>(); + // remember picked cards for better draft choices private final transient List pickedCards = new ArrayList<>(); private final transient List chosenColors = new ArrayList<>(); @@ -125,9 +103,8 @@ public class ComputerPlayer extends PlayerImpl { @Override public boolean chooseMulligan(Game game) { - log.debug("chooseMulligan"); if (hand.size() < 6 - || isTestsMode() // ignore mulligan in tests + || isTestMode() // ignore mulligan in tests || game.getClass().getName().contains("Momir") // ignore mulligan in Momir games ) { return false; @@ -144,1524 +121,253 @@ public class ComputerPlayer extends PlayerImpl { @Override public boolean choose(Outcome outcome, Target target, Ability source, Game game, Map options) { - if (log.isDebugEnabled()) { - log.debug("choose: " + outcome.toString() + ':' + target.toString()); - } - - boolean isAddedSomething = false; // must return true on any changes in targets, so game can ask next choose dialog until finish - - // controller hints: - // - target.getTargetController(), this.getId() -- player that must makes choices (must be same with this.getId) - // - target.getAbilityController(), abilityControllerId -- affected player/controller for all actions/filters - // - affected controller can be different from target controller (another player makes choices for controller) - // sometimes a target selection can be made from a player that does not control the ability - UUID abilityControllerId = playerId; - if (target.getTargetController() != null - && target.getAbilityController() != null) { - abilityControllerId = target.getAbilityController(); - } - UUID sourceId = source != null ? source.getSourceId() : null; - - boolean required = target.isRequired(sourceId, game); - Set possibleTargets = target.possibleTargets(abilityControllerId, source, game); - if (possibleTargets.isEmpty() || target.getTargets().size() >= target.getMinNumberOfTargets()) { - required = false; - } - - UUID randomOpponentId = getRandomOpponent(game); - - if (target.getOriginalTarget() instanceof TargetPlayer) { - return selectPlayer(outcome, target, abilityControllerId, randomOpponentId, game, required); - } - - if (target.getOriginalTarget() instanceof TargetDiscard) { - findPlayables(game); - // discard not playable first - if (!unplayable.isEmpty()) { - for (int i = unplayable.size() - 1; i >= 0; i--) { - UUID targetId = unplayable.values().toArray(new Card[0])[i].getId(); - if (target.canTarget(abilityControllerId, targetId, source, game) && !target.contains(targetId)) { - target.add(targetId, game); - isAddedSomething = true; - if (target.isChosen(game)) { - return true; - } - } - } - } - if (!hand.isEmpty()) { - for (int i = 0; i < hand.size(); i++) { - UUID targetId = hand.toArray(new UUID[0])[i]; - if (target.canTarget(abilityControllerId, targetId, source, game) && !target.contains(targetId)) { - target.add(targetId, game); - isAddedSomething = true; - if (target.isChosen(game)) { - return true; - } - } - } - } - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetControlledPermanent - || target.getOriginalTarget() instanceof TargetSacrifice) { - List targets; - TargetPermanent origTarget = (TargetPermanent) target.getOriginalTarget(); - targets = threats(abilityControllerId, source, origTarget.getFilter(), game, target.getTargets()); - if (!outcome.isGood()) { - Collections.reverse(targets); - } - for (Permanent permanent : targets) { - if (origTarget.canTarget(abilityControllerId, permanent.getId(), source, game, false) && !target.contains(permanent.getId())) { - target.add(permanent.getId(), game); - isAddedSomething = true; - if (target.isChosen(game)) { - return true; - } - } - } - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetPermanent) { - FilterPermanent filter = null; - if (target.getOriginalTarget().getFilter() instanceof FilterPermanent) { - filter = (FilterPermanent) target.getOriginalTarget().getFilter(); - } - if (filter == null) { - throw new IllegalStateException("Unsupported permanent filter in computer's choose method: " - + target.getOriginalTarget().getClass().getCanonicalName()); - } - - List targets; - if (outcome.isCanTargetAll()) { - targets = threats(null, source, filter, game, target.getTargets()); - } else { - if (outcome.isGood()) { - targets = threats(abilityControllerId, source, filter, game, target.getTargets()); - } else { - targets = threats(randomOpponentId, source, filter, game, target.getTargets()); - } - if (targets.isEmpty() && target.isRequired()) { - if (!outcome.isGood()) { - targets = threats(abilityControllerId, source, filter, game, target.getTargets()); - } else { - targets = threats(randomOpponentId, source, filter, game, target.getTargets()); - } - } - } - - for (Permanent permanent : targets) { - if (target.canTarget(abilityControllerId, permanent.getId(), source, game) && !target.contains(permanent.getId())) { - // AI workaround to stop adding more targets in "up to" on bad outcome for itself - if (target.isChosen(game) && target.getMinNumberOfTargets() == target.getTargets().size()) { - if (outcome.isGood() && hasOpponent(permanent.getControllerId(), game)) { - return isAddedSomething; - } - if (!outcome.isGood() && !hasOpponent(permanent.getControllerId(), game)) { - return isAddedSomething; - } - } - // add the target - target.add(permanent.getId(), game); - isAddedSomething = true; - if (target.isChosen(game)) { - return true; - } - } - } - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetCardInHand - || (target.getZone() == Zone.HAND && (target.getOriginalTarget() instanceof TargetCard))) { - List cards = new ArrayList<>(); - for (UUID cardId : target.possibleTargets(this.getId(), source, game)) { - Card card = game.getCard(cardId); - if (card != null) { - cards.add(card); - } - } - while ((outcome.isGood() ? target.getTargets().size() < target.getMaxNumberOfTargets() : !target.isChosen(game)) - && !cards.isEmpty()) { - Card card = selectCard(abilityControllerId, cards, outcome, target, game); - if (card != null) { - cards.remove(card); // selectCard don't remove cards (only on second+ tries) - if (!target.contains(card.getId())) { - target.add(card.getId(), game); // TODO: why it add as much as possible instead go to isChosen check like above? - isAddedSomething = true; - if (target.isChosen(game)) { - //return true; // TODO: why it add as much as possible instead go to isChosen check like above? - } - } - } else { - break; - } - } - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetAnyTarget) { - List targets; - TargetAnyTarget origTarget = (TargetAnyTarget) target.getOriginalTarget(); - if (outcome.isGood()) { - targets = threats(abilityControllerId, source, ((FilterAnyTarget) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); - } else { - targets = threats(randomOpponentId, source, ((FilterAnyTarget) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); - } - for (Permanent permanent : targets) { - if (target.canTarget(abilityControllerId, permanent.getId(), source, game) && !target.contains(permanent.getId())) { - target.add(permanent.getId(), game); - isAddedSomething = true; - if (target.isChosen(game)) { - return true; - } - } - } - if (outcome.isGood()) { - if (target.canTarget(abilityControllerId, getId(), source, game) && !target.contains(getId())) { - target.add(getId(), game); - isAddedSomething = true; - if (target.isChosen(game)) { - return true; - } - } - } else if (target.canTarget(abilityControllerId, randomOpponentId, source, game) && !target.contains(randomOpponentId)) { - target.add(randomOpponentId, game); - isAddedSomething = true; - if (target.isChosen(game)) { - return true; - } - } - if (!required) { - return isAddedSomething; - } - } - - if (target.getOriginalTarget() instanceof TargetPermanentOrPlayer) { - List targets; - TargetPermanentOrPlayer origTarget = (TargetPermanentOrPlayer) target.getOriginalTarget(); - List ownedTargets = threats(abilityControllerId, source, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); - List opponentTargets = threats(randomOpponentId, source, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); - if (outcome.isGood()) { - targets = ownedTargets; - } else { - targets = opponentTargets; - } - for (Permanent permanent : targets) { - if (target.canTarget(abilityControllerId, permanent.getId(), source, game) && !target.contains(permanent.getId())) { - isAddedSomething = true; - target.add(permanent.getId(), game); - return true; - } - } - if (outcome.isGood()) { - if (target.canTarget(abilityControllerId, getId(), source, game) && !target.contains(getId())) { - target.add(getId(), game); - isAddedSomething = true; - if (target.isChosen(game)) { - return true; - } - } - } else if (target.canTarget(abilityControllerId, randomOpponentId, source, game) && !target.contains(randomOpponentId)) { - target.add(randomOpponentId, game); - isAddedSomething = true; - if (target.isChosen(game)) { - return true; - } - } - if (!target.isRequired(sourceId, game) || target.getMinNumberOfTargets() == 0) { - return isAddedSomething; // TODO: need research why it here (between diff type of targets) - } - if (target.canTarget(abilityControllerId, randomOpponentId, source, game) && !target.contains(randomOpponentId)) { - target.add(randomOpponentId, game); - isAddedSomething = true; - if (target.isChosen(game)) { - return true; - } - } - if (target.canTarget(abilityControllerId, getId(), source, game) && !target.contains(getId())) { - target.add(getId(), game); - isAddedSomething = true; - if (target.isChosen(game)) { - return true; - } - } - if (outcome.isGood()) { // no other valid targets so use a permanent - targets = opponentTargets; - } else { - targets = ownedTargets; - } - for (Permanent permanent : targets) { - if (target.canTarget(abilityControllerId, permanent.getId(), source, game) && !target.contains(permanent.getId())) { - target.add(permanent.getId(), game); - isAddedSomething = true; - if (target.isChosen(game)) { - return true; - } - } - } - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetCardInASingleGraveyard) { - List cards = new ArrayList<>(); - for (Player player : game.getPlayers().values()) { - for (Card card : player.getGraveyard().getCards(game)) { - if (target.canTarget(abilityControllerId, card.getId(), source, game)) { - cards.add(card); - } - } - } - - // exile cost workaround: exile is bad, but exile from graveyard in most cases is good (more exiled -- more good things you get, e.g. delve's pay) - boolean isRealGood = outcome.isGood() || outcome == Outcome.Exile; - while ((isRealGood ? target.getTargets().size() < target.getMaxNumberOfTargets() : !target.isChosen(game)) - && !cards.isEmpty()) { - Card card = selectCard(abilityControllerId, cards, outcome, target, game); - if (card != null) { - cards.remove(card); // selectCard don't remove cards (only on second+ tries) - if (!target.contains(card.getId())) { - target.add(card.getId(), game); - isAddedSomething = true; - if (target.isChosen(game)) { - //return true; // TODO: why it add as much as possible instead go to isChosen check like above? - } - } - } else { - break; - } - } - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetCardInGraveyard - || (target.getZone() == Zone.GRAVEYARD && (target.getOriginalTarget() instanceof TargetCard))) { - List cards = new ArrayList<>(); - for (Player player : game.getPlayers().values()) { - for (Card card : player.getGraveyard().getCards(game)) { - if (target.canTarget(abilityControllerId, card.getId(), source, game)) { - cards.add(card); - } - } - } - - // exile cost workaround: exile is bad, but exile from graveyard in most cases is good (more exiled -- more good things you get, e.g. delve's pay) - boolean isRealGood = outcome.isGood() || outcome == Outcome.Exile; - while ((isRealGood ? target.getTargets().size() < target.getMaxNumberOfTargets() : !target.isChosen(game)) - && !cards.isEmpty()) { - Card card = selectCard(abilityControllerId, cards, outcome, target, game); - if (card != null) { - cards.remove(card); // selectCard don't remove cards (only on second+ tries) - if (!target.contains(card.getId())) { - target.add(card.getId(), game); - isAddedSomething = true; - if (target.isChosen(game)) { - //return true; // TODO: why it add as much as possible instead go to isChosen check like above? - } - } - } else { - break; - } - } - - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetCardInYourGraveyard - || target.getOriginalTarget() instanceof TargetCardInASingleGraveyard) { - TargetCard originalTarget = (TargetCard) target.getOriginalTarget(); - List cards = new ArrayList<>(game.getPlayer(abilityControllerId).getGraveyard().getCards(originalTarget.getFilter(), game)); - while (!cards.isEmpty()) { - Card card = selectCard(abilityControllerId, cards, outcome, target, game); - if (card != null && !target.contains(card.getId())) { - target.add(card.getId(), game); - isAddedSomething = true; - if (target.isChosen(game)) { - return true; - } - } - } - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetCardInExile) { - FilterCard filter = null; - if (target.getOriginalTarget().getFilter() instanceof FilterCard) { - filter = (FilterCard) target.getOriginalTarget().getFilter(); - } - if (filter == null) { - throw new IllegalStateException("Unsupported exile target filter in computer's choose method: " - + target.getOriginalTarget().getClass().getCanonicalName()); - } - - List cards = game.getExile().getCards(filter, game); - while (!cards.isEmpty()) { - Card card = selectCard(abilityControllerId, cards, outcome, target, game); - if (card != null && !target.contains(card.getId())) { - target.add(card.getId(), game); - isAddedSomething = true; - if (target.isChosen(game)) { - return true; - } - } - } - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetSource) { - Set targets; - targets = target.possibleTargets(abilityControllerId, source, game); - for (UUID targetId : targets) { - MageObject targetObject = game.getObject(targetId); - if (targetObject != null) { - if (target.canTarget(abilityControllerId, targetObject.getId(), source, game)) { - if (!target.contains(targetObject.getId())) { - target.add(targetObject.getId(), game); - isAddedSomething = true; - if (target.isChosen(game)) { - return true; - } - } - } - } - } - if (!required) { - return isAddedSomething; - } - throw new IllegalStateException("TargetSource wasn't handled in computer's choose method: " + target.getClass().getCanonicalName()); - } - - if (target.getOriginalTarget() instanceof TargetPermanentOrSuspendedCard) { - List cards = new ArrayList<>(new CardsImpl(possibleTargets).getCards(game)); - while (!cards.isEmpty()) { - Card card = selectCard(abilityControllerId, cards, outcome, target, game); - if (card != null) { - cards.remove(card); // selectCard don't remove cards (only on second+ tries) - if (!target.contains(card.getId())) { - target.add(card.getId(), game); - isAddedSomething = true; - if (target.isChosen(game)) { - //return true; // TODO: why it add as much as possible instead go to isChosen check like above? - } - } - } else { - break; - } - } - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetCard - && (target.getZone() == Zone.COMMAND)) { // Hellkite Courser - List cards = new ArrayList<>(); - for (Player player : game.getPlayers().values()) { - for (Card card : game.getCommanderCardsFromCommandZone(player, CommanderCardType.COMMANDER_OR_OATHBREAKER)) { - if (target.canTarget(abilityControllerId, card.getId(), source, game)) { - cards.add(card); - } - } - } - while (!cards.isEmpty()) { - Card card = selectCard(abilityControllerId, cards, outcome, target, game); - if (card != null) { - cards.remove(card); - if (!target.contains(card.getId())) { - target.add(card.getId(), game); - isAddedSomething = true; - if (target.isChosen(game)) { - //return true; // TODO: why it add as much as possible instead go to isChosen check like above? - } - } - } else { - break; - } - } - return isAddedSomething; - } - - throw new IllegalStateException("Target wasn't handled in computer's choose method: " + target.getClass().getCanonicalName()); - } //end of choose method - - @Override - public boolean chooseTarget(Outcome outcome, Target target, Ability source, Game game) { - if (log.isDebugEnabled()) { - log.debug("chooseTarget: " + outcome.toString() + ':' + target.toString()); - } - - boolean isAddedSomething = false; // must return true on any changes in targets, so game can ask next choose dialog until finish - - // target - real target, make all changes and add targets to it - // target.getOriginalTarget() - copy spell effect replaces original target with TargetWithAdditionalFilter - // use originalTarget to get filters and target class info - // source can be null (as example: legendary rule permanent selection) - UUID sourceId = source != null ? source.getSourceId() : null; - - // sometimes a target selection can be made from a player that does not control the ability - UUID abilityControllerId = playerId; - if (target.getAbilityController() != null) { - abilityControllerId = target.getAbilityController(); - } - - boolean required = target.isRequired(sourceId, game); - Set possibleTargets = target.possibleTargets(abilityControllerId, source, game); - if (possibleTargets.isEmpty() || target.getTargets().size() >= target.getMinNumberOfTargets()) { - required = false; - } - - List goodList = new ArrayList<>(); - List badList = new ArrayList<>(); - List allList = new ArrayList<>(); - - UUID randomOpponentId = getRandomOpponent(game); - - if (target.getOriginalTarget() instanceof TargetPlayer) { - return selectPlayerTarget(outcome, target, source, abilityControllerId, randomOpponentId, game, required); - } - - // Angel of Serenity trigger - if (target.getOriginalTarget() instanceof TargetCardInGraveyardBattlefieldOrStack) { - List cards = new ArrayList<>(new CardsImpl(possibleTargets).getCards(game)); - isAddedSomething = false; - for (Card card : cards) { - // check permanents first; they have more intrinsic worth - if (card instanceof Permanent) { - Permanent p = ((Permanent) card); - if (outcome.isGood() - && p.isControlledBy(abilityControllerId)) { - if (target.canTarget(abilityControllerId, p.getId(), source, game) && !target.contains(p.getId())) { - if (target.getTargets().size() >= target.getMaxNumberOfTargets()) { - break; - } - target.addTarget(p.getId(), source, game); - isAddedSomething = true; - if (target.isChoiceCompleted(game)) { - return true; - } - } - } - if (!outcome.isGood() - && !p.isControlledBy(abilityControllerId)) { - if (target.canTarget(abilityControllerId, p.getId(), source, game) && !target.contains(p.getId())) { - if (target.getTargets().size() >= target.getMaxNumberOfTargets()) { - break; - } - target.addTarget(p.getId(), source, game); - isAddedSomething = true; - if (target.isChoiceCompleted(game)) { - return true; - } - } - } - } - // check the graveyards last - if (game.getState().getZone(card.getId()) == Zone.GRAVEYARD) { - if (outcome.isGood() - && card.isOwnedBy(abilityControllerId)) { - if (target.canTarget(abilityControllerId, card.getId(), source, game) && !target.contains(card.getId())) { - if (target.getTargets().size() >= target.getMaxNumberOfTargets()) { - break; - } - target.addTarget(card.getId(), source, game); - isAddedSomething = true; - if (target.isChoiceCompleted(game)) { - return true; - } - } - } - if (!outcome.isGood() - && !card.isOwnedBy(abilityControllerId)) { - if (target.canTarget(abilityControllerId, card.getId(), source, game) && !target.contains(card.getId())) { - if (target.getTargets().size() >= target.getMaxNumberOfTargets()) { - break; - } - target.addTarget(card.getId(), source, game); - isAddedSomething = true; - if (target.isChoiceCompleted(game)) { - return true; - } - } - } - } - } - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetDiscard - || target.getOriginalTarget() instanceof TargetCardInHand) { - isAddedSomething = false; - if (outcome.isGood()) { - // good - Cards cards = new CardsImpl(possibleTargets); - List cardsInHand = new ArrayList<>(cards.getCards(game)); - while (!target.isChosen(game) - && !cardsInHand.isEmpty() - && target.getMaxNumberOfTargets() > target.getTargets().size()) { - Card card = selectBestCardTarget(cardsInHand, Collections.emptyList(), target, source, game); - if (card != null) { - if (target.canTarget(abilityControllerId, card.getId(), source, game) && !target.contains(card.getId())) { - target.addTarget(card.getId(), source, game); - isAddedSomething = true; - cardsInHand.remove(card); - if (target.isChoiceCompleted(game)) { - return true; - } - } - } - } - } else { - // bad - findPlayables(game); - for (Card card : unplayable.values()) { - if (possibleTargets.contains(card.getId()) - && target.canTarget(abilityControllerId, card.getId(), source, game) - && !target.contains(card.getId())) { - target.addTarget(card.getId(), source, game); - isAddedSomething = true; - if (target.isChoiceCompleted(game)) { - return true; - } - } - } - if (!hand.isEmpty()) { - for (Card card : hand.getCards(game)) { - if (possibleTargets.contains(card.getId()) - && target.canTarget(abilityControllerId, card.getId(), source, game) - && !target.contains(card.getId())) { - target.addTarget(card.getId(), source, game); - isAddedSomething = true; - if (target.isChoiceCompleted(game)) { - return true; - } - } - } - } - } - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetControlledPermanent - || target.getOriginalTarget() instanceof TargetSacrifice) { - TargetPermanent origTarget = (TargetPermanent) target.getOriginalTarget(); - List targets; - targets = threats(abilityControllerId, source, origTarget.getFilter(), game, target.getTargets()); - if (!outcome.isGood()) { - Collections.reverse(targets); - } - isAddedSomething = false; - for (Permanent permanent : targets) { - if (target.canTarget(abilityControllerId, permanent.getId(), source, game) && !target.contains(permanent.getId())) { - target.addTarget(permanent.getId(), source, game); - isAddedSomething = true; - if (target.getMinNumberOfTargets() <= target.getTargets().size() && (!outcome.isGood() || target.getMaxNumberOfTargets() <= target.getTargets().size())) { - return true; // TODO: need research - is it good optimization for good/bad effects? - } - } - } - return isAddedSomething; - - } - - // TODO: implemented findBestPlayerTargets - // TODO: add findBest*Targets for all target types - // TODO: Much of this code needs to be re-written to move code into Target.possibleTargets - // A) Having it here makes this function ridiculously long - // B) Each time a new target type is added, people must remember to add it here - if (target.getOriginalTarget() instanceof TargetPermanent) { - FilterPermanent filter = null; - if (target.getOriginalTarget().getFilter() instanceof FilterPermanent) { - filter = (FilterPermanent) target.getOriginalTarget().getFilter(); - } - if (filter == null) { - throw new IllegalStateException("Unsupported permanent filter in computer's chooseTarget method: " - + target.getOriginalTarget().getClass().getCanonicalName()); - } - - findBestPermanentTargets(outcome, abilityControllerId, sourceId, source, filter, - game, target, goodList, badList, allList); - - // use good list all the time and add maximum targets - isAddedSomething = false; - for (Permanent permanent : goodList) { - if (target.canTarget(abilityControllerId, permanent.getId(), source, game) && !target.contains(permanent.getId())) { - if (target.getTargets().size() >= target.getMaxNumberOfTargets()) { - break; - } - target.addTarget(permanent.getId(), source, game); - isAddedSomething = true; - } - } - - // use bad list only on required target and add minimum targets - if (required) { - for (Permanent permanent : badList) { - if (target.canTarget(abilityControllerId, permanent.getId(), source, game) && !target.contains(permanent.getId())) { - if (target.getTargets().size() >= target.getMinNumberOfTargets()) { - break; - } - target.addTarget(permanent.getId(), source, game); - isAddedSomething = true; - } - } - } - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetAnyTarget) { - List targets; - TargetAnyTarget origTarget = ((TargetAnyTarget) target.getOriginalTarget()); - if (outcome.isGood()) { - targets = threats(abilityControllerId, source, ((FilterAnyTarget) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); - } else { - targets = threats(randomOpponentId, source, ((FilterAnyTarget) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); - } - - if (targets.isEmpty()) { - if (outcome.isGood()) { - if (target.canTarget(abilityControllerId, getId(), source, game) && !target.contains(getId())) { - return tryAddTarget(target, getId(), source, game); - } - } else if (target.canTarget(abilityControllerId, randomOpponentId, source, game) && !target.contains(randomOpponentId)) { - return tryAddTarget(target, randomOpponentId, source, game); - } - } - - if (targets.isEmpty() && required) { - targets = game.getBattlefield().getActivePermanents(((FilterAnyTarget) origTarget.getFilter()).getPermanentFilter(), playerId, game); - } - for (Permanent permanent : targets) { - List alreadyTargeted = target.getTargets(); - if (target.canTarget(abilityControllerId, permanent.getId(), source, game) && !target.contains(permanent.getId())) { - if (alreadyTargeted != null && !alreadyTargeted.contains(permanent.getId())) { - tryAddTarget(target, permanent.getId(), source, game); - } - } - } - - if (outcome.isGood()) { - if (target.canTarget(abilityControllerId, getId(), source, game) && !target.contains(getId())) { - return tryAddTarget(target, getId(), source, game); - } - } else if (target.canTarget(abilityControllerId, randomOpponentId, source, game) && !target.contains(randomOpponentId)) { - return tryAddTarget(target, randomOpponentId, source, game); - } - - //if (!target.isRequired()) - return false; - } - - if (target.getOriginalTarget() instanceof TargetPermanentOrPlayer) { - List targets; - TargetPermanentOrPlayer origTarget = ((TargetPermanentOrPlayer) target.getOriginalTarget()); - if (outcome.isGood()) { - targets = threats(abilityControllerId, source, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); - } else { - targets = threats(randomOpponentId, source, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); - } - - if (targets.isEmpty()) { - if (outcome.isGood()) { - if (target.canTarget(abilityControllerId, getId(), source, game) && !target.contains(getId())) { - return tryAddTarget(target, getId(), source, game); - } - } else if (target.canTarget(abilityControllerId, randomOpponentId, source, game) && !target.contains(randomOpponentId)) { - return tryAddTarget(target, randomOpponentId, source, game); - } - } - - if (targets.isEmpty() && target.isRequired(source)) { - targets = game.getBattlefield().getActivePermanents(((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), playerId, game); - } - for (Permanent permanent : targets) { - List alreadyTargeted = target.getTargets(); - if (target.canTarget(abilityControllerId, permanent.getId(), source, game) && !target.contains(permanent.getId())) { - if (alreadyTargeted != null && !alreadyTargeted.contains(permanent.getId())) { - return tryAddTarget(target, permanent.getId(), source, game); - } - } - } - } - - if (target.getOriginalTarget() instanceof TargetPlayerOrPlaneswalker - || target.getOriginalTarget() instanceof TargetOpponentOrPlaneswalker) { - List targets; - TargetPermanentOrPlayer origTarget = ((TargetPermanentOrPlayer) target.getOriginalTarget()); - - // TODO: in multiplayer game there many opponents - if random opponents don't have targets then AI must use next opponent, but it skips - // (e.g. you randomOpponentId must be replaced by List randomOpponents) - // normal cycle (good for you, bad for opponents) - // possible good/bad permanents - if (outcome.isGood()) { - targets = threats(abilityControllerId, source, ((FilterPermanentOrPlayer) target.getFilter()).getPermanentFilter(), game, target.getTargets()); - } else { - targets = threats(randomOpponentId, source, ((FilterPermanentOrPlayer) target.getFilter()).getPermanentFilter(), game, target.getTargets()); - } - - // possible good/bad players - if (targets.isEmpty()) { - if (outcome.isGood()) { - if (target.canTarget(abilityControllerId, getId(), source, game) && !target.contains(getId())) { - return tryAddTarget(target, getId(), source, game); - } - } else if (target.canTarget(abilityControllerId, randomOpponentId, source, game) && !target.contains(randomOpponentId)) { - return tryAddTarget(target, randomOpponentId, source, game); - } - } - - // can't find targets (e.g. effect is bad, but you need take targets from yourself) - if (targets.isEmpty() && required) { - targets = game.getBattlefield().getActivePermanents(origTarget.getFilterPermanent(), playerId, game); - } - - // try target permanent - for (Permanent permanent : targets) { - if (target.canTarget(abilityControllerId, permanent.getId(), source, game) && !target.contains(permanent.getId())) { - return tryAddTarget(target, permanent.getId(), source, game); - } - } - - // try target player as normal - if (outcome.isGood()) { - if (target.canTarget(abilityControllerId, getId(), source, game) && !target.contains(getId())) { - return tryAddTarget(target, getId(), source, game); - } - } else if (target.canTarget(abilityControllerId, randomOpponentId, source, game) && !target.contains(randomOpponentId)) { - return tryAddTarget(target, randomOpponentId, source, game); - } - - // try target player as bad (bad on itself, good on opponent) - for (UUID opponentId : game.getOpponents(getId(), true)) { - if (target.canTarget(abilityControllerId, opponentId, source, game) && !target.contains(opponentId)) { - return tryAddTarget(target, opponentId, source, game); - } - } - if (target.canTarget(abilityControllerId, getId(), source, game) && !target.contains(getId())) { - return tryAddTarget(target, getId(), source, game); - } - - return false; - } - - if (target.getOriginalTarget() instanceof TargetCardInGraveyard) { - List cards = new ArrayList<>(); - for (Player player : game.getPlayers().values()) { - cards.addAll(player.getGraveyard().getCards(game)); - } - Card card = selectCardTarget(abilityControllerId, cards, outcome, target, source, game); - if (card != null && !target.contains(card.getId())) { - return tryAddTarget(target, card.getId(), source, game); - } - //if (!target.isRequired()) - return false; - } - - if (target.getOriginalTarget() instanceof TargetCardInLibrary) { - List cards = new ArrayList<>(game.getPlayer(abilityControllerId).getLibrary().getCards(game)); - Card card = selectCardTarget(abilityControllerId, cards, outcome, target, source, game); - if (card != null && !target.contains(card.getId())) { - return tryAddTarget(target, card.getId(), source, game); - } - return false; - } - - if (target.getOriginalTarget() instanceof TargetCardInYourGraveyard) { - List cards = new ArrayList<>(game.getPlayer(abilityControllerId).getGraveyard().getCards((FilterCard) target.getFilter(), game)); - isAddedSomething = false; - while (!target.isChosen(game) && !cards.isEmpty()) { - Card card = selectCardTarget(abilityControllerId, cards, outcome, target, source, game); - if (card != null) { - cards.remove(card); // selectCard don't remove cards (only on second+ tries) - if (!target.contains(card.getId())) { - target.addTarget(card.getId(), source, game); // TODO: why it add as much as possible instead go to isChosen check like above in choose? - isAddedSomething = true; - if (target.isChoiceCompleted(game)) { - return true; - } - } - } else { - break; - } - } - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetSpell - || target.getOriginalTarget() instanceof TargetStackObject) { - if (!game.getStack().isEmpty()) { - for (StackObject o : game.getStack()) { - if (o instanceof Spell - && !source.getId().equals(o.getStackAbility().getId()) - && target.canTarget(abilityControllerId, o.getStackAbility().getId(), source, game) - && !target.contains(o.getId())) { - return tryAddTarget(target, o.getId(), source, game); - } - } - } - return false; - } - - if (target.getOriginalTarget() instanceof TargetSpellOrPermanent) { - // TODO: Also check if a spell should be selected - TargetSpellOrPermanent origTarget = (TargetSpellOrPermanent) target.getOriginalTarget(); - List targets; - boolean outcomeTargets = true; - if (outcome.isGood()) { - targets = threats(abilityControllerId, source, origTarget.getPermanentFilter(), game, target.getTargets()); - } else { - targets = threats(randomOpponentId, source, origTarget.getPermanentFilter(), game, target.getTargets()); - } - if (targets.isEmpty() && required) { - targets = threats(null, source, origTarget.getPermanentFilter(), game, target.getTargets()); - Collections.reverse(targets); - outcomeTargets = false; - } - for (Permanent permanent : targets) { - if (target.canTarget(abilityControllerId, permanent.getId(), source, game) && !target.contains(permanent.getId())) { - target.addTarget(permanent.getId(), source, game); - if (!outcomeTargets || target.getMaxNumberOfTargets() <= target.getTargets().size()) { - return true; // TODO: need logic research (e.g. select as much as possible on good outcome?) - } - } - } - if (!game.getStack().isEmpty()) { - for (StackObject stackObject : game.getStack()) { - if (stackObject instanceof Spell && source != null && !source.getId().equals(stackObject.getStackAbility().getId())) { - if (target.getFilter().match(stackObject, game) && !target.contains(stackObject.getId())) { - return tryAddTarget(target, stackObject.getId(), source, game); - } - } - } - } - return false; - } - - if (target.getOriginalTarget() instanceof TargetCardInOpponentsGraveyard) { - List cards = new ArrayList<>(); - for (UUID uuid : game.getOpponents(getId(), true)) { - Player player = game.getPlayer(uuid); - if (player != null) { - cards.addAll(player.getGraveyard().getCards(game)); - } - } - isAddedSomething = false; - while (!cards.isEmpty()) { - Card card = selectCardTarget(abilityControllerId, cards, outcome, target, source, game); - if (card != null) { - cards.remove(card); // selectCard don't remove cards (only on second+ tries) - if (!target.contains(card.getId())) { - isAddedSomething = true; - target.addTarget(card.getId(), source, game); - if (target.isChoiceCompleted(game)) { - return true; - } - } - } else { - break; - } - } - //if (!target.isRequired()) - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetDefender) { - List targets = new ArrayList<>(possibleTargets); - isAddedSomething = false; - while (!targets.isEmpty()) { - UUID randomDefender = RandomUtil.randomFromCollection(possibleTargets); - if (randomDefender != null) { - targets.remove(randomDefender); - if (!target.contains(randomDefender)) { - isAddedSomething = true; - target.addTarget(randomDefender, source, game); - if (target.isChoiceCompleted(game)) { - return true; - } - } - } else { - break; - } - } - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetCardInASingleGraveyard) { - List cards = new ArrayList<>(); - for (Player player : game.getPlayers().values()) { - cards.addAll(player.getGraveyard().getCards(game)); - } - isAddedSomething = false; - while (!cards.isEmpty()) { - Card card = selectCardTarget(abilityControllerId, cards, outcome, target, source, game); - if (card != null) { - cards.remove(card); // selectCard don't remove cards (only on second+ tries) - if (!target.contains(card.getId())) { - isAddedSomething = true; - target.addTarget(card.getId(), source, game); - if (target.isChoiceCompleted(game)) { - return true; - } - } - } else { - break; - } - } - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetCardInExile) { - FilterCard filter = null; - if (target.getOriginalTarget().getFilter() instanceof FilterCard) { - filter = (FilterCard) target.getOriginalTarget().getFilter(); - } - if (filter == null) { - throw new IllegalStateException("Unsupported exile target filter in computer's chooseTarget method: " - + target.getOriginalTarget().getClass().getCanonicalName()); - } - - List cards = new ArrayList<>(); - for (UUID uuid : target.possibleTargets(source.getControllerId(), source, game)) { - Card card = game.getCard(uuid); - if (card != null && game.getState().getZone(card.getId()) == Zone.EXILED) { - cards.add(card); - } - } - isAddedSomething = false; - while (!cards.isEmpty()) { - Card card = selectCardTarget(abilityControllerId, cards, outcome, target, source, game); - if (card != null) { - cards.remove(card); // selectCard don't remove cards (only on second+ tries) - if (!target.contains(card.getId())) { - isAddedSomething = true; - target.addTarget(card.getId(), source, game); - if (target.isChoiceCompleted(game)) { - return true; - } - } - } else { - break; - } - } - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetActivatedAbility) { - List stackObjects = new ArrayList<>(); - for (UUID uuid : target.possibleTargets(source.getControllerId(), source, game)) { - StackObject stackObject = game.getStack().getStackObject(uuid); - if (stackObject != null) { - stackObjects.add(stackObject); - } - } - while (!stackObjects.isEmpty()) { - StackObject pick = stackObjects.get(0); - if (pick != null) { - stackObjects.remove(0); - if (!target.contains(pick.getId())) { - isAddedSomething = true; - target.addTarget(pick.getId(), source, game); - if (target.isChoiceCompleted(game)) { - return true; - } - } - } else { - break; - } - } - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetActivatedOrTriggeredAbility) { - List targets = new ArrayList<>(target.possibleTargets(source.getControllerId(), source, game)); - isAddedSomething = false; - while (!targets.isEmpty()) { - UUID id = targets.get(0); - if (id != null) { - targets.remove(0); - if (!target.contains(id)) { - isAddedSomething = true; - target.addTarget(id, source, game); - if (target.isChoiceCompleted(game)) { - return true; - } - } - } else { - break; - } - } - return isAddedSomething; - } - - if (target.getOriginalTarget() instanceof TargetCardInGraveyardBattlefieldOrStack) { - List cards = new ArrayList<>(); - for (Player player : game.getPlayers().values()) { - cards.addAll(player.getGraveyard().getCards(game)); - cards.addAll(game.getBattlefield().getAllActivePermanents(new FilterPermanent(), player.getId(), game)); - } - while (!cards.isEmpty()) { - Card card = selectCardTarget(abilityControllerId, cards, outcome, target, source, game); - if (card != null) { - cards.remove(card); // selectCard don't remove cards (only on second+ tries) - if (!target.contains(card.getId())) { - isAddedSomething = true; - target.addTarget(card.getId(), source, game); - if (target.isChoiceCompleted(game)) { - return true; - } - } - } else { - break; - } - } - } - - if (target.getOriginalTarget() instanceof TargetPermanentOrSuspendedCard) { - List cards = new ArrayList<>(new CardsImpl(possibleTargets).getCards(game)); - isAddedSomething = false; - while (!cards.isEmpty()) { - Card card = selectCardTarget(abilityControllerId, cards, outcome, target, source, game); - if (card != null) { - cards.remove(card); // selectCard don't remove cards (only on second+ tries) - if (!target.contains(card.getId())) { - isAddedSomething = true; - target.addTarget(card.getId(), source, game); - if (target.isChoiceCompleted(game)) { - return true; - } - } - } else { - break; - } - } - return isAddedSomething; - } - - throw new IllegalStateException("Target wasn't handled in computer's chooseTarget method: " + target.getClass().getCanonicalName()); - } //end of chooseTarget method - - protected Card selectCard(UUID abilityControllerId, List cards, Outcome outcome, Target target, Game game) { - return selectCardInner(abilityControllerId, cards, outcome, target, null, game); - } - - protected Card selectCardTarget(UUID abilityControllerId, List cards, Outcome outcome, Target target, Ability targetingSource, Game game) { - return selectCardInner(abilityControllerId, cards, outcome, target, targetingSource, game); + return makeChoice(outcome, target, source, game, null); } /** - * @param targetingSource null on non-target choice like choose and source on targeting choice like chooseTarget + * Default choice logic for any choose dialogs due effect's outcome and possible target priority */ - protected Card selectCardInner(UUID abilityControllerId, List cards, Outcome outcome, Target target, Ability targetingSource, Game game) { - Card card; - while (!cards.isEmpty()) { - if (outcome.isGood()) { - card = selectBestCardInner(cards, Collections.emptyList(), target, targetingSource, game); - } else { - card = selectWorstCardInner(cards, Collections.emptyList(), target, targetingSource, game); - } - if (!target.getTargets().contains(card.getId())) { - if (targetingSource != null) { - if (target.canTarget(abilityControllerId, card.getId(), targetingSource, game)) { - return card; - } - } else { - return card; - } - } - cards.remove(card); // TODO: research parent code - is it depends on original list? Can be bugged + private boolean makeChoice(Outcome outcome, Target target, Ability source, Game game, Cards fromCards) { + // choose itself for starting player all the time + if (target.getMessage(game).equals("Select a starting player")) { + target.add(this.getId(), game); + return true; } - return null; + + // nothing to choose + if (fromCards != null && fromCards.isEmpty()) { + return false; + } + + UUID abilityControllerId = target.getAffectedAbilityControllerId(getId()); + + // nothing to choose, e.g. X=0 + if (target.isChoiceCompleted(abilityControllerId, source, game)) { + return false; + } + + // default logic for any targets + PossibleTargetsSelector possibleTargetsSelector = new PossibleTargetsSelector(outcome, target, abilityControllerId, source, game); + possibleTargetsSelector.findNewTargets(fromCards); + // good targets -- choose as much as possible + for (MageItem item : possibleTargetsSelector.getGoodTargets()) { + target.add(item.getId(), game); + if (target.isChoiceCompleted(abilityControllerId, source, game)) { + return true; + } + } + // bad targets -- choose as low as possible + for (MageItem item : possibleTargetsSelector.getBadTargets()) { + if (target.isChosen(game)) { + break; + } + target.add(item.getId(), game); + } + + return target.isChosen(game) && !target.getTargets().isEmpty(); + } + + /** + * Default choice logic for X or amount values + */ + private int makeChoiceAmount(int min, int max, Game game, Ability source, boolean isManaPay) { + // fast calc on nothing to choose + if (min >= max) { + return min; + } + + // TODO: add good/bad effects support + // TODO: add simple game simulations like declare blocker (need to find only workable payment)? + // TODO: remove random logic or make it more stable (e.g. use same value in same game cycle) + + // protection from too big values + int realMin = min; + int realMax = max; + if (max == Integer.MAX_VALUE) { + realMax = Math.max(realMin, 10); // AI don't need huge values for X, cause can't use infinite combos + } + + int xValue; + if (isManaPay) { + // as X mana payment - due available mana + xValue = Math.max(0, getAvailableManaProducers(game).size() - source.getManaCostsToPay().getUnpaid().manaValue()); + } else { + // as X actions + xValue = RandomUtil.nextInt(realMax + 1); + } + + if (xValue > realMax) { + xValue = realMax; + } + if (xValue < realMin) { + xValue = realMin; + } + + return xValue; + } + + @Override + public boolean chooseTarget(Outcome outcome, Target target, Ability source, Game game) { + return makeChoice(outcome, target, source, game, null); } @Override public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) { - // TODO: make same code for chooseTarget (without filter and target type dependence) - if (log.isDebugEnabled()) { - log.debug("chooseTarget: " + outcome.toString() + ':' + target.toString()); - } - UUID sourceId = source != null ? source.getSourceId() : null; - - // sometimes a target selection can be made from a player that does not control the ability - UUID abilityControllerId = playerId; - if (target.getTargetController() != null - && target.getAbilityController() != null) { - abilityControllerId = target.getAbilityController(); - } - - // process multiple opponents by random - List opponents = new ArrayList<>(game.getOpponents(getId(), true)); - Collections.shuffle(opponents); - - List targets; - - // ONE KILL PRIORITY: player -> planeswalker -> creature - if (outcome == Outcome.Damage) { - // player kill - for (UUID opponentId : opponents) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null - && target.canTarget(abilityControllerId, opponentId, source, game) - && opponent.getLife() <= target.getAmountRemaining()) { - return tryAddTarget(target, opponentId, opponent.getLife(), source, game); - } - } - - // permanents kill - for (UUID opponentId : opponents) { - targets = threats(opponentId, source, StaticFilters.FILTER_PERMANENT_CREATURE_OR_PLANESWALKER_A, game, target.getTargets()); - - // planeswalker kill - for (Permanent permanent : targets) { - if (permanent.isPlaneswalker(game) && target.canTarget(abilityControllerId, permanent.getId(), source, game)) { - int loy = permanent.getCounters(game).getCount(CounterType.LOYALTY); - if (loy <= target.getAmountRemaining()) { - return tryAddTarget(target, permanent.getId(), loy, source, game); - } - } - } - - // creature kill - for (Permanent permanent : targets) { - if (permanent.isCreature(game) && target.canTarget(abilityControllerId, permanent.getId(), source, game)) { - if (permanent.getToughness().getValue() <= target.getAmountRemaining()) { - return tryAddTarget(target, permanent.getId(), permanent.getToughness().getValue(), source, game); - } - } - } - } - } - - // NORMAL PRIORITY: planeswalker -> player -> creature - // own permanents will be checked multiple times... that's ok - for (UUID opponentId : opponents) { - if (outcome.isGood()) { - targets = threats(getId(), source, StaticFilters.FILTER_PERMANENT, game, target.getTargets()); - } else { - targets = threats(opponentId, source, StaticFilters.FILTER_PERMANENT, game, target.getTargets()); - } - - // planeswalkers - for (Permanent permanent : targets) { - if (permanent.isPlaneswalker(game) && target.canTarget(abilityControllerId, permanent.getId(), source, game)) { - return tryAddTarget(target, permanent.getId(), target.getAmountRemaining(), source, game); - } - } - - // players - if (outcome.isGood() && target.canTarget(abilityControllerId, getId(), source, game)) { - return tryAddTarget(target, getId(), target.getAmountRemaining(), source, game); - } - if (!outcome.isGood() && target.canTarget(abilityControllerId, opponentId, source, game)) { - return tryAddTarget(target, opponentId, target.getAmountRemaining(), source, game); - } - - // creature - for (Permanent permanent : targets) { - if (permanent.isCreature(game) && target.canTarget(abilityControllerId, permanent.getId(), source, game)) { - return tryAddTarget(target, permanent.getId(), target.getAmountRemaining(), source, game); - } - } - } - - // BAD PRIORITY, e.g. need bad target on yourself or good target on opponent - // priority: creature (non killable, killable) -> planeswalker -> player - if (!target.isRequired(sourceId, game)) { + // nothing to choose, e.g. X=0 + target.prepareAmount(source, game); + if (target.getAmountRemaining() <= 0) { + return false; + } + if (target.getMaxNumberOfTargets() == 0 && target.getMinNumberOfTargets() == 0) { return false; } - for (UUID opponentId : opponents) { - if (!outcome.isGood()) { - // bad on yourself, uses the weakest targets - targets = threats(getId(), source, StaticFilters.FILTER_PERMANENT, game, target.getTargets(), false); - } else { - targets = threats(opponentId, source, StaticFilters.FILTER_PERMANENT, game, target.getTargets(), false); - } - // creatures - non killable (TODO: add extra skill checks like undestructeable) - for (Permanent permanent : targets) { - if (permanent.isCreature(game) && target.canTarget(abilityControllerId, permanent.getId(), source, game)) { - int safeDamage = Math.min(permanent.getToughness().getValue() - 1, target.getAmountRemaining()); - if (safeDamage > 0) { - return tryAddTarget(target, permanent.getId(), safeDamage, source, game); + UUID abilityControllerId = target.getAffectedAbilityControllerId(getId()); + + // nothing to choose, e.g. X=0 + if (target.isChoiceCompleted(abilityControllerId, source, game)) { + return false; + } + + PossibleTargetsSelector possibleTargetsSelector = new PossibleTargetsSelector(outcome, target, abilityControllerId, source, game); + possibleTargetsSelector.findNewTargets(null); + + // nothing to choose, e.g. no valid targets + if (!possibleTargetsSelector.hasAnyTargets()) { + return false; + } + + // KILL PRIORITY + if (outcome == Outcome.Damage) { + // opponent first + for (MageItem item : possibleTargetsSelector.getGoodTargets()) { + if (target.getAmountRemaining() <= 0) { + break; + } + if (target.contains(item.getId()) || !(item instanceof Player)) { + continue; + } + int leftLife = PossibleTargetsComparator.getLifeForDamage(item, game); + if (leftLife > 0 && leftLife <= target.getAmountRemaining()) { + target.addTarget(item.getId(), leftLife, source, game); + if (target.isChoiceCompleted(abilityControllerId, source, game)) { + return true; } } } - // creatures - all - for (Permanent permanent : targets) { - if (permanent.isCreature(game) && target.canTarget(abilityControllerId, permanent.getId(), source, game)) { - return tryAddTarget(target, permanent.getId(), target.getAmountRemaining(), source, game); + // opponent's creatures second + for (MageItem item : possibleTargetsSelector.getGoodTargets()) { + if (target.getAmountRemaining() <= 0) { + break; + } + if (target.contains(item.getId()) || (item instanceof Player)) { + continue; + } + int leftLife = PossibleTargetsComparator.getLifeForDamage(item, game); + if (leftLife > 0 && leftLife <= target.getAmountRemaining()) { + target.addTarget(item.getId(), leftLife, source, game); + if (target.isChoiceCompleted(abilityControllerId, source, game)) { + return true; + } } } - // planeswalkers - for (Permanent permanent : targets) { - if (permanent.isPlaneswalker(game) && target.canTarget(abilityControllerId, permanent.getId(), source, game)) { - return tryAddTarget(target, permanent.getId(), target.getAmountRemaining(), source, game); + // opponent's any + for (MageItem item : possibleTargetsSelector.getGoodTargets()) { + if (target.getAmountRemaining() <= 0) { + break; + } + if (target.contains(item.getId())) { + continue; + } + target.addTarget(item.getId(), target.getAmountRemaining(), source, game); + if (target.isChoiceCompleted(abilityControllerId, source, game)) { + return true; } } + + // own - non-killable + for (MageItem item : possibleTargetsSelector.getBadTargets()) { + if (target.getAmountRemaining() <= 0) { + break; + } + if (target.contains(item.getId())) { + continue; + } + // stop as fast as possible on bad outcome + if (target.isChosen(game)) { + return !target.getTargets().isEmpty(); + } + int leftLife = PossibleTargetsComparator.getLifeForDamage(item, game); + if (leftLife > 1) { + target.addTarget(item.getId(), Math.min(leftLife - 1, target.getAmountRemaining()), source, game); + if (target.isChoiceCompleted(abilityControllerId, source, game)) { + return true; + } + } + } + + // own - any + for (MageItem item : possibleTargetsSelector.getBadTargets()) { + if (target.getAmountRemaining() <= 0) { + break; + } + if (target.contains(item.getId())) { + continue; + } + // stop as fast as possible on bad outcome + if (target.isChosen(game)) { + return !target.getTargets().isEmpty(); + } + target.addTarget(item.getId(), target.getAmountRemaining(), source, game); + if (target.isChoiceCompleted(abilityControllerId, source, game)) { + return true; + } + } + + return target.isChosen(game); } - // players - for (UUID opponentId : opponents) { - if (target.canTarget(abilityControllerId, getId(), source, game)) { - // on itself - return tryAddTarget(target, getId(), target.getAmountRemaining(), source, game); - } else if (target.canTarget(abilityControllerId, opponentId, source, game)) { - // on opponent - return tryAddTarget(target, opponentId, target.getAmountRemaining(), source, game); + + // non-damage effect like counters - give all to first valid item + for (MageItem item : possibleTargetsSelector.getGoodTargets()) { + if (target.getAmountRemaining() <= 0) { + break; + } + if (target.contains(item.getId())) { + continue; + } + target.addTarget(item.getId(), target.getAmountRemaining(), source, game); + if (target.isChoiceCompleted(abilityControllerId, source, game)) { + return true; + } + } + for (MageItem item : possibleTargetsSelector.getBadTargets()) { + if (target.getAmountRemaining() <= 0) { + break; + } + if (target.contains(item.getId())) { + continue; + } + // stop as fast as possible on bad outcome + if (target.isChosen(game)) { + return !target.getTargets().isEmpty(); + } + target.addTarget(item.getId(), target.getAmountRemaining(), source, game); + if (target.isChoiceCompleted(abilityControllerId, source, game)) { + return true; } } - // it's ok on no targets available - log.warn("No proper AI target handling or can't find permanents/cards to target: " + target.getClass().getName()); - return false; + return target.isChosen(game) && !target.getTargets().isEmpty(); } @Override public boolean priority(Game game) { - game.resumeTimer(getTurnControlledBy()); - boolean result = priorityPlay(game); - game.pauseTimer(getTurnControlledBy()); - return result; - } - - private boolean priorityPlay(Game game) { - UUID opponentId = getRandomOpponent(game); - if (game.isActivePlayer(playerId)) { - if (game.isMainPhase() && game.getStack().isEmpty()) { - playLand(game); - } - switch (game.getTurnStepType()) { - case UPKEEP: - // TODO: is it needs here? Need research (e.g. for better choose in upkeep triggers)? - findPlayables(game); - break; - case DRAW: - break; - case PRECOMBAT_MAIN: - findPlayables(game); - if (!playableAbilities.isEmpty()) { - for (ActivatedAbility ability : playableAbilities) { - if (ability.canActivate(playerId, game).canActivate()) { - if (ability.getEffects().hasOutcome(ability, Outcome.PutLandInPlay)) { - if (this.activateAbility(ability, game)) { - return true; - } - } - if (ability.getEffects().hasOutcome(ability, Outcome.PutCreatureInPlay)) { - if (getOpponentBlockers(opponentId, game).size() <= 1) { - if (this.activateAbility(ability, game)) { - return true; - } - } - } - } - } - } - break; - case DECLARE_BLOCKERS: - findPlayables(game); - playRemoval(game.getCombat().getBlockers(), game); - playDamage(game.getCombat().getBlockers(), game); - break; - case END_COMBAT: - findPlayables(game); - playDamage(game.getCombat().getBlockers(), game); - break; - case POSTCOMBAT_MAIN: - findPlayables(game); - if (game.getStack().isEmpty()) { - if (!playableNonInstant.isEmpty()) { - for (Card card : playableNonInstant) { - if (card.getSpellAbility().canActivate(playerId, game).canActivate()) { - if (this.activateAbility(card.getSpellAbility(), game)) { - return true; - } - } - } - } - if (!playableAbilities.isEmpty()) { - for (ActivatedAbility ability : playableAbilities) { - if (ability.canActivate(playerId, game).canActivate()) { - if (!(ability.getEffects().get(0) instanceof BecomesCreatureSourceEffect)) { - if (this.activateAbility(ability, game)) { - return true; - } - } - } - } - } - } - break; - } - } else { - //respond to opponent events - switch (game.getTurnStepType()) { - case UPKEEP: - findPlayables(game); - break; - case DECLARE_ATTACKERS: - findPlayables(game); - playRemoval(game.getCombat().getAttackers(), game); - playDamage(game.getCombat().getAttackers(), game); - break; - case END_COMBAT: - findPlayables(game); - playDamage(game.getCombat().getAttackers(), game); - break; - } - } + // minimum implementation for do nothing pass(game); - return true; - } // end priorityPlay method - - protected void playLand(Game game) { - log.debug("playLand"); - Set lands = new LinkedHashSet<>(); - for (Card landCard : hand.getCards(new FilterLandCard(), game)) { - // remove lands that can not be played - boolean canPlay = false; - for (Ability ability : landCard.getAbilities(game)) { - if (ability instanceof PlayLandAbility) { - if (!game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, landCard.getId(), ability, playerId), null, game, true)) { - canPlay = true; - } - } - } - if (canPlay) { - lands.add(landCard); - } - } - while (!lands.isEmpty() && this.canPlayLand()) { - if (lands.size() == 1) { - this.playLand(lands.iterator().next(), game, false); - } else { - playALand(lands, game); - } - } - } - - protected void playALand(Set lands, Game game) { - log.debug("playALand"); - //play a land that will allow us to play an unplayable - for (Mana mana : unplayable.keySet()) { - for (Card card : lands) { - for (ActivatedManaAbilityImpl ability : card.getAbilities(game).getActivatedManaAbilities(Zone.BATTLEFIELD)) { - for (Mana netMana : ability.getNetMana(game)) { - if (netMana.enough(mana)) { - this.playLand(card, game, false); - lands.remove(card); - return; - } - } - } - } - } - //play a land that will get us closer to playing an unplayable - for (Mana mana : unplayable.keySet()) { - for (Card card : lands) { - for (ActivatedManaAbilityImpl ability : card.getAbilities(game).getActivatedManaAbilities(Zone.BATTLEFIELD)) { - for (Mana netMana : ability.getNetMana(game)) { - if (mana.contains(netMana)) { - this.playLand(card, game, false); - lands.remove(card); - return; - } - } - } - } - } - //play first available land - this.playLand(lands.iterator().next(), game, false); - lands.remove(lands.iterator().next()); - } - - protected void findPlayables(Game game) { - playableInstant.clear(); - playableNonInstant.clear(); - unplayable.clear(); - playableAbilities.clear(); - Set nonLands = hand.getCards(new FilterNonlandCard(), game); - ManaOptions available = getManaAvailable(game); -// available.addMana(manaPool.getMana()); - - for (Card card : nonLands) { - ManaOptions options = card.getManaCost().getOptions(); - if (!card.getManaCost().getVariableCosts().isEmpty()) { - //don't use variable mana costs unless there is at least 3 extra mana for X - for (Mana option : options) { - option.add(Mana.GenericMana(3)); - } - } - for (Mana mana : options) { - for (Mana avail : available) { - if (mana.enough(avail)) { - SpellAbility ability = card.getSpellAbility(); - GameEvent castEvent = GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, ability.getId(), ability, playerId); - castEvent.setZone(game.getState().getZone(card.getMainCard().getId())); - if (ability != null && ability.canActivate(playerId, game).canActivate() - && !game.getContinuousEffects().preventedByRuleModification(castEvent, ability, game, true)) { - if (card.isInstant(game) - || card.hasAbility(FlashAbility.getInstance(), game)) { - playableInstant.add(card); - } else { - playableNonInstant.add(card); - } - } - } else if (!playableInstant.contains(card) && !playableNonInstant.contains(card)) { - unplayable.put(mana.needed(avail), card); - } - } - } - } - // TODO: wtf?! change to player.getPlayable - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) { - for (ActivatedAbility ability : permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD)) { - if (!ability.isManaActivatedAbility() && ability.canActivate(playerId, game).canActivate()) { - if (ability instanceof EquipAbility && permanent.getAttachedTo() != null) { - continue; - } - ManaOptions abilityOptions = ability.getManaCosts().getOptions(); - if (!ability.getManaCosts().getVariableCosts().isEmpty()) { - //don't use variable mana costs unless there is at least 3 extra mana for X - for (Mana option : abilityOptions) { - option.add(Mana.GenericMana(3)); - } - } - if (abilityOptions.isEmpty()) { - playableAbilities.add(ability); - } else { - for (Mana mana : abilityOptions) { - for (Mana avail : available) { - if (mana.enough(avail)) { - playableAbilities.add(ability); - } - } - } - } - } - } - } - for (Card card : graveyard.getCards(game)) { - for (ActivatedAbility ability : card.getAbilities(game).getActivatedAbilities(Zone.GRAVEYARD)) { - if (ability.canActivate(playerId, game).canActivate()) { - ManaOptions abilityOptions = ability.getManaCosts().getOptions(); - if (abilityOptions.isEmpty()) { - playableAbilities.add(ability); - } else { - for (Mana mana : abilityOptions) { - for (Mana avail : available) { - if (mana.enough(avail)) { - playableAbilities.add(ability); - } - } - } - } - } - } - } - if (log.isDebugEnabled()) { - log.debug("findPlayables: " + playableInstant.toString() + "---" + playableNonInstant.toString() + "---" + playableAbilities.toString()); - } + return false; } @Override @@ -1702,7 +408,7 @@ public class ComputerPlayer extends PlayerImpl { for (Mana mana : manaAbility.getNetMana(game)) { // if mana ability can produce non-useful mana then ignore whole ability here (example: {R} or {G}) // (AI can't choose a good mana option, so make sure any selection option will be compatible with cost) - // AI support {Any} choice by lastUnpaidMana, so it can safly used in includesMana + // AI support {Any} choice by lastUnpaidMana, so it can safety used in includesMana if (!unpaid.getMana().includesMana(mana)) { continue ManaAbility; } else if (mana.getAny() > 0) { @@ -1807,7 +513,7 @@ public class ComputerPlayer extends PlayerImpl { } } } - // then pay colorless hybrid - more restrictive than mono hybrid + // then pay colorless hybrid - more restrictive than monohybrid for (ActivatedManaAbilityImpl manaAbility : getManaAbilitiesSortedByManaCount(mageObject, game)) { if (cost instanceof ColorlessHybridManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { @@ -1825,7 +531,7 @@ public class ComputerPlayer extends PlayerImpl { } } } - // then pay mono hybrid + // then pay monohybrid for (ActivatedManaAbilityImpl manaAbility : getManaAbilitiesSortedByManaCount(mageObject, game)) { if (cost instanceof MonoHybridManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { @@ -1929,7 +635,7 @@ public class ComputerPlayer extends PlayerImpl { ); } - // cost can contains multiple mana types, must check each type (is it possible to pay a cost) + // cost can contain multiple mana types, must check each type (is it possible to pay a cost) for (ManaType checkType : ManaUtil.getManaTypesInCost(checkCost)) { // affected asThoughMana effect must fit a checkType with pool mana ManaType possibleAsThoughPoolManaType = game.getContinuousEffects().asThoughMana(checkType, possiblePoolItem, abilityToPay.getSourceId(), abilityToPay, abilityToPay.getControllerId(), game); @@ -1938,10 +644,10 @@ public class ComputerPlayer extends PlayerImpl { } boolean canPay; if (possibleAsThoughPoolManaType == ManaType.COLORLESS) { - // colorless can be payed by any color from the pool + // colorless can be paid by any color from the pool canPay = possiblePoolItem.count() > 0; } else { - // colored must be payed by specific color from the pool (AsThough already changed it to fit with mana pool) + // colored must be paid by specific color from the pool (AsThough already changed it to fit with mana pool) canPay = possiblePoolItem.get(possibleAsThoughPoolManaType) > 0; } if (canPay) { @@ -1956,23 +662,20 @@ public class ComputerPlayer extends PlayerImpl { Abilities manaAbilities = mageObject.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, playerId, game); if (manaAbilities.size() > 1) { // Sort mana abilities by number of produced manas, to use ability first that produces most mana (maybe also conditional if possible) - Collections.sort(manaAbilities, new Comparator() { - @Override - public int compare(ActivatedManaAbilityImpl a1, ActivatedManaAbilityImpl a2) { - int a1Max = 0; - for (Mana netMana : a1.getNetMana(game)) { - if (netMana.count() > a1Max) { - a1Max = netMana.count(); - } + Collections.sort(manaAbilities, (a1, a2) -> { + int a1Max = 0; + for (Mana netMana : a1.getNetMana(game)) { + if (netMana.count() > a1Max) { + a1Max = netMana.count(); } - int a2Max = 0; - for (Mana netMana : a2.getNetMana(game)) { - if (netMana.count() > a2Max) { - a2Max = netMana.count(); - } - } - return CardUtil.overflowDec(a2Max, a1Max); } + int a2Max = 0; + for (Mana netMana : a2.getNetMana(game)) { + if (netMana.count() > a2Max) { + a2Max = netMana.count(); + } + } + return CardUtil.overflowDec(a2Max, a1Max); }); } return manaAbilities; @@ -1988,7 +691,6 @@ public class ComputerPlayer extends PlayerImpl { * costs that can't be paid by any other producers * * @param unpaid - the amount of unpaid mana costs - * @param game * @return List */ private List getSortedProducers(ManaCosts unpaid, Game game) { @@ -2024,12 +726,7 @@ public class ComputerPlayer extends PlayerImpl { private List sortByValue(Map map) { List> list = new LinkedList<>(map.entrySet()); - Collections.sort(list, new Comparator>() { - @Override - public int compare(Entry o1, Entry o2) { - return (o1.getValue().compareTo(o2.getValue())); - } - }); + Collections.sort(list, Comparator.comparing(Entry::getValue)); List result = new ArrayList<>(); for (Entry entry : list) { result.add(entry.getKey()); @@ -2039,39 +736,7 @@ public class ComputerPlayer extends PlayerImpl { @Override public int announceX(int min, int max, String message, Game game, Ability source, boolean isManaPay) { - // fast calc on nothing to choose - if (min >= max) { - return min; - } - - // TODO: add good/bad effects support - // TODO: add simple game simulations like declare blocker (need to find only workable payment)? - // TODO: remove random logic or make it more stable (e.g. use same value in same game cycle) - - // protection from too big values - int realMin = min; - int realMax = max; - if (max == Integer.MAX_VALUE) { - realMax = Math.max(realMin, 10); // AI don't need huge values for X, cause can't use infinite combos - } - - int xValue; - if (isManaPay) { - // as X mana payment - due available mana - xValue = Math.max(0, getAvailableManaProducers(game).size() - source.getManaCostsToPay().getUnpaid().manaValue()); - } else { - // as X actions - xValue = RandomUtil.nextInt(realMax + 1); - } - - if (xValue > realMax) { - xValue = realMax; - } - if (xValue < realMin) { - xValue = realMin; - } - - return xValue; + return makeChoiceAmount(min, max, game, source, isManaPay); } @Override @@ -2085,12 +750,11 @@ public class ComputerPlayer extends PlayerImpl { @Override public boolean chooseUse(Outcome outcome, String message, Ability source, Game game) { - return this.chooseUse(outcome, message, null, null, null, source, game); + return chooseUse(outcome, message, null, null, null, source, game); } @Override public boolean chooseUse(Outcome outcome, String message, String secondMessage, String trueText, String falseText, Ability source, Game game) { - log.debug("chooseUse: " + outcome.isGood()); // Be proactive! Always use abilities, the evaluation function will decide if it's good or not // Otherwise some abilities won't be used by AI like LoseTargetEffect that has "bad" outcome // but still is good when targets opponent @@ -2099,13 +763,14 @@ public class ComputerPlayer extends PlayerImpl { @Override public boolean choose(Outcome outcome, Choice choice, Game game) { - log.debug("choose 3"); //TODO: improve this // choose creature type // TODO: WTF?! Creature types dialog text can changes, need to replace that code if (choice.getMessage() != null && (choice.getMessage().equals("Choose creature type") || choice.getMessage().equals("Choose a creature type"))) { - chooseCreatureType(outcome, choice, game); + if (chooseCreatureType(outcome, choice, game)) { + return true; + } } // choose the correct color to pay a spell (use last unpaid ability for color hint) @@ -2206,133 +871,38 @@ public class ComputerPlayer extends PlayerImpl { @Override public boolean chooseTarget(Outcome outcome, Cards cards, TargetCard target, Ability source, Game game) { - if (cards == null || cards.isEmpty()) { - return false; - } - - boolean isAddedSomething = false; // must return true on any changes in targets, so game can ask next choose dialog until finish - - // sometimes a target selection can be made from a player that does not control the ability - UUID abilityControllerId = playerId; - if (target.getTargetController() != null - && target.getAbilityController() != null) { - abilityControllerId = target.getAbilityController(); - } - - // we still use playerId when getting cards even if they don't control the search - List cardChoices = new ArrayList<>(cards.getCards(target.getFilter(), playerId, source, game)); - isAddedSomething = false; - while (!cardChoices.isEmpty()) { - Card card = selectCardTarget(abilityControllerId, cardChoices, outcome, target, source, game); - if (card != null) { - cardChoices.remove(card); // selectCard don't remove cards (only on second+ tries) - if (!target.contains(card.getId())) { - target.addTarget(card.getId(), source, game); - isAddedSomething = true; - if (target.isChoiceCompleted(game)) { - return true; - } - } - } else { - break; - } - - // try to fill as much as possible for good effect (see while end) or half for bad (see if) - if (target.isChosen(game) && !outcome.isGood() && target.getTargets().size() > target.getMinNumberOfTargets() + (target.getMaxNumberOfTargets() - target.getMinNumberOfTargets()) / 2) { - return true; - } - } - return isAddedSomething; + return makeChoice(outcome, target, source, game, cards); } @Override public boolean choose(Outcome outcome, Cards cards, TargetCard target, Ability source, Game game) { - log.debug("choose 2"); - if (cards == null || cards.isEmpty()) { - return true; - } - - // sometimes a target selection can be made from a player that does not control the ability - UUID abilityControllerId = playerId; - if (target.getTargetController() != null - && target.getAbilityController() != null) { - abilityControllerId = target.getAbilityController(); - } - - List cardChoices = new ArrayList<>(cards.getCards(target.getFilter(), abilityControllerId, source, game)); - do { - Card card = selectCard(abilityControllerId, cardChoices, outcome, target, game); - if (card != null) { - target.add(card.getId(), game); - cardChoices.remove(card); // selectCard don't remove cards (only on second+ tries) - } else { - // We don't have any valid target to choose so stop choosing - return target.isChosen(game); - } - // try to fill as much as possible for good effect (see while end) or half for bad (see if) - if (outcome == Outcome.Neutral && target.getTargets().size() > target.getMinNumberOfTargets() + (target.getMaxNumberOfTargets() - target.getMinNumberOfTargets()) / 2) { - return target.isChosen(game); - } - } while (target.getTargets().size() < target.getMaxNumberOfTargets()); - return true; + return makeChoice(outcome, target, source, game, cards); } @Override public boolean choosePile(Outcome outcome, String message, List pile1, List pile2, Game game) { //TODO: improve this - return true; + return true; // select left pile all the time } @Override public void selectAttackers(Game game, UUID attackingPlayerId) { - log.debug("selectAttackers"); - UUID opponentId = game.getCombat().getDefenders().iterator().next(); - Attackers attackers = getPotentialAttackers(game); - List blockers = getOpponentBlockers(opponentId, game); - List actualAttackers = new ArrayList<>(); - if (blockers.isEmpty()) { - actualAttackers = attackers.getAttackers(); - } else if (attackers.size() - blockers.size() >= game.getPlayer(opponentId).getLife()) { - actualAttackers = attackers.getAttackers(); - } else { - CombatSimulator combat = simulateAttack(attackers, blockers, opponentId, game); - if (combat.rating > 2) { - for (CombatGroupSimulator group : combat.groups) { - this.declareAttacker(group.attackers.get(0).id, group.defenderId, game, false); - } - } - } - for (Permanent attacker : actualAttackers) { - this.declareAttacker(attacker.getId(), opponentId, game, false); - } + // do nothing, parent class must implement it } @Override public void selectBlockers(Ability source, Game game, UUID defendingPlayerId) { - log.debug("selectBlockers"); - - List blockers = getAvailableBlockers(game); - - CombatSimulator sim = simulateBlock(CombatSimulator.load(game), blockers, game); - - List groups = game.getCombat().getGroups(); - for (int i = 0; i < groups.size(); i++) { - for (CreatureSimulator creature : sim.groups.get(i).blockers) { - groups.get(i).addBlocker(creature.id, playerId, game); - } - } + // do nothing, parent class must implement it } @Override public int chooseReplacementEffect(Map effectsMap, Map objectsMap, Game game) { - log.debug("chooseReplacementEffect"); //TODO: implement this - return 0; + return 0; // select first effect all the time } @Override public Mode chooseMode(Modes modes, Ability source, Game game) { - log.debug("chooseMode"); if (modes.getMode() != null && modes.getMaxModes(game, source) == modes.getSelectedModes().size()) { // mode was already set by the AI return modes.getMode(); @@ -2341,52 +911,30 @@ public class ComputerPlayer extends PlayerImpl { // spell modes simulated by AI, see addModeOptions // trigger modes chooses here // TODO: add AI support to select best modes, current code uses first valid mode - AvailableMode: - for (Mode mode : modes.getAvailableModes(source, game)) { - for (UUID selectedModeId : modes.getSelectedModes()) { - Mode selectedMode = modes.get(selectedModeId); - if (selectedMode.getId().equals(mode.getId())) { - continue AvailableMode; - } - } - if (mode.getTargets().canChoose(source.getControllerId(), source, game)) { // and where targets are available - return mode; - } - } - return null; + return modes.getAvailableModes(source, game).stream() + .filter(mode -> !modes.getSelectedModes().contains(mode.getId())) + .filter(mode -> mode.getTargets().canChoose(source.getControllerId(), source, game)) + .findFirst() + .orElse(null); } @Override public TriggeredAbility chooseTriggeredAbility(List abilities, Game game) { - log.debug("chooseTriggeredAbility: " + abilities.toString()); //TODO: improve this if (!abilities.isEmpty()) { - return abilities.get(0); + return abilities.get(0); // select first trigger all the time } return null; } @Override - // TODO: add AI support with outcome and replace random with min/max public int getAmount(int min, int max, String message, Ability source, Game game) { - log.debug("getAmount"); - - // fast calc on nothing to choose - if (min >= max) { - return min; - } - - if (min == 0) { - return RandomUtil.nextInt(CardUtil.overflowInc(max, 1)); - } - return min; + return makeChoiceAmount(min, max, game, source, false); } @Override public List getMultiAmountWithIndividualConstraints(Outcome outcome, List messages, int totalMin, int totalMax, MultiAmountType type, Game game) { - log.debug("getMultiAmount"); - int needCount = messages.size(); List defaultList = MultiAmountType.prepareDefaultValues(messages, totalMin, totalMax); if (needCount == 0) { @@ -2401,7 +949,7 @@ public class ComputerPlayer extends PlayerImpl { } // GOOD effect - // values must be stable, so AI must able to simulate it and choose correct actions + // values must be stable, so AI must be able to simulate it and choose correct actions // fill max values as much as possible return MultiAmountType.prepareMaxValues(messages, totalMin, totalMax); } @@ -2413,8 +961,8 @@ public class ComputerPlayer extends PlayerImpl { @Override public void sideboard(Match match, Deck deck) { - //TODO: improve this - match.submitDeck(playerId, deck); + // TODO: improve this + match.submitDeck(playerId, deck); // do not change a deck } private static void addBasicLands(Deck deck, String landName, int number) { @@ -2422,7 +970,7 @@ public class ComputerPlayer extends PlayerImpl { CardCriteria criteria = new CardCriteria(); if (!landSets.isEmpty()) { - criteria.setCodes(landSets.toArray(new String[landSets.size()])); + criteria.setCodes(landSets.toArray(new String[0])); } criteria.rarities(Rarity.LAND).name(landName); List cards = CardRepository.instance.findCards(criteria); @@ -2478,13 +1026,10 @@ public class ComputerPlayer extends PlayerImpl { // sort card pool by top score List sortedCards = new ArrayList<>(cardPool); - Collections.sort(sortedCards, new Comparator() { - @Override - public int compare(Card o1, Card o2) { - Integer score1 = RateCard.rateCard(o1, colors); - Integer score2 = RateCard.rateCard(o2, colors); - return score2.compareTo(score1); - } + Collections.sort(sortedCards, (o1, o2) -> { + Integer score1 = RateCard.rateCard(o1, colors); + Integer score2 = RateCard.rateCard(o2, colors); + return score2.compareTo(score1); }); // get top cards @@ -2576,28 +1121,11 @@ public class ComputerPlayer extends PlayerImpl { tournament.submitDeck(playerId, deck); } - public Card selectBestCard(List cards, List chosenColors) { - return selectBestCardInner(cards, chosenColors, null, null, null); - } - - public Card selectBestCardTarget(List cards, List chosenColors, Target target, Ability targetingSource, Game game) { - return selectBestCardInner(cards, chosenColors, target, targetingSource, game); - } - - /** - * @param targetingSource null on non-target choice like choose and source on targeting choice like chooseTarget - */ - public Card selectBestCardInner(List cards, List chosenColors, Target target, Ability targetingSource, Game game) { + public Card makePickCard(List cards, List chosenColors) { if (cards.isEmpty()) { return null; } - // sometimes a target selection can be made from a player that does not control the ability - UUID abilityControllerId = playerId; - if (target != null && target.getAbilityController() != null) { - abilityControllerId = target.getAbilityController(); - } - Card bestCard = null; int maxScore = 0; for (Card card : cards) { @@ -2606,13 +1134,7 @@ public class ComputerPlayer extends PlayerImpl { if (bestCard == null) { // we need any card to prevent NPE in callers betterCard = true; } else if (score > maxScore) { // we need better card - if (target != null && targetingSource != null && game != null) { - // but also check it can be targeted - betterCard = target.canTarget(abilityControllerId, card.getId(), targetingSource, game); - } else { - // target object wasn't provided, so accepting it anyway - betterCard = true; - } + betterCard = true; } // is it better than previous one? if (betterCard) { @@ -2623,69 +1145,23 @@ public class ComputerPlayer extends PlayerImpl { return bestCard; } - public Card selectWorstCard(List cards, List chosenColors) { - return selectWorstCardInner(cards, chosenColors, null, null, null); - } - - public Card selectWorstCardTarget(List cards, List chosenColors, Target target, Ability targetingSource, Game game) { - return selectWorstCardInner(cards, chosenColors, target, targetingSource, game); - } - - /** - * @param targetingSource null on non-target choice like choose and source on targeting choice like chooseTarget - */ - public Card selectWorstCardInner(List cards, List chosenColors, Target target, Ability targetingSource, Game game) { - if (cards.isEmpty()) { - return null; - } - - // sometimes a target selection can be made from a player that does not control the ability - UUID abilityControllerId = playerId; - if (target != null && target.getAbilityController() != null) { - abilityControllerId = target.getAbilityController(); - } - - Card worstCard = null; - int minScore = Integer.MAX_VALUE; - for (Card card : cards) { - int score = RateCard.rateCard(card, chosenColors); - boolean worseCard = false; - if (worstCard == null) { // we need any card to prevent NPE in callers - worseCard = true; - } else if (score < minScore) { // we need worse card - if (target != null && targetingSource != null && game != null) { - // but also check it can be targeted - worseCard = target.canTarget(abilityControllerId, card.getId(), targetingSource, game); - } else { - // target object wasn't provided, so accepting it anyway - worseCard = true; - } - } - // is it worse than previous one? - if (worseCard) { - minScore = score; - worstCard = card; - } - } - return worstCard; - } - @Override public void pickCard(List cards, Deck deck, Draft draft) { + // method used by DRAFT bot too if (cards.isEmpty()) { throw new IllegalArgumentException("No cards to pick from."); } try { - Card bestCard = selectBestCard(cards, chosenColors); + Card bestCard = makePickCard(cards, chosenColors); int maxScore = RateCard.rateCard(bestCard, chosenColors); int pickedCardRate = RateCard.getBaseCardScore(bestCard); if (pickedCardRate <= 30) { // if card is bad // try to counter pick without any color restriction - Card counterPick = selectBestCard(cards, Collections.emptyList()); + Card counterPick = makePickCard(cards, Collections.emptyList()); int counterPickScore = RateCard.getBaseCardScore(counterPick); - // card is really good + // card is perfect // take it! if (counterPickScore >= 80) { bestCard = counterPick; @@ -2708,19 +1184,15 @@ public class ComputerPlayer extends PlayerImpl { colors += symbol.toString(); } } - log.debug("[DEBUG] AI picked: " + bestCard.getName() + ", score=" + maxScore + ", deck colors=" + colors); draft.addPick(playerId, bestCard.getId(), null); } catch (Exception e) { - log.debug("Exception during AI pick card for draft playerId= " + getId()); + logger.error("Error during AI pick card for draft playerId = " + getId(), e); draft.addPick(playerId, cards.get(0).getId(), null); } } /** * Remember picked card with its score. - * - * @param card - * @param score */ protected void rememberPick(Card card, int score) { pickedCards.add(new PickedCard(card, score)); @@ -2730,22 +1202,17 @@ public class ComputerPlayer extends PlayerImpl { * Choose 2 deck colors for draft: 1. there should be at least 3 cards in * card pool 2. at least 2 cards should have different colors 3. get card * colors as chosen starting from most rated card - * - * @return */ protected List chooseDeckColorsIfPossible() { if (pickedCards.size() > 2) { // sort by score and color mana symbol count in descending order - pickedCards.sort(new Comparator() { - @Override - public int compare(PickedCard o1, PickedCard o2) { - if (o1.score.equals(o2.score)) { - Integer i1 = RateCard.getColorManaCount(o1.card); - Integer i2 = RateCard.getColorManaCount(o2.card); - return i2.compareTo(i1); - } - return o2.score.compareTo(o1.score); + pickedCards.sort((o1, o2) -> { + if (o1.score.equals(o2.score)) { + Integer i1 = RateCard.getColorManaCount(o1.card); + Integer i2 = RateCard.getColorManaCount(o2.card); + return i2.compareTo(i1); } + return o2.score.compareTo(o1.score); }); Set chosenSymbols = new HashSet<>(); for (PickedCard picked : pickedCards) { @@ -2793,105 +1260,6 @@ public class ComputerPlayer extends PlayerImpl { } } - protected Attackers getPotentialAttackers(Game game) { - log.debug("getAvailableAttackers"); - Attackers attackers = new Attackers(); - List creatures = super.getAvailableAttackers(game); - for (Permanent creature : creatures) { - int potential = combatPotential(creature, game); - if (potential > 0 && creature.getPower().getValue() > 0) { - List l = attackers.get(potential); - if (l == null) { - attackers.put(potential, l = new ArrayList<>()); - } - l.add(creature); - } - } - return attackers; - } - - protected int combatPotential(Permanent creature, Game game) { - log.debug("combatPotential"); - if (!creature.canAttack(null, game)) { - return 0; - } - int potential = creature.getPower().getValue(); - potential += creature.getAbilities().getEvasionAbilities().size(); - potential += creature.getAbilities().getProtectionAbilities().size(); - potential += creature.getAbilities().containsKey(FirstStrikeAbility.getInstance().getId()) ? 1 : 0; - potential += creature.getAbilities().containsKey(DoubleStrikeAbility.getInstance().getId()) ? 2 : 0; - potential += creature.getAbilities().containsKey(TrampleAbility.getInstance().getId()) ? 1 : 0; - return potential; - } - - protected List getOpponentBlockers(UUID opponentId, Game game) { - FilterCreatureForCombatBlock blockFilter = new FilterCreatureForCombatBlock(); - return game.getBattlefield().getAllActivePermanents(blockFilter, opponentId, game); - } - - protected CombatSimulator simulateAttack(Attackers attackers, List blockers, UUID opponentId, Game game) { - log.debug("simulateAttack"); - List attackersList = attackers.getAttackers(); - CombatSimulator best = new CombatSimulator(); - int bestResult = 0; - //use binary digits to calculate powerset of attackers - int powerElements = (int) Math.pow(2, attackersList.size()); - for (int i = 1; i < powerElements; i++) { - String binary = Integer.toBinaryString(i); - while (binary.length() < attackersList.size()) { - binary = '0' + binary; - } - List trialAttackers = new ArrayList<>(); - for (int j = 0; j < attackersList.size(); j++) { - if (binary.charAt(j) == '1') { - trialAttackers.add(attackersList.get(j)); - } - } - CombatSimulator combat = new CombatSimulator(); - for (Permanent permanent : trialAttackers) { - combat.groups.add(new CombatGroupSimulator(opponentId, Arrays.asList(permanent.getId()), new ArrayList(), game)); - } - CombatSimulator test = simulateBlock(combat, blockers, game); - if (test.evaluate() > bestResult) { - best = test; - bestResult = test.evaluate(); - } - } - - return best; - } - - protected CombatSimulator simulateBlock(CombatSimulator combat, List blockers, Game game) { - log.debug("simulateBlock"); - - TreeNode simulations; - - simulations = new TreeNode<>(combat); - addBlockSimulations(blockers, simulations, game); - combat.simulate(game); - - return getWorstSimulation(simulations); - - } - - protected void addBlockSimulations(List blockers, TreeNode node, Game game) { - int numGroups = node.getData().groups.size(); - Copier copier = new Copier<>(); - for (Permanent blocker : blockers) { - List subList = remove(blockers, blocker); - for (int i = 0; i < numGroups; i++) { - if (node.getData().groups.get(i).canBlock(blocker, game)) { - CombatSimulator combat = copier.copy(node.getData()); - combat.groups.get(i).blockers.add(new CreatureSimulator(blocker)); - TreeNode child = new TreeNode<>(combat); - node.addChild(child); - addBlockSimulations(subList, child, game); - combat.simulate(game); - } - } - } - } - protected List remove(List source, Permanent element) { List newList = new ArrayList<>(); for (Permanent permanent : source) { @@ -2902,172 +1270,13 @@ public class ComputerPlayer extends PlayerImpl { return newList; } - protected CombatSimulator getBestSimulation(TreeNode simulations) { - CombatSimulator best = simulations.getData(); - int bestResult = best.evaluate(); - for (TreeNode node : simulations.getChildren()) { - CombatSimulator bestSub = getBestSimulation(node); - if (bestSub.evaluate() > bestResult) { - best = node.getData(); - bestResult = best.evaluate(); - } - } - return best; - } - - protected CombatSimulator getWorstSimulation(TreeNode simulations) { - CombatSimulator worst = simulations.getData(); - int worstResult = worst.evaluate(); - for (TreeNode node : simulations.getChildren()) { - CombatSimulator worstSub = getWorstSimulation(node); - if (worstSub.evaluate() < worstResult) { - worst = node.getData(); - worstResult = worst.evaluate(); - } - } - return worst; - } - - protected void findBestPermanentTargets(Outcome outcome, UUID abilityControllerId, UUID sourceId, Ability source, FilterPermanent filter, Game game, Target target, - List goodList, List badList, List allList) { - // searching for most valuable/powerfull permanents - goodList.clear(); - badList.clear(); - allList.clear(); - List usedTargets = target.getTargets(); - - // search all - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, abilityControllerId, source, game)) { - if (usedTargets.contains(permanent.getId())) { - continue; - } - - if (outcome.isGood()) { - // good effect - if (permanent.isControlledBy(abilityControllerId)) { - goodList.add(permanent); - } else { - badList.add(permanent); - } - } else { - // bad effect - if (permanent.isControlledBy(abilityControllerId)) { - badList.add(permanent); - } else { - goodList.add(permanent); - } - } - } - - // sort from tiny to big (more valuable) - PermanentComparator comparator = new PermanentComparator(game); - goodList.sort(comparator); - badList.sort(comparator); - - // most valueable goes first in good list - Collections.reverse(goodList); - // most weakest goes first in bad list (no need to reverse) - //Collections.reverse(badList); - - allList.addAll(goodList); - allList.addAll(badList); - - // "can target all mode" don't need your/opponent lists -- all targets goes with same value - if (outcome.isCanTargetAll()) { - allList.sort(comparator); // bad sort - if (outcome.isGood()) { - Collections.reverse(allList); // good sort - } - goodList.clear(); - goodList.addAll(allList); - badList.clear(); - badList.addAll(allList); - } - } - - protected List threats(UUID playerId, Ability source, FilterPermanent filter, Game game, List targets) { - return threats(playerId, source, filter, game, targets, true); - } - - protected List threats(UUID playerId, Ability source, FilterPermanent filter, Game game, List targets, boolean mostValueableGoFirst) { - // most valuable/powerfull permanents goes at first - List threats; - if (playerId == null) { - threats = game.getBattlefield().getActivePermanents(filter, this.getId(), source, game); // all permanents within the range of the player - } else { - FilterPermanent filterCopy = filter.copy(); - filterCopy.add(new ControllerIdPredicate(playerId)); - threats = game.getBattlefield().getActivePermanents(filter, this.getId(), source, game); - } - Iterator it = threats.iterator(); - while (it.hasNext()) { // remove permanents already targeted - Permanent test = it.next(); - if (targets.contains(test.getId()) || (playerId != null && !test.getControllerId().equals(playerId))) { - it.remove(); - } - } - Collections.sort(threats, new PermanentComparator(game)); - if (mostValueableGoFirst) { - Collections.reverse(threats); - } - return threats; - } - protected void logList(String message, List list) { StringBuilder sb = new StringBuilder(); sb.append(message).append(": "); for (MageObject object : list) { sb.append(object.getName()).append(','); } - log.info(sb.toString()); - } - - protected void logAbilityList(String message, List list) { - StringBuilder sb = new StringBuilder(); - sb.append(message).append(": "); - for (Ability ability : list) { - sb.append(ability.getRule()).append(','); - } - log.debug(sb.toString()); - } - - private void playRemoval(Set creatures, Game game) { - for (UUID creatureId : creatures) { - for (Card card : this.playableInstant) { - if (card.getSpellAbility().canActivate(playerId, game).canActivate()) { - for (Effect effect : card.getSpellAbility().getEffects()) { - if (effect.getOutcome() == Outcome.DestroyPermanent || effect.getOutcome() == Outcome.ReturnToHand) { - if (card.getSpellAbility().getTargets().get(0).canTarget(creatureId, card.getSpellAbility(), game)) { - if (this.activateAbility(card.getSpellAbility(), game)) { - return; - } - } - } - } - } - } - } - } - - private void playDamage(Set creatures, Game game) { - for (UUID creatureId : creatures) { - Permanent creature = game.getPermanent(creatureId); - for (Card card : this.playableInstant) { - if (card.getSpellAbility().canActivate(playerId, game).canActivate()) { - for (Effect effect : card.getSpellAbility().getEffects()) { - if (effect instanceof DamageTargetEffect) { - if (card.getSpellAbility().getTargets().get(0).canTarget(creatureId, card.getSpellAbility(), game)) { - if (((DamageTargetEffect) effect).getAmount() > (creature.getPower().getValue() - creature.getDamage())) { - if (this.activateAbility(card.getSpellAbility(), game)) { - return; - } - } - } - } - } - } - } - } + logger.info(sb.toString()); } @Override @@ -3080,151 +1289,13 @@ public class ComputerPlayer extends PlayerImpl { return new ComputerPlayer(this); } - @Deprecated // TODO: replace by standard while cycle with cards.isempty and addTarget - private boolean tryAddTarget(Target target, UUID id, Ability source, Game game) { - // workaround to to check successfull targets add - int before = target.getTargets().size(); - target.addTarget(id, source, game); - int after = target.getTargets().size(); - return before != after; - } - - private boolean tryAddTarget(Target target, UUID id, int amount, Ability source, Game game) { - // workaround to to check successfull targets add - int before = target.getTargets().size(); - target.addTarget(id, amount, source, game); - int after = target.getTargets().size(); - return before != after; - } - - private boolean selectPlayer(Outcome outcome, Target target, UUID abilityControllerId, UUID randomOpponentId, Game game, boolean required) { - return selectPlayerInner(outcome, target, null, abilityControllerId, randomOpponentId, game, required); - } - - private boolean selectPlayerTarget(Outcome outcome, Target target, Ability targetingSource, UUID abilityControllerId, UUID randomOpponentId, Game game, boolean required) { - return selectPlayerInner(outcome, target, targetingSource, abilityControllerId, randomOpponentId, game, required); - } - - /** - * Sets a possible target player. Depends on bad/good outcome - *

- * Return false on no more valid targets, e.g. can stop choose dialog - * - * @param targetingSource null on non-target choice like choose and source on targeting choice like chooseTarget - */ - private boolean selectPlayerInner(Outcome outcome, Target target, Ability targetingSource, UUID abilityControllerId, UUID randomOpponentId, Game game, boolean required) { - Outcome affectedOutcome; - if (abilityControllerId == this.playerId) { - // selects for itself - affectedOutcome = outcome; - } else { - // selects for another player - affectedOutcome = Outcome.inverse(outcome); - } - - if (target.getOriginalTarget() instanceof TargetOpponent) { - if (targetingSource == null) { - if (target.canTarget(randomOpponentId, game)) { - if (!target.contains(randomOpponentId)) { - target.add(randomOpponentId, game); - return true; - } - } - } else if (target.canTarget(abilityControllerId, randomOpponentId, targetingSource, game)) { - if (!target.contains(randomOpponentId)) { - target.addTarget(randomOpponentId, targetingSource, game); - return true; - } - } - for (UUID possibleOpponentId : game.getOpponents(getId(), true)) { - if (targetingSource == null) { - if (target.canTarget(possibleOpponentId, game)) { - if (!target.contains(possibleOpponentId)) { - target.add(possibleOpponentId, game); - return true; - } - } - } else if (target.canTarget(abilityControllerId, possibleOpponentId, targetingSource, game)) { - if (!target.contains(possibleOpponentId)) { - target.addTarget(possibleOpponentId, targetingSource, game); - return true; - } - } - } - return false; - } - - UUID sourceId = targetingSource != null ? targetingSource.getSourceId() : null; - if (target.getOriginalTarget() instanceof TargetPlayer) { - if (affectedOutcome.isGood()) { - if (targetingSource == null) { - // good - if (target.canTarget(getId(), game) && !target.contains(getId())) { - target.add(getId(), game); - return true; - } - if (target.isRequired(sourceId, game)) { - if (target.canTarget(randomOpponentId, game) && !target.contains(randomOpponentId)) { - target.add(randomOpponentId, game); - return true; - } - } - } else { - // good - if (target.canTarget(abilityControllerId, getId(), targetingSource, game) && !target.contains(getId())) { - target.addTarget(getId(), targetingSource, game); - return true; - } - if (target.isRequired(sourceId, game)) { - if (target.canTarget(abilityControllerId, randomOpponentId, targetingSource, game) && !target.contains(randomOpponentId)) { - target.addTarget(randomOpponentId, targetingSource, game); - return true; - } - } - } - } else if (targetingSource == null) { - // bad - if (target.canTarget(randomOpponentId, game) && !target.contains(randomOpponentId)) { - target.add(randomOpponentId, game); - return true; - } - if (target.isRequired(sourceId, game)) { - if (target.canTarget(getId(), game) && !target.contains(getId())) { - target.add(getId(), game); - return true; - } - } - } else { - // bad - if (target.canTarget(abilityControllerId, randomOpponentId, targetingSource, game) && !target.contains(randomOpponentId)) { - target.addTarget(randomOpponentId, targetingSource, game); - return true; - } - if (required) { - if (target.canTarget(abilityControllerId, getId(), targetingSource, game) && !target.contains(getId())) { - target.addTarget(getId(), targetingSource, game); - return true; - } - } - } - return false; - } - - return false; - } - - /** - * Returns an opponent by random - */ - @Deprecated // TODO: rework all usages and replace to all possible opponents instead single - private UUID getRandomOpponent(Game game) { - return RandomUtil.randomFromCollection(game.getOpponents(getId(), true)); - } - @Override public SpellAbility chooseAbilityForCast(Card card, Game game, boolean noMana) { - Map useable = PlayerImpl.getCastableSpellAbilities(game, this.getId(), card, game.getState().getZone(card.getId()), noMana); - return useable.values().stream().findFirst().orElse(null); + Map usable = PlayerImpl.getCastableSpellAbilities(game, this.getId(), card, game.getState().getZone(card.getId()), noMana); + return usable.values().stream() + .filter(a -> a.getTargets().canChoose(getId(), a, game)) + .findFirst() + .orElse(null); } @Override @@ -3262,12 +1333,4 @@ public class ComputerPlayer extends PlayerImpl { // all human players converted to computer and analyse this.human = false; } - - public long getLastThinkTime() { - return lastThinkTime; - } - - public void setLastThinkTime(long lastThinkTime) { - this.lastThinkTime = lastThinkTime; - } -} +} \ No newline at end of file diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/PossibleTargetsComparator.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/PossibleTargetsComparator.java new file mode 100644 index 00000000000..7f4f199b5ab --- /dev/null +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/PossibleTargetsComparator.java @@ -0,0 +1,152 @@ +package mage.player.ai; + +import mage.MageItem; +import mage.MageObject; +import mage.cards.Card; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.player.ai.score.GameStateEvaluator2; +import mage.players.PlayableObjectsList; +import mage.players.Player; + +import java.util.Comparator; +import java.util.UUID; + +/** + * AI related code - compare and sort possible targets due target/effect type + * + * @author JayDi85 + */ +public class PossibleTargetsComparator { + + UUID abilityControllerId; + Game game; + PlayableObjectsList playableItems = new PlayableObjectsList(); + + public PossibleTargetsComparator(UUID abilityControllerId, Game game) { + this.abilityControllerId = abilityControllerId; + this.game = game; + } + + public void findPlayableItems() { + this.playableItems = this.game.getPlayer(this.abilityControllerId).getPlayableObjects(this.game, Zone.ALL); + } + + private int getScoreFromBattlefield(MageItem item) { + if (item instanceof Permanent) { + // use battlefield score instead simple life + return GameStateEvaluator2.evaluatePermanent((Permanent) item, game, false); + } else { + return getScoreFromLife(item); + } + } + + private String getName(MageItem item) { + if (item instanceof Player) { + return ((Player) item).getName(); + } else if (item instanceof MageObject) { + return ((MageObject) item).getName(); + } else { + return "unknown"; + } + } + + public static int getLifeForDamage(MageItem item, Game game) { + int res = 0; + if (item instanceof Player) { + res = ((Player) item).getLife(); + } else if (item instanceof Card) { + Card card = (Card) item; + if (card.isPlaneswalker(game)) { + res = card.getCounters(game).getCount(CounterType.LOYALTY); + } else if (card.isBattle(game)) { + res = card.getCounters(game).getCount(CounterType.DEFENSE); + } else { + int damage = 0; + if (card instanceof Permanent) { + damage = ((Permanent) card).getDamage(); + } + res = Math.max(0, card.getToughness().getValue() - damage); + } + } + return res; + } + + private int getScoreFromLife(MageItem item) { + // TODO: replace permanent/card life by battlefield score? + int res = getLifeForDamage(item, game); + if (res == 0 && item instanceof Card) { + res = ((Card) item).getManaValue(); + } + return res; + } + + private boolean isMyItem(MageItem item) { + return PossibleTargetsSelector.isMyItem(this.abilityControllerId, item); + } + + // sort by name-id at the end, so AI will use same choices in all simulations + private final Comparator BY_NAME = (o1, o2) -> getName(o2).compareTo(getName(o1)); + private final Comparator BY_ID = Comparator.comparing(MageItem::getId); + + private final Comparator BY_ME = (o1, o2) -> Boolean.compare( + isMyItem(o2), + isMyItem(o1) + ); + + private final Comparator BY_BIGGER_SCORE = (o1, o2) -> Integer.compare( + getScoreFromBattlefield(o2), + getScoreFromBattlefield(o1) + ); + + private final Comparator BY_PLAYABLE = (o1, o2) -> Boolean.compare( + this.playableItems.containsObject(o2.getId()), + this.playableItems.containsObject(o1.getId()) + ); + + private final Comparator BY_LAND = (o1, o2) -> { + boolean isLand1 = o1 instanceof MageObject && ((MageObject) o1).isLand(game); + boolean isLand2 = o2 instanceof MageObject && ((MageObject) o2).isLand(game); + return Boolean.compare(isLand2, isLand1); + }; + + private final Comparator BY_TYPE_PLAYER = (o1, o2) -> Boolean.compare( + o2 instanceof Player, + o1 instanceof Player + ); + + private final Comparator BY_TYPE_PLANESWALKER = (o1, o2) -> { + boolean isPlaneswalker1 = o1 instanceof MageObject && ((MageObject) o1).isPlaneswalker(game); + boolean isPlaneswalker2 = o2 instanceof MageObject && ((MageObject) o2).isPlaneswalker(game); + return Boolean.compare(isPlaneswalker2, isPlaneswalker1); + }; + + private final Comparator BY_TYPE_BATTLE = (o1, o2) -> { + boolean isBattle1 = o1 instanceof MageObject && ((MageObject) o1).isBattle(game); + boolean isBattle2 = o2 instanceof MageObject && ((MageObject) o2).isBattle(game); + return Boolean.compare(isBattle2, isBattle1); + }; + + private final Comparator BY_TYPES = BY_TYPE_PLANESWALKER + .thenComparing(BY_TYPE_BATTLE) + .thenComparing(BY_TYPE_PLAYER); + + /** + * Default sorting for good effects - put the biggest items to the top + */ + public final Comparator ANY_MOST_VALUABLE_FIRST = BY_TYPES + .thenComparing(BY_BIGGER_SCORE) + .thenComparing(BY_NAME) + .thenComparing(BY_ID); + public final Comparator ANY_MOST_VALUABLE_LAST = ANY_MOST_VALUABLE_FIRST.reversed(); + + /** + * Sorting for discard effects - put the biggest unplayable at the top, lands at the end anyway + */ + public final Comparator ANY_UNPLAYABLE_AND_USELESS = BY_LAND.reversed() + .thenComparing(BY_PLAYABLE.reversed()) + .thenComparing(ANY_MOST_VALUABLE_FIRST); + +} diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/PossibleTargetsSelector.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/PossibleTargetsSelector.java new file mode 100644 index 00000000000..c3d9f25ea22 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/PossibleTargetsSelector.java @@ -0,0 +1,187 @@ +package mage.player.ai; + +import mage.MageItem; +import mage.abilities.Ability; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.ControllableOrOwnerable; +import mage.game.Game; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInGraveyardBattlefieldOrStack; +import mage.target.common.TargetDiscard; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * AI related code - find possible targets and sort it due priority + * + * @author JayDi85 + */ +public class PossibleTargetsSelector { + + Outcome outcome; + Target target; + UUID abilityControllerId; + Ability source; + Game game; + + PossibleTargetsComparator comparators; + + // possible targets lists + List me = new ArrayList<>(); + List opponents = new ArrayList<>(); + List any = new ArrayList<>(); // for outcomes with any target like copy + + public PossibleTargetsSelector(Outcome outcome, Target target, UUID abilityControllerId, Ability source, Game game) { + this.outcome = outcome; + this.target = target; + this.abilityControllerId = abilityControllerId; + this.source = source; + this.game = game; + this.comparators = new PossibleTargetsComparator(abilityControllerId, game); + } + + public void findNewTargets(Set fromTargetsList) { + // collect new valid targets + List found = target.possibleTargets(abilityControllerId, source, game, fromTargetsList).stream() + .filter(id -> !target.contains(id)) + .filter(id -> target.canTarget(abilityControllerId, id, source, game)) + .map(id -> { + Player player = game.getPlayer(id); + if (player != null) { + return player; + } else { + return game.getObject(id); + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + // split targets between me and opponents + found.forEach(item -> { + if (isMyItem(abilityControllerId, item)) { + this.me.add(item); + } else { + this.opponents.add(item); + } + this.any.add(item); + }); + + if (target instanceof TargetDiscard) { + // sort due unplayable + sortByUnplayableAndUseless(); + } else { + // sort due good/bad outcome + sortByMostValuableTargets(); + } + } + + /** + * Sorting for any good/bad effects + */ + private void sortByMostValuableTargets() { + if (isGoodEffect()) { + // for good effect must choose the biggest objects + this.me.sort(comparators.ANY_MOST_VALUABLE_FIRST); + this.opponents.sort(comparators.ANY_MOST_VALUABLE_LAST); + this.any.sort(comparators.ANY_MOST_VALUABLE_FIRST); + } else { + // for bad effect must choose the smallest objects + this.me.sort(comparators.ANY_MOST_VALUABLE_LAST); + this.opponents.sort(comparators.ANY_MOST_VALUABLE_FIRST); + this.any.sort(comparators.ANY_MOST_VALUABLE_LAST); + } + } + + /** + * Sorting for discard + */ + private void sortByUnplayableAndUseless() { + // used + // no good or bad effect - you must choose + comparators.findPlayableItems(); + this.me.sort(comparators.ANY_UNPLAYABLE_AND_USELESS); + this.opponents.sort(comparators.ANY_UNPLAYABLE_AND_USELESS); + this.any.sort(comparators.ANY_UNPLAYABLE_AND_USELESS); + } + + /** + * Priority targets. Try to use as much as possible. + */ + public List getGoodTargets() { + if (isAnyEffect()) { + return this.any; + } + + if (isGoodEffect()) { + return this.me; + } else { + return this.opponents; + } + } + + /** + * Optional targets. Try to ignore bad targets (e.g. opponent's creatures for your good effect). + */ + public List getBadTargets() { + if (isAnyEffect()) { + return Collections.emptyList(); + } + + if (isGoodEffect()) { + return this.opponents; + } else { + return this.me; + } + } + + public static boolean isMyItem(UUID abilityControllerId, MageItem item) { + if (item instanceof Player) { + return item.getId().equals(abilityControllerId); + } else if (item instanceof ControllableOrOwnerable) { + return ((ControllableOrOwnerable) item).getControllerOrOwnerId().equals(abilityControllerId); + } + return false; + } + + private boolean isAnyEffect() { + boolean isAnyEffect = outcome.anyTargetHasSameValue(); + + if (hasGoodExile()) { + isAnyEffect = true; + } + + return isAnyEffect; + } + + private boolean isGoodEffect() { + boolean isGoodEffect = outcome.isGood(); + + if (hasGoodExile()) { + isGoodEffect = true; + } + + return isGoodEffect; + } + + private boolean hasGoodExile() { + // exile workaround: exile is bad, but exile from library or graveyard in most cases is good + // (more exiled -- more good things you get, e.g. delve's pay or search cards with same name) + if (outcome == Outcome.Exile) { + if (Zone.GRAVEYARD.match(target.getZone()) + || Zone.LIBRARY.match(target.getZone())) { + // TargetCardInGraveyardBattlefieldOrStack - used for additional payment like Craft, so do not allow big cards for it + if (!(target instanceof TargetCardInGraveyardBattlefieldOrStack)) { + return true; + } + } + } + return false; + } + + boolean hasAnyTargets() { + return !this.any.isEmpty(); + } +} \ No newline at end of file diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/ArtificialScoringSystem.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/score/ArtificialScoringSystem.java similarity index 99% rename from Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/ArtificialScoringSystem.java rename to Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/score/ArtificialScoringSystem.java index 35ededd0de4..4cef32c7ec8 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/ArtificialScoringSystem.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/score/ArtificialScoringSystem.java @@ -1,4 +1,4 @@ -package mage.player.ai.ma; +package mage.player.ai.score; import mage.MageObject; import mage.abilities.Ability; diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/GameStateEvaluator2.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/score/GameStateEvaluator2.java similarity index 99% rename from Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/GameStateEvaluator2.java rename to Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/score/GameStateEvaluator2.java index ebc0dbcdade..9c96a619d10 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/GameStateEvaluator2.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/score/GameStateEvaluator2.java @@ -1,8 +1,7 @@ -package mage.player.ai; +package mage.player.ai.score; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.player.ai.ma.ArtificialScoringSystem; import mage.players.Player; import org.apache.log4j.Logger; diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/MagicAbility.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/score/MagicAbility.java similarity index 87% rename from Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/MagicAbility.java rename to Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/score/MagicAbility.java index 43fae122d17..63346dc3ed0 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/MagicAbility.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/score/MagicAbility.java @@ -1,4 +1,4 @@ -package mage.player.ai.ma; +package mage.player.ai.score; import mage.abilities.Ability; import mage.abilities.keyword.*; @@ -7,6 +7,7 @@ import java.util.HashMap; import java.util.Map; /** + * TODO: outdated, replace by edh or commander brackets ability score * @author nantuko */ public final class MagicAbility { @@ -18,10 +19,10 @@ public final class MagicAbility { put(DoubleStrikeAbility.getInstance().getRule(), 100); put(new ExaltedAbility().getRule(), 10); put(FirstStrikeAbility.getInstance().getRule(), 50); - put(FlashAbility.getInstance().getRule(), 0); + put(FlashAbility.getInstance().getRule(), 20); put(FlyingAbility.getInstance().getRule(), 50); put(new ForestwalkAbility().getRule(), 10); - put(HasteAbility.getInstance().getRule(), 0); + put(HasteAbility.getInstance().getRule(), 20); put(IndestructibleAbility.getInstance().getRule(), 150); put(InfectAbility.getInstance().getRule(), 60); put(IntimidateAbility.getInstance().getRule(), 50); @@ -46,7 +47,7 @@ public final class MagicAbility { if (!scores.containsKey(ability.getRule())) { //System.err.println("Couldn't find ability score: " + ability.getClass().getSimpleName() + " - " + ability.toString()); //TODO: add handling protection from ..., levelup, kicker, etc. abilities - return 0; + return 2; // more abilities - more score in any use cases } return scores.get(ability.getRule()); } diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/ActionSimulator.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/ActionSimulator.java deleted file mode 100644 index e67d6383710..00000000000 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/ActionSimulator.java +++ /dev/null @@ -1,65 +0,0 @@ - - -package mage.player.ai.simulators; - -import mage.abilities.ActivatedAbility; -import mage.cards.Card; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.player.ai.ComputerPlayer; -import mage.player.ai.PermanentEvaluator; -import mage.players.Player; - -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author BetaSteward_at_googlemail.com - */ -public class ActionSimulator { - - private ComputerPlayer player; - private List playableInstants = new ArrayList<>(); - private List playableAbilities = new ArrayList<>(); - - private Game game; - - public ActionSimulator(ComputerPlayer player) { - this.player = player; - } - - public void simulate(Game game) { - - } - - public int evaluateState() { - // must find all leaved opponents - Player opponent = game.getPlayer(game.getOpponents(player.getId(), false).stream().findFirst().orElse(null)); - if (opponent == null) { - return Integer.MAX_VALUE; - } - - if (game.checkIfGameIsOver()) { - if (player.hasLost() || opponent.hasWon()) { - return Integer.MIN_VALUE; - } - if (opponent.hasLost() || player.hasWon()) { - return Integer.MAX_VALUE; - } - } - int value = player.getLife(); - value -= opponent.getLife(); - PermanentEvaluator evaluator = new PermanentEvaluator(); - for (Permanent permanent: game.getBattlefield().getAllActivePermanents(player.getId())) { - value += evaluator.evaluate(permanent, game); - } - for (Permanent permanent: game.getBattlefield().getAllActivePermanents(player.getId())) { - value -= evaluator.evaluate(permanent, game); - } - value += player.getHand().size(); - value -= opponent.getHand().size(); - return value; - } - -} diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/CombatGroupSimulator.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/CombatGroupSimulator.java deleted file mode 100644 index ffa8bdee0e6..00000000000 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/CombatGroupSimulator.java +++ /dev/null @@ -1,148 +0,0 @@ -package mage.player.ai.simulators; - -import mage.game.Game; -import mage.game.permanent.Permanent; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * - * @author BetaSteward_at_googlemail.com - */ -public class CombatGroupSimulator implements Serializable { - public List attackers = new ArrayList<>(); - public List blockers = new ArrayList<>(); - public UUID defenderId; - public boolean defenderIsPlaneswalker; - public int unblockedDamage; - private CreatureSimulator attacker; - - public CombatGroupSimulator(UUID defenderId, List attackers, List blockers, Game game) { - this.defenderId = defenderId; - for (UUID attackerId: attackers) { - Permanent permanent = game.getPermanent(attackerId); - this.attackers.add(new CreatureSimulator(permanent)); - } - for (UUID blockerId: blockers) { - Permanent permanent = game.getPermanent(blockerId); - this.blockers.add(new CreatureSimulator(permanent)); - } - //NOTE: assumes no banding - attacker = this.attackers.get(0); - } - - private boolean hasFirstOrDoubleStrike() { - for (CreatureSimulator creature: attackers) { - if (creature.hasDoubleStrike || creature.hasFirstStrike) - return true; - } - for (CreatureSimulator creature: blockers) { - if (creature.hasDoubleStrike || creature.hasFirstStrike) - return true; - } - return false; - } - - public boolean canBlock(Permanent blocker, Game game) { - return blocker.canBlock(attacker.id, game); - } - - public void simulateCombat(Game game) { - unblockedDamage = 0; - - if (hasFirstOrDoubleStrike()) - assignDamage(true, game); - assignDamage(false, game); - } - - private void assignDamage(boolean first, Game game) { - if (blockers.isEmpty()) { - if (canDamage(attacker, first)) - unblockedDamage += attacker.power; - } - else if (blockers.size() == 1) { - CreatureSimulator blocker = blockers.get(0); - if (canDamage(attacker, first)) { - if (attacker.hasTrample) { - int lethalDamage = blocker.getLethalDamage(game); - if (attacker.power > lethalDamage) { - blocker.damage += lethalDamage; - unblockedDamage += attacker.power - lethalDamage; - } - else { - blocker.damage += attacker.power; - } - } - } - if (canDamage(blocker, first)) { - attacker.damage += blocker.power; - } - } - else { - int damage = attacker.power; - for (CreatureSimulator blocker: blockers) { - if (damage > 0 && canDamage(attacker, first)) { - int lethalDamage = blocker.getLethalDamage(game); - if (damage > lethalDamage) { - blocker.damage += lethalDamage; - damage -= lethalDamage; - } - else { - blocker.damage += damage; - damage = 0; - } - } - if (canDamage(blocker, first)) { - attacker.damage += blocker.power; - } - } - if (damage > 0) { - if (attacker.hasTrample) { - unblockedDamage += damage; - } - else { - blockers.get(0).damage += damage; - } - } - } - } - - private boolean canDamage(CreatureSimulator creature, boolean first) { - if (first && (creature.hasFirstStrike || creature.hasDoubleStrike)) - return true; - if (!first && (!creature.hasFirstStrike || creature.hasDoubleStrike)) - return true; - return false; - } - - /** - * returns 3 attacker survives blockers destroyed - * returns 2 both destroyed - * returns 1 both survive - * returns 0 attacker destroyed blockers survive - * - * @return int - */ - public int evaluateCombat() { - int survivingBlockers = 0; - for (CreatureSimulator blocker: blockers) { - if (blocker.damage < blocker.toughness) - survivingBlockers++; - } - if (attacker.isDead()) { - if (survivingBlockers > 0) { - return 0; - } - return 2; - } - else { - if (survivingBlockers > 0) { - return 1; - } - return 3; - } - } -} diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/CombatSimulator.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/CombatSimulator.java deleted file mode 100644 index 7157962a522..00000000000 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/CombatSimulator.java +++ /dev/null @@ -1,86 +0,0 @@ -package mage.player.ai.simulators; - -import mage.counters.CounterType; -import mage.game.Game; -import mage.game.combat.CombatGroup; -import mage.game.permanent.Permanent; -import mage.players.Player; - -import java.io.Serializable; -import java.util.*; -import java.util.Map.Entry; - -/** - * - * @author BetaSteward_at_googlemail.com - */ -public class CombatSimulator implements Serializable { - - public List groups = new ArrayList<>(); - public List defenders = new ArrayList<>(); - public Map playersLife = new HashMap<>(); - public Map planeswalkerLoyalty = new HashMap<>(); - public UUID attackerId; - public int rating = 0; - - public static CombatSimulator load(Game game) { - CombatSimulator simCombat = new CombatSimulator(); - for (CombatGroup group: game.getCombat().getGroups()) { - simCombat.groups.add(new CombatGroupSimulator(group.getDefenderId(), group.getAttackers(), group.getBlockers(), game)); - } - for (UUID defenderId: game.getCombat().getDefenders()) { - simCombat.defenders.add(defenderId); - Player player = game.getPlayer(defenderId); - if (player != null) { - simCombat.playersLife.put(defenderId, player.getLife()); - } - else { - Permanent permanent = game.getPermanent(defenderId); - simCombat.planeswalkerLoyalty.put(defenderId, permanent.getCounters(game).getCount(CounterType.LOYALTY)); - } - } - return simCombat; - } - - public CombatSimulator() {} - - public void clear() { - groups.clear(); - defenders.clear(); - attackerId = null; - } - - public void simulate(Game game) { - for (CombatGroupSimulator group: groups) { - group.simulateCombat(game); - } - } - - public int evaluate() { - Map damage = new HashMap<>(); - int result = 0; - for (CombatGroupSimulator group: groups) { - if (!damage.containsKey(group.defenderId)) { - damage.put(group.defenderId, group.unblockedDamage); - } - else { - damage.put(group.defenderId, damage.get(group.defenderId) + group.unblockedDamage); - } - } - //check for lethal damage to player - for (Entry entry: playersLife.entrySet()) { - if (damage.containsKey(entry.getKey()) && entry.getValue() <= damage.get(entry.getKey())) { - //TODO: check for protection - //NOTE: not applicable for mulitplayer games - return Integer.MAX_VALUE; - } - } - - for (CombatGroupSimulator group: groups) { - result += group.evaluateCombat(); - } - - rating = result; - return result; - } -} diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/CreatureSimulator.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/CreatureSimulator.java deleted file mode 100644 index 1a5e7fe7b85..00000000000 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/CreatureSimulator.java +++ /dev/null @@ -1,57 +0,0 @@ -package mage.player.ai.simulators; - -import mage.abilities.keyword.DoubleStrikeAbility; -import mage.abilities.keyword.FirstStrikeAbility; -import mage.abilities.keyword.TrampleAbility; -import mage.filter.common.FilterCreaturePermanent; -import mage.game.Game; -import mage.game.permanent.Permanent; - -import java.io.Serializable; -import java.util.List; -import java.util.UUID; - -/** - * - * @author BetaSteward_at_googlemail.com - */ -public class CreatureSimulator implements Serializable { - public UUID id; - public int damage; - public int power; - public int toughness; - public boolean hasFirstStrike; - public boolean hasDoubleStrike; - public boolean hasTrample; - public Permanent permanent; - - public CreatureSimulator(Permanent permanent) { - this.id = permanent.getId(); - this.damage = permanent.getDamage(); - this.power = permanent.getPower().getValue(); - this.toughness = permanent.getToughness().getValue(); - this.hasDoubleStrike = permanent.getAbilities().containsKey(DoubleStrikeAbility.getInstance().getId()); - this.hasFirstStrike = permanent.getAbilities().containsKey(FirstStrikeAbility.getInstance().getId()); - this.hasTrample = permanent.getAbilities().containsKey(TrampleAbility.getInstance().getId()); - this.permanent = permanent; - } - - public boolean isDead() { - return damage >= toughness; - } - - public int getLethalDamage(Game game) { - List usePowerInsteadOfToughnessForDamageLethalityFilters = game.getState().getActivePowerInsteadOfToughnessForDamageLethalityFilters(); - /* - * for handling Zilortha, Strength Incarnate: - * 2020-04-17 - * Any time the game is checking whether damage is lethal or if a creature should be destroyed for having lethal damage marked on it, use the power of your creatures rather than their toughness to check the damage against. This includes being assigned trample damage, damage from Flame Spill, and so on. - */ - boolean usePowerInsteadOfToughnessForDamageLethality = usePowerInsteadOfToughnessForDamageLethalityFilters.stream() - .anyMatch(filter -> filter.match(permanent, game)); - int lethalDamageThreshold = usePowerInsteadOfToughnessForDamageLethality ? - // Zilortha, Strength Incarnate, 2020-04-17: A creature with 0 power isn’t destroyed unless it has at least 1 damage marked on it. - Math.max(power, 1) : toughness; - return Math.max(lethalDamageThreshold - damage, 0); - } -} diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/ComputerPlayerMCTS.java b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/ComputerPlayerMCTS.java index 8619ef2aeb8..4d65b8bc61c 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/ComputerPlayerMCTS.java +++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/ComputerPlayerMCTS.java @@ -196,7 +196,7 @@ public class ComputerPlayerMCTS extends ComputerPlayer { } catch (ExecutionException e) { // real games: must catch and log // unit tests: must raise again for fast fail - if (this.isTestsMode()) { + if (this.isTestMode() && this.isFastFailInTestMode()) { throw new IllegalStateException("One of the simulated games raise the error: " + e, e); } } diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java index 944d9aa5135..f3dd92bb7be 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java +++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java @@ -288,6 +288,16 @@ public final class SimulatedPlayerMCTS extends MCTSPlayer { @Override public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) { + + // nothing to choose + target.prepareAmount(source, game); + if (target.getAmountRemaining() <= 0) { + return false; + } + if (target.getMaxNumberOfTargets() == 0 && target.getMinNumberOfTargets() == 0) { + return false; + } + Set possibleTargets = target.possibleTargets(playerId, source, game); if (possibleTargets.isEmpty()) { return !target.isRequired(source); diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index c0ab0e728db..cd7b6569cf8 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -297,7 +297,7 @@ public class HumanPlayer extends PlayerImpl { return; } if (logger.isDebugEnabled()) { - logger.debug("Setting game priority for " + getId() + " [" + DebugUtil.getMethodNameWithSource(1) + ']'); + logger.debug("Setting game priority for " + getId() + " [" + DebugUtil.getMethodNameWithSource(1, "method") + ']'); } game.getState().setPriorityPlayerId(getId()); } @@ -328,7 +328,7 @@ public class HumanPlayer extends PlayerImpl { while (loop) { // start waiting for next answer response.clear(); - response.setActiveAction(game, DebugUtil.getMethodNameWithSource(1)); + response.setActiveAction(game, DebugUtil.getMethodNameWithSource(1, "method")); game.resumeTimer(getTurnControlledBy()); responseOpenedForAnswer = true; @@ -690,12 +690,8 @@ public class HumanPlayer extends PlayerImpl { return false; } - // choose one or multiple permanents - UUID abilityControllerId = playerId; - if (target.getTargetController() != null - && target.getAbilityController() != null) { - abilityControllerId = target.getAbilityController(); - } + // choose one or multiple targets + UUID abilityControllerId = target.getAffectedAbilityControllerId(this.getId()); if (options == null) { options = new HashMap<>(); } @@ -782,11 +778,7 @@ public class HumanPlayer extends PlayerImpl { } // choose one or multiple targets - UUID abilityControllerId = playerId; - if (target.getAbilityController() != null) { - abilityControllerId = target.getAbilityController(); - } - + UUID abilityControllerId = target.getAffectedAbilityControllerId(this.getId()); Map options = new HashMap<>(); while (canRespond()) { @@ -869,13 +861,7 @@ public class HumanPlayer extends PlayerImpl { return false; } - UUID abilityControllerId; - if (target.getTargetController() != null - && target.getAbilityController() != null) { - abilityControllerId = target.getAbilityController(); - } else { - abilityControllerId = playerId; - } + UUID abilityControllerId = target.getAffectedAbilityControllerId(this.getId()); while (canRespond()) { @@ -966,13 +952,7 @@ public class HumanPlayer extends PlayerImpl { return false; } - UUID abilityControllerId; - if (target.getTargetController() != null - && target.getAbilityController() != null) { - abilityControllerId = target.getAbilityController(); - } else { - abilityControllerId = playerId; - } + UUID abilityControllerId = target.getAffectedAbilityControllerId(this.getId()); while (canRespond()) { boolean required = target.isRequiredExplicitlySet() ? target.isRequired() : target.isRequired(source); @@ -1042,14 +1022,20 @@ public class HumanPlayer extends PlayerImpl { return false; } + // nothing to choose + target.prepareAmount(source, game); + if (target.getAmountRemaining() <= 0) { + return false; + } + if (target.getMaxNumberOfTargets() == 0 && target.getMinNumberOfTargets() == 0) { + return false; + } + if (source == null) { return false; } - UUID abilityControllerId = playerId; - if (target.getAbilityController() != null) { - abilityControllerId = target.getAbilityController(); - } + UUID abilityControllerId = target.getAffectedAbilityControllerId(this.getId()); int amountTotal = target.getAmountTotal(game, source); if (amountTotal == 0) { diff --git a/Mage.Server/config/config.xml b/Mage.Server/config/config.xml index 928cb18c62f..48b09948dc3 100644 --- a/Mage.Server/config/config.xml +++ b/Mage.Server/config/config.xml @@ -196,6 +196,7 @@ + diff --git a/Mage.Server/pom.xml b/Mage.Server/pom.xml index ff104474d0e..12051c74d86 100644 --- a/Mage.Server/pom.xml +++ b/Mage.Server/pom.xml @@ -192,11 +192,6 @@ runtime - - org.apache.commons - commons-lang3 - 3.11 - javax.xml.bind jaxb-api @@ -218,7 +213,7 @@ org.apache.shiro shiro-core - 1.8.0 + 1.13.0 javax.mail diff --git a/Mage.Server/release/config/config.xml b/Mage.Server/release/config/config.xml index 1e7a126def9..f30470ab1d1 100644 --- a/Mage.Server/release/config/config.xml +++ b/Mage.Server/release/config/config.xml @@ -190,6 +190,7 @@ + diff --git a/Mage.Server/src/main/java/mage/server/ChatManagerImpl.java b/Mage.Server/src/main/java/mage/server/ChatManagerImpl.java index de1c4e24081..335dc081dc0 100644 --- a/Mage.Server/src/main/java/mage/server/ChatManagerImpl.java +++ b/Mage.Server/src/main/java/mage/server/ChatManagerImpl.java @@ -4,6 +4,8 @@ import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.constants.Constants; import mage.game.Game; +import mage.game.Table; +import mage.game.tournament.Tournament; import mage.server.game.GameController; import mage.server.managers.ChatManager; import mage.server.managers.ManagerFactory; @@ -40,11 +42,39 @@ public class ChatManagerImpl implements ChatManager { this.managerFactory = managerFactory; } + @Override - public UUID createChatSession(String info) { + public UUID createRoomChatSession(UUID roomId) { + return createChatSession("Room " + roomId) + .withRoom(roomId) + .getChatId(); + } + + @Override + public UUID createTourneyChatSession(Tournament tournament) { + return createChatSession("Tourney " + tournament.getId()) + .withTourney(tournament) + .getChatId(); + } + + @Override + public UUID createTableChatSession(Table table) { + return createChatSession("Table " + table.getId()) + .withTable(table) + .getChatId(); + } + + @Override + public UUID createGameChatSession(Game game) { + return createChatSession("Game " + game.getId()) + .withGame(game) + .getChatId(); + } + + private ChatSession createChatSession(String info) { ChatSession chatSession = new ChatSession(managerFactory, info); chatSessions.put(chatSession.getChatId(), chatSession); - return chatSession.getChatId(); + return chatSession; } @Override @@ -94,7 +124,7 @@ public class ChatManagerImpl implements ChatManager { ChatSession chatSession = chatSessions.get(chatId); Optional user = managerFactory.userManager().getUserByName(userName); if (chatSession != null) { - // special commads + // special commands if (message.startsWith("\\") || message.startsWith("/")) { if (user.isPresent()) { if (!performUserCommand(user.get(), message, chatId, false)) { diff --git a/Mage.Server/src/main/java/mage/server/ChatSession.java b/Mage.Server/src/main/java/mage/server/ChatSession.java index b58222afbfb..229ee885b6f 100644 --- a/Mage.Server/src/main/java/mage/server/ChatSession.java +++ b/Mage.Server/src/main/java/mage/server/ChatSession.java @@ -1,6 +1,9 @@ package mage.server; +import mage.collectors.DataCollectorServices; import mage.game.Game; +import mage.game.Table; +import mage.game.tournament.Tournament; import mage.interfaces.callback.ClientCallback; import mage.interfaces.callback.ClientCallbackMethod; import mage.server.managers.ManagerFactory; @@ -27,6 +30,13 @@ public class ChatSession { private final ManagerFactory managerFactory; private final ReadWriteLock lock = new ReentrantReadWriteLock(); // TODO: no needs due ConcurrentHashMap usage? + // only 1 field must be filled per chat type + // TODO: rework chat sessions to share logic (one server room/lobby + one table/subtable + one games/match) + private UUID roomId = null; + private UUID tourneyId = null; + private UUID tableId = null; + private UUID gameId = null; + private final ConcurrentMap users = new ConcurrentHashMap<>(); // active users private final Set usersHistory = new HashSet<>(); // all users that was here (need for system messages like connection problem) private final UUID chatId; @@ -40,6 +50,26 @@ public class ChatSession { this.info = info; } + public ChatSession withRoom(UUID roomId) { + this.roomId = roomId; + return this; + } + + public ChatSession withTourney(Tournament tournament) { + this.tourneyId = tournament.getId(); + return this; + } + + public ChatSession withTable(Table table) { + this.tableId = table.getId(); + return this; + } + + public ChatSession withGame(Game game) { + this.gameId = game.getId(); + return this; + } + public void join(UUID userId) { managerFactory.userManager().getUser(userId).ifPresent(user -> { if (!users.containsKey(userId)) { @@ -112,9 +142,36 @@ public class ChatSession { // TODO: is it freeze on someone's connection fail/freeze with play multiple games/chats/lobby? // TODO: send messages in another thread?! if (!message.isEmpty()) { + ChatMessage chatMessage = new ChatMessage(userName, message, (withTime ? new Date() : null), game, color, messageType, soundToPlay); + + switch (messageType) { + case USER_INFO: + case STATUS: + case TALK: + if (this.roomId != null) { + DataCollectorServices.getInstance().onChatRoom(this.roomId, userName, message); + } else if (this.tourneyId != null) { + DataCollectorServices.getInstance().onChatTourney(this.tourneyId, userName, message); + } else if (this.tableId != null) { + DataCollectorServices.getInstance().onChatTable(this.tableId, userName, message); + } else if (this.gameId != null) { + DataCollectorServices.getInstance().onChatGame(this.gameId, userName, message); + } + break; + case GAME: + // game logs processing in other place + break; + case WHISPER_FROM: + case WHISPER_TO: + // ignore private messages + break; + default: + throw new IllegalStateException("Unsupported message type " + messageType); + } + + // TODO: wtf, remove all that locks/tries and make it simpler Set clientsToRemove = new HashSet<>(); - ClientCallback clientCallback = new ClientCallback(ClientCallbackMethod.CHATMESSAGE, chatId, - new ChatMessage(userName, message, (withTime ? new Date() : null), game, color, messageType, soundToPlay)); + ClientCallback clientCallback = new ClientCallback(ClientCallbackMethod.CHATMESSAGE, chatId, chatMessage); List chatUserIds = new ArrayList<>(); final Lock r = lock.readLock(); r.lock(); diff --git a/Mage.Server/src/main/java/mage/server/MageServerImpl.java b/Mage.Server/src/main/java/mage/server/MageServerImpl.java index dcc20c38256..a0083afc710 100644 --- a/Mage.Server/src/main/java/mage/server/MageServerImpl.java +++ b/Mage.Server/src/main/java/mage/server/MageServerImpl.java @@ -5,6 +5,7 @@ import mage.cards.decks.DeckCardLists; import mage.cards.decks.DeckValidatorFactory; import mage.cards.repository.CardRepository; import mage.cards.repository.ExpansionRepository; +import mage.collectors.DataCollectorServices; import mage.constants.Constants; import mage.constants.ManaType; import mage.constants.PlayerAction; @@ -29,6 +30,7 @@ import mage.server.managers.ManagerFactory; import mage.server.services.impl.FeedbackServiceImpl; import mage.server.tournament.TournamentFactory; import mage.server.util.ServerMessagesUtil; +import mage.util.DebugUtil; import mage.utils.*; import mage.view.*; import mage.view.ChatMessage.MessageColor; @@ -68,6 +70,13 @@ public class MageServerImpl implements MageServer { this.detailsMode = detailsMode; this.callExecutor = managerFactory.threadExecutor().getCallExecutor(); ServerMessagesUtil.instance.getMessages(); + + // additional logs + DataCollectorServices.init( + DebugUtil.SERVER_DATA_COLLECTORS_ENABLE_PRINT_GAME_LOGS, + DebugUtil.SERVER_DATA_COLLECTORS_ENABLE_SAVE_GAME_HISTORY + ); + DataCollectorServices.getInstance().onServerStart(); } @Override diff --git a/Mage.Server/src/main/java/mage/server/RoomImpl.java b/Mage.Server/src/main/java/mage/server/RoomImpl.java index 9221ee0cd38..8b628544e27 100644 --- a/Mage.Server/src/main/java/mage/server/RoomImpl.java +++ b/Mage.Server/src/main/java/mage/server/RoomImpl.java @@ -14,7 +14,7 @@ public abstract class RoomImpl implements Room { public RoomImpl(ChatManager chatManager) { roomId = UUID.randomUUID(); - chatId = chatManager.createChatSession("Room " + roomId); + chatId = chatManager.createRoomChatSession(roomId); } /** diff --git a/Mage.Server/src/main/java/mage/server/SessionManagerImpl.java b/Mage.Server/src/main/java/mage/server/SessionManagerImpl.java index a3fe09ef6b6..76bbb3d755e 100644 --- a/Mage.Server/src/main/java/mage/server/SessionManagerImpl.java +++ b/Mage.Server/src/main/java/mage/server/SessionManagerImpl.java @@ -8,7 +8,6 @@ import mage.util.ThreadUtils; import org.apache.log4j.Logger; import org.jboss.remoting.callback.InvokerCallbackHandler; -import javax.annotation.Nonnull; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; @@ -29,7 +28,7 @@ public class SessionManagerImpl implements SessionManager { } @Override - public Optional getSession(@Nonnull String sessionId) { + public Optional getSession(String sessionId) { return Optional.ofNullable(sessions.getOrDefault(sessionId, null)); } @@ -180,12 +179,12 @@ public class SessionManagerImpl implements SessionManager { } @Override - public boolean isValidSession(@Nonnull String sessionId) { + public boolean isValidSession(String sessionId) { return sessions.containsKey(sessionId); } @Override - public Optional getUser(@Nonnull String sessionId) { + public Optional getUser(String sessionId) { Session session = sessions.get(sessionId); if (session != null) { return managerFactory.userManager().getUser(sessions.get(sessionId).getUserId()); diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java index b23895416cd..be338040777 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -72,7 +72,7 @@ public class TableController { } this.table = new Table(roomId, options.getGameType(), options.getName(), controllerName, DeckValidatorFactory.instance.createDeckValidator(options.getDeckType()), options.getPlayerTypes(), new TableRecorderImpl(managerFactory.userManager()), match, options.getBannedUsers(), options.isPlaneChase()); - this.chatId = managerFactory.chatManager().createChatSession("Match Table " + table.getId()); + this.chatId = managerFactory.chatManager().createTableChatSession(table); init(); } @@ -94,7 +94,7 @@ public class TableController { } table = new Table(roomId, options.getTournamentType(), options.getName(), controllerName, DeckValidatorFactory.instance.createDeckValidator(options.getMatchOptions().getDeckType()), options.getPlayerTypes(), new TableRecorderImpl(managerFactory.userManager()), tournament, options.getMatchOptions().getBannedUsers(), options.isPlaneChase()); - chatId = managerFactory.chatManager().createChatSession("Tourney table " + table.getId()); + chatId = managerFactory.chatManager().createTableChatSession(table); } private void init() { diff --git a/Mage.Server/src/main/java/mage/server/challenge/ChallengeManager.java b/Mage.Server/src/main/java/mage/server/challenge/ChallengeManager.java deleted file mode 100644 index 1c9b4f57777..00000000000 --- a/Mage.Server/src/main/java/mage/server/challenge/ChallengeManager.java +++ /dev/null @@ -1,25 +0,0 @@ -package mage.server.challenge; - -import mage.constants.Zone; -import mage.game.match.Match; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -/** - * C U R R E N T L Y U N U S E D - * - * Loads challenges from scenarios. - * Configure games by initializing starting game board. - */ -public enum ChallengeManager { - - instance; - - public void prepareChallenge(UUID playerId, Match match) { - Map commands = new HashMap<>(); - commands.put(Zone.OUTSIDE, "life:3"); - match.getGame().cheat(playerId, commands); - } -} diff --git a/Mage.Server/src/main/java/mage/server/exceptions/UserNotFoundException.java b/Mage.Server/src/main/java/mage/server/exceptions/UserNotFoundException.java deleted file mode 100644 index 5787b42f6d5..00000000000 --- a/Mage.Server/src/main/java/mage/server/exceptions/UserNotFoundException.java +++ /dev/null @@ -1,7 +0,0 @@ -package mage.server.exceptions; - -/** - * Created by igoudt on 14-1-2017. - */ -public class UserNotFoundException extends Exception { -} diff --git a/Mage.Server/src/main/java/mage/server/game/GameController.java b/Mage.Server/src/main/java/mage/server/game/GameController.java index 96ed8b53505..8141658f86f 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameController.java +++ b/Mage.Server/src/main/java/mage/server/game/GameController.java @@ -85,11 +85,11 @@ public class GameController implements GameCallback { public GameController(ManagerFactory managerFactory, Game game, ConcurrentMap userPlayerMap, UUID tableId, UUID choosingPlayerId, GameOptions gameOptions) { this.managerFactory = managerFactory; - gameExecutor = managerFactory.threadExecutor().getGameExecutor(); - responseIdleTimeoutExecutor = managerFactory.threadExecutor().getTimeoutIdleExecutor(); - gameSessionId = UUID.randomUUID(); + this.gameExecutor = managerFactory.threadExecutor().getGameExecutor(); + this.responseIdleTimeoutExecutor = managerFactory.threadExecutor().getTimeoutIdleExecutor(); + this.gameSessionId = UUID.randomUUID(); this.userPlayerMap = userPlayerMap; - chatId = managerFactory.chatManager().createChatSession("Game " + game.getId()); + this.chatId = managerFactory.chatManager().createGameChatSession(game); this.userRequestingRollback = null; this.game = game; this.game.setSaveGame(managerFactory.configSettings().isSaveGameActivated()); diff --git a/Mage.Server/src/main/java/mage/server/managers/ChatManager.java b/Mage.Server/src/main/java/mage/server/managers/ChatManager.java index 7319561890d..056500cae69 100644 --- a/Mage.Server/src/main/java/mage/server/managers/ChatManager.java +++ b/Mage.Server/src/main/java/mage/server/managers/ChatManager.java @@ -1,9 +1,10 @@ package mage.server.managers; import mage.game.Game; +import mage.game.Table; +import mage.game.tournament.Tournament; import mage.server.ChatSession; import mage.server.DisconnectReason; -import mage.server.exceptions.UserNotFoundException; import mage.view.ChatMessage; import java.util.List; @@ -11,7 +12,13 @@ import java.util.UUID; public interface ChatManager { - UUID createChatSession(String info); + UUID createRoomChatSession(UUID roomId); + + UUID createTourneyChatSession(Tournament tournament); + + UUID createTableChatSession(Table table); + + UUID createGameChatSession(Game game); void joinChat(UUID chatId, UUID userId); diff --git a/Mage.Server/src/main/java/mage/server/managers/SessionManager.java b/Mage.Server/src/main/java/mage/server/managers/SessionManager.java index c5d1559b068..181ea1b28a9 100644 --- a/Mage.Server/src/main/java/mage/server/managers/SessionManager.java +++ b/Mage.Server/src/main/java/mage/server/managers/SessionManager.java @@ -7,12 +7,11 @@ import mage.server.Session; import mage.server.User; import org.jboss.remoting.callback.InvokerCallbackHandler; -import javax.annotation.Nonnull; import java.util.Optional; public interface SessionManager { - Optional getSession(@Nonnull String sessionId); + Optional getSession(String sessionId); void createSession(String sessionId, InvokerCallbackHandler callbackHandler); @@ -37,9 +36,9 @@ public interface SessionManager { boolean checkAdminAccess(String sessionId); - boolean isValidSession(@Nonnull String sessionId); + boolean isValidSession(String sessionId); - Optional getUser(@Nonnull String sessionId); + Optional getUser(String sessionId); boolean extendUserSession(String sessionId, String pingInfo); diff --git a/Mage.Server/src/main/java/mage/server/services/LogService.java b/Mage.Server/src/main/java/mage/server/services/LogService.java deleted file mode 100644 index b0edcdfba49..00000000000 --- a/Mage.Server/src/main/java/mage/server/services/LogService.java +++ /dev/null @@ -1,18 +0,0 @@ -package mage.server.services; - -/** - * Responsible for gathering logs and storing them in DB. - * - * @author noxx - */ -@FunctionalInterface -public interface LogService { - - /** - * Logs any information - * - * @param key Log key. Should be the same for the same types of logs. - * @param args Any parameters in string representation. - */ - void log(String key, String... args); -} diff --git a/Mage.Server/src/main/java/mage/server/services/MageService.java b/Mage.Server/src/main/java/mage/server/services/MageService.java deleted file mode 100644 index d80d7568d7e..00000000000 --- a/Mage.Server/src/main/java/mage/server/services/MageService.java +++ /dev/null @@ -1,18 +0,0 @@ -package mage.server.services; - -/** - * Common interface for all services. - * - * @author noxx - */ -public interface MageService { - /** - * Restores data on startup. - */ - void initService(); - - /** - * Dumps data to DB. - */ - void saveData(); -} diff --git a/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java b/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java index 939ee2db5b9..df85a172b05 100644 --- a/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java +++ b/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java @@ -54,7 +54,7 @@ public class TournamentController { public TournamentController(ManagerFactory managerFactory, Tournament tournament, ConcurrentMap userPlayerMap, UUID tableId) { this.managerFactory = managerFactory; this.userPlayerMap = userPlayerMap; - chatId = managerFactory.chatManager().createChatSession("Tournament " + tournament.getId()); + this.chatId = managerFactory.chatManager().createTourneyChatSession(tournament); this.tournament = tournament; this.tableId = tableId; init(); @@ -261,9 +261,7 @@ public class TournamentController { table.setState(TableState.STARTING); tableManager.startTournamentSubMatch(null, table.getId()); tableManager.getMatch(table.getId()).ifPresent(match -> { - match.setTableId(tableId); - pair.setMatch(match); - pair.setTableId(table.getId()); + pair.setMatchAndTable(match, table.getId()); player1.setState(TournamentPlayerState.DUELING); player2.setState(TournamentPlayerState.DUELING); }); @@ -291,9 +289,7 @@ public class TournamentController { table.setState(TableState.STARTING); tableManager.startTournamentSubMatch(null, table.getId()); tableManager.getMatch(table.getId()).ifPresent(match -> { - match.setTableId(tableId); - round.setMatch(match); - round.setTableId(table.getId()); + round.setMatchAndTable(match, table.getId()); for (TournamentPlayer player : round.getAllPlayers()) { player.setState(TournamentPlayerState.DUELING); } diff --git a/Mage.Sets/src/mage/cards/a/AbunaAcolyte.java b/Mage.Sets/src/mage/cards/a/AbunaAcolyte.java index 2b4699f8d01..f072fd4e51a 100644 --- a/Mage.Sets/src/mage/cards/a/AbunaAcolyte.java +++ b/Mage.Sets/src/mage/cards/a/AbunaAcolyte.java @@ -14,6 +14,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetAnyTarget; import mage.target.common.TargetCreaturePermanent; @@ -39,7 +40,7 @@ public final class AbunaAcolyte extends CardImpl { Ability ability1 = new SimpleActivatedAbility(new PreventDamageToTargetEffect(Duration.EndOfTurn, 1), new TapSourceCost()); ability1.addTarget(new TargetAnyTarget()); Ability ability2 = new SimpleActivatedAbility(new PreventDamageToTargetEffect(Duration.EndOfTurn, 2), new TapSourceCost()); - ability2.addTarget(new TargetCreaturePermanent(filter)); + ability2.addTarget(new TargetPermanent(filter)); this.addAbility(ability1); this.addAbility(ability2); } diff --git a/Mage.Sets/src/mage/cards/a/AbzanCharm.java b/Mage.Sets/src/mage/cards/a/AbzanCharm.java index 288f3e1c380..64e1e67de45 100644 --- a/Mage.Sets/src/mage/cards/a/AbzanCharm.java +++ b/Mage.Sets/src/mage/cards/a/AbzanCharm.java @@ -13,6 +13,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanentAmount; @@ -33,7 +34,7 @@ public final class AbzanCharm extends CardImpl { // Choose one - // *Exile target creature with power 3 or greater - this.getSpellAbility().addTarget(new TargetCreaturePermanent(FILTER)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER)); this.getSpellAbility().addEffect(new ExileTargetEffect()); // *You draw two cards and you lose 2 life diff --git a/Mage.Sets/src/mage/cards/a/AcademyJourneymage.java b/Mage.Sets/src/mage/cards/a/AcademyJourneymage.java index a3b3893e1ba..dd12271e5c0 100644 --- a/Mage.Sets/src/mage/cards/a/AcademyJourneymage.java +++ b/Mage.Sets/src/mage/cards/a/AcademyJourneymage.java @@ -16,10 +16,13 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * @author JRHerlehy */ @@ -47,7 +50,7 @@ public final class AcademyJourneymage extends CardImpl { // When Academy Journeymage enters the battlefield, return target creature an opponent controls to its owner's hand. ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AccumulatedKnowledge.java b/Mage.Sets/src/mage/cards/a/AccumulatedKnowledge.java index 9089d5f3d76..ab3716f78c3 100644 --- a/Mage.Sets/src/mage/cards/a/AccumulatedKnowledge.java +++ b/Mage.Sets/src/mage/cards/a/AccumulatedKnowledge.java @@ -1,7 +1,6 @@ package mage.cards.a; -import java.util.UUID; import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -11,8 +10,9 @@ import mage.constants.CardType; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.NamePredicate; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class AccumulatedKnowledge extends CardImpl { @@ -24,13 +24,13 @@ public final class AccumulatedKnowledge extends CardImpl { } public AccumulatedKnowledge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Draw a card, then draw cards equal to the number of cards named Accumulated Knowledge in all graveyards. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); Effect effect = new DrawCardSourceControllerEffect(new CardsInAllGraveyardsCount(filter)); - effect.setText(", then draw cards equal to the number of cards named {this} in all graveyards"); + effect.setText(", then draw cards equal to the number of cards named Accumulated Knowledge in all graveyards"); this.getSpellAbility().addEffect(effect); } diff --git a/Mage.Sets/src/mage/cards/a/AcererakTheArchlich.java b/Mage.Sets/src/mage/cards/a/AcererakTheArchlich.java index d429f82da8c..7e2a4356737 100644 --- a/Mage.Sets/src/mage/cards/a/AcererakTheArchlich.java +++ b/Mage.Sets/src/mage/cards/a/AcererakTheArchlich.java @@ -44,9 +44,7 @@ public final class AcererakTheArchlich extends CardImpl { Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandSourceEffect(true)) .withInterveningIf(AcererakTheArchlichCondition.instance); ability.addEffect(new VentureIntoTheDungeonEffect().concatBy("and")); - ability.addHint(CurrentDungeonHint.instance); - ability.addHint(CompletedDungeonCondition.getHint()); - this.addAbility(ability, new CompletedDungeonWatcher()); + this.addAbility(ability.addHint(CurrentDungeonHint.instance).addHint(CompletedDungeonCondition.getHint()), new CompletedDungeonWatcher()); // Whenever Acererak the Archlich attacks, for each opponent, you create a 2/2 black Zombie creature token unless that player sacrifices a creature. this.addAbility(new AttacksTriggeredAbility(new AcererakTheArchlichEffect())); @@ -83,7 +81,7 @@ class AcererakTheArchlichEffect extends OneShotEffect { AcererakTheArchlichEffect() { super(Outcome.Benefit); staticText = "for each opponent, you create a 2/2 black Zombie creature " + - "token unless that player sacrifices a creature"; + "token unless that player sacrifices a creature of their choice"; } private AcererakTheArchlichEffect(final AcererakTheArchlichEffect effect) { diff --git a/Mage.Sets/src/mage/cards/a/AcesBaseballBat.java b/Mage.Sets/src/mage/cards/a/AcesBaseballBat.java index 0a54026f17a..2eca11d118b 100644 --- a/Mage.Sets/src/mage/cards/a/AcesBaseballBat.java +++ b/Mage.Sets/src/mage/cards/a/AcesBaseballBat.java @@ -15,7 +15,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -60,7 +60,7 @@ public final class AcesBaseballBat extends CardImpl { // Equip legendary creature (1) this.addAbility(new EquipAbility( Outcome.AddAbility, new GenericManaCost(1), - new TargetControlledCreaturePermanent(filterLegendary), false + new TargetPermanent(filterLegendary), false )); // Equip {3} diff --git a/Mage.Sets/src/mage/cards/a/AcidicDagger.java b/Mage.Sets/src/mage/cards/a/AcidicDagger.java index a33f2c051fe..5cd4d7e2e98 100644 --- a/Mage.Sets/src/mage/cards/a/AcidicDagger.java +++ b/Mage.Sets/src/mage/cards/a/AcidicDagger.java @@ -5,7 +5,7 @@ import mage.abilities.DelayedTriggeredAbility; import mage.abilities.condition.common.BeforeBlockersAreDeclaredCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.DestroyTargetEffect; @@ -39,7 +39,7 @@ public final class AcidicDagger extends CardImpl { // {4}, {tap}: Whenever target creature deals combat damage to a non-Wall creature this turn, // destroy that non-Wall creature. When the targeted creature leaves the battlefield this turn, // sacrifice Acidic Dagger. Activate this ability only before blockers are declared. - Ability ability = new ConditionalActivatedAbility( + Ability ability = new ActivateIfConditionActivatedAbility( new CreateDelayedTriggeredAbilityEffect(new AcidicDaggerDestroyNonWallAbility()), new GenericManaCost(4), BeforeBlockersAreDeclaredCondition.instance); diff --git a/Mage.Sets/src/mage/cards/a/ActOfAggression.java b/Mage.Sets/src/mage/cards/a/ActOfAggression.java index 468e53e5f16..8787eaedb16 100644 --- a/Mage.Sets/src/mage/cards/a/ActOfAggression.java +++ b/Mage.Sets/src/mage/cards/a/ActOfAggression.java @@ -11,8 +11,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author North @@ -21,7 +24,7 @@ public final class ActOfAggression extends CardImpl { public ActOfAggression(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R/P}{R/P}"); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfTurn)); this.getSpellAbility().addEffect(new UntapTargetEffect().setText("Untap that creature")); this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn).setText("It gains haste until end of turn.")); diff --git a/Mage.Sets/src/mage/cards/a/AdaptiveOmnitool.java b/Mage.Sets/src/mage/cards/a/AdaptiveOmnitool.java index f88856700d9..7e9d1901c0f 100644 --- a/Mage.Sets/src/mage/cards/a/AdaptiveOmnitool.java +++ b/Mage.Sets/src/mage/cards/a/AdaptiveOmnitool.java @@ -1,7 +1,5 @@ package mage.cards.a; -import java.util.UUID; - import mage.abilities.common.AttacksAttachedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; @@ -9,35 +7,35 @@ import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; -import mage.abilities.hint.Hint; -import mage.abilities.hint.ValueHint; +import mage.abilities.hint.common.ArtifactYouControlHint; import mage.abilities.keyword.EquipAbility; -import mage.constants.Outcome; -import mage.constants.PutCards; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.PutCards; +import mage.constants.SubType; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledArtifactPermanent; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author sobiech */ public final class AdaptiveOmnitool extends CardImpl { + private final static DynamicValue artifactYouControlCount = new PermanentsOnBattlefieldCount(new FilterControlledArtifactPermanent()); - private final static Hint hint = new ValueHint("Artifacts you control", artifactYouControlCount); public AdaptiveOmnitool(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); - + this.subtype.add(SubType.EQUIPMENT); // Equipped creature gets +1/+1 for each artifact you control. this.addAbility( - new SimpleStaticAbility(new BoostEquippedEffect(artifactYouControlCount, artifactYouControlCount)).addHint(hint) + new SimpleStaticAbility(new BoostEquippedEffect(artifactYouControlCount, artifactYouControlCount)).addHint(ArtifactYouControlHint.instance) ); // Whenever equipped creature attacks, look at the top six cards of your library. You may reveal an artifact card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. diff --git a/Mage.Sets/src/mage/cards/a/AdaptiveTrainingPost.java b/Mage.Sets/src/mage/cards/a/AdaptiveTrainingPost.java index 36f48cb6f75..b53f18cfd23 100644 --- a/Mage.Sets/src/mage/cards/a/AdaptiveTrainingPost.java +++ b/Mage.Sets/src/mage/cards/a/AdaptiveTrainingPost.java @@ -31,7 +31,7 @@ public final class AdaptiveTrainingPost extends CardImpl { this.addAbility(new SpellCastControllerTriggeredAbility( new AddCountersSourceEffect(CounterType.CHARGE.createInstance()), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false - ).withInterveningIf(condition)); + ).withInterveningIf(condition).withRuleTextReplacement(true)); // Remove three charge counters from this artifact: When you next cast an instant or sorcery spell this turn, copy it and you may choose new targets for the copy. this.addAbility(new SimpleActivatedAbility( diff --git a/Mage.Sets/src/mage/cards/a/AdmonitionAngel.java b/Mage.Sets/src/mage/cards/a/AdmonitionAngel.java index a7597e37970..4a0c7e97325 100644 --- a/Mage.Sets/src/mage/cards/a/AdmonitionAngel.java +++ b/Mage.Sets/src/mage/cards/a/AdmonitionAngel.java @@ -1,7 +1,6 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbility; @@ -20,13 +19,15 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.TargetPermanent; +import java.util.UUID; + /** * * @author jeffwadsworth */ public final class AdmonitionAngel extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("nonland permanent other than Admonition Angel"); + private static final FilterPermanent filter = new FilterPermanent("nonland permanent other than {this}"); static { filter.add(AnotherPredicate.instance); diff --git a/Mage.Sets/src/mage/cards/a/AdvocateOfTheBeast.java b/Mage.Sets/src/mage/cards/a/AdvocateOfTheBeast.java index a72aa079675..1b3220379d8 100644 --- a/Mage.Sets/src/mage/cards/a/AdvocateOfTheBeast.java +++ b/Mage.Sets/src/mage/cards/a/AdvocateOfTheBeast.java @@ -14,6 +14,7 @@ import mage.constants.TargetController; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class AdvocateOfTheBeast extends CardImpl { // At the beginning of your end step, put a +1/+1 counter on target Beast creature you control. Ability ability = new BeginningOfEndStepTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); ability.addTarget(target); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AegisAutomaton.java b/Mage.Sets/src/mage/cards/a/AegisAutomaton.java index db0ea3472ea..ee80a59768b 100644 --- a/Mage.Sets/src/mage/cards/a/AegisAutomaton.java +++ b/Mage.Sets/src/mage/cards/a/AegisAutomaton.java @@ -1,6 +1,5 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -10,12 +9,12 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author fireshoes */ public final class AegisAutomaton extends CardImpl { @@ -29,7 +28,7 @@ public final class AegisAutomaton extends CardImpl { // {4}{W}: Return another target creature you control to its owner's hand. Ability ability = new SimpleActivatedAbility(new ReturnToHandTargetEffect(), new ManaCostsImpl<>("{4}{W}")); - ability.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AegisOfTheMeek.java b/Mage.Sets/src/mage/cards/a/AegisOfTheMeek.java index 96bbbbfc9c8..b7ae289da89 100644 --- a/Mage.Sets/src/mage/cards/a/AegisOfTheMeek.java +++ b/Mage.Sets/src/mage/cards/a/AegisOfTheMeek.java @@ -16,6 +16,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.filter.predicate.mageobject.ToughnessPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class AegisOfTheMeek extends CardImpl { // {1}, {T}: Target 1/1 creature gets +1/+2 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(1, 2, Duration.EndOfTurn), new ManaCostsImpl<>("{1}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AerialPredation.java b/Mage.Sets/src/mage/cards/a/AerialPredation.java index e0abfba71bd..e3e9164983e 100644 --- a/Mage.Sets/src/mage/cards/a/AerialPredation.java +++ b/Mage.Sets/src/mage/cards/a/AerialPredation.java @@ -12,6 +12,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -31,7 +32,7 @@ public final class AerialPredation extends CardImpl { // Destroy target creature with flying. You gain 2 life. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addEffect(new GainLifeEffect(2)); } diff --git a/Mage.Sets/src/mage/cards/a/AerialSurveyor.java b/Mage.Sets/src/mage/cards/a/AerialSurveyor.java index 0aaed9d279b..b8199c1a008 100644 --- a/Mage.Sets/src/mage/cards/a/AerialSurveyor.java +++ b/Mage.Sets/src/mage/cards/a/AerialSurveyor.java @@ -84,7 +84,7 @@ enum AerialSurveyorCondition implements Condition { @Override public String toString() { - return ""; + return "defending player controls more lands than you"; } } diff --git a/Mage.Sets/src/mage/cards/a/AerieOuphes.java b/Mage.Sets/src/mage/cards/a/AerieOuphes.java index cbe0fccb147..588d018cefd 100644 --- a/Mage.Sets/src/mage/cards/a/AerieOuphes.java +++ b/Mage.Sets/src/mage/cards/a/AerieOuphes.java @@ -16,6 +16,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -42,7 +43,7 @@ public final class AerieOuphes extends CardImpl { // Sacrifice Aerie Ouphes: Aerie Ouphes deals damage equal to its power to target creature with flying. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(SourcePermanentPowerValue.NOT_NEGATIVE) .setText("it deals damage equal to its power to target creature with flying"), new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Persist diff --git a/Mage.Sets/src/mage/cards/a/AetherBarrier.java b/Mage.Sets/src/mage/cards/a/AetherBarrier.java index 170ea126d00..8378d421e33 100644 --- a/Mage.Sets/src/mage/cards/a/AetherBarrier.java +++ b/Mage.Sets/src/mage/cards/a/AetherBarrier.java @@ -44,7 +44,7 @@ class AetherBarrierEffect extends SacrificeEffect { AetherBarrierEffect() { super(new FilterPermanent("permanent to sacrifice"), 1, "that player"); - this.staticText = "that player sacrifices a permanent unless they pay {1}"; + this.staticText = "that player sacrifices a permanent of their choice unless they pay {1}"; } private AetherBarrierEffect(final AetherBarrierEffect effect) { diff --git a/Mage.Sets/src/mage/cards/a/AetherfluxConduit.java b/Mage.Sets/src/mage/cards/a/AetherfluxConduit.java index f4f9316a48e..263ffa68a36 100644 --- a/Mage.Sets/src/mage/cards/a/AetherfluxConduit.java +++ b/Mage.Sets/src/mage/cards/a/AetherfluxConduit.java @@ -1,19 +1,22 @@ package mage.cards.a; +import mage.Mana; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.costs.common.PayEnergyCost; import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.counter.GetEnergyCountersControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; +import mage.counters.CounterType; import mage.filter.StaticFilters; +import mage.game.Controllable; import mage.game.Game; import mage.game.stack.Spell; import mage.players.Player; @@ -34,8 +37,8 @@ public final class AetherfluxConduit extends CardImpl { this.addAbility(new SpellCastControllerTriggeredAbility(new AetherfluxConduitManaEffect(), false)); // {T}, Pay fifty {E}: Draw seven cards. You may cast any number of spells from your hand without paying their mana costs. - final Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(7), new TapSourceCost()); - ability.addCost(new PayEnergyCost(50).setText("Pay fifty {E}")); + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(7), new TapSourceCost()); + ability.addCost(new PayEnergyCost(50).setText("pay fifty {E}")); ability.addEffect(new AetherfluxConduitCastEffect()); this.addAbility(ability); } @@ -68,10 +71,21 @@ class AetherfluxConduitManaEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Optional.ofNullable(this.getValue("spellCast")) + int amount = Optional + .ofNullable(this.getValue("spellCast")) .map(Spell.class::cast) - .ifPresent(spell -> new GetEnergyCountersControllerEffect(spell.getManaValue()).apply(game, source)); - return true; + .map(Spell::getStackAbility) + .map(Ability::getManaCostsToPay) + .map(ManaCost::getUsedManaToPay) + .map(Mana::count) + .orElse(0); + return amount > 0 + && Optional + .ofNullable(source) + .map(Controllable::getControllerId) + .map(game::getPlayer) + .filter(player -> player.addCounters(CounterType.ENERGY.createInstance(amount), player.getId(), source, game)) + .isPresent(); } } diff --git a/Mage.Sets/src/mage/cards/a/AethershieldArtificer.java b/Mage.Sets/src/mage/cards/a/AethershieldArtificer.java index 834f30d8126..381028cfea3 100644 --- a/Mage.Sets/src/mage/cards/a/AethershieldArtificer.java +++ b/Mage.Sets/src/mage/cards/a/AethershieldArtificer.java @@ -1,22 +1,22 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.IndestructibleAbility; -import mage.constants.SubType; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class AethershieldArtificer extends CardImpl { @@ -45,7 +45,7 @@ public final class AethershieldArtificer extends CardImpl { IndestructibleAbility.getInstance(), Duration.EndOfTurn ).setText("and gains indestructible until end of turn")); - ability.addTarget(new TargetControlledCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/Aethertow.java b/Mage.Sets/src/mage/cards/a/Aethertow.java index 7db15f9b34d..834eff2e808 100644 --- a/Mage.Sets/src/mage/cards/a/Aethertow.java +++ b/Mage.Sets/src/mage/cards/a/Aethertow.java @@ -13,6 +13,7 @@ import mage.filter.common.FilterAttackingOrBlockingCreature; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -28,7 +29,7 @@ public final class Aethertow extends CardImpl { // Put target attacking or blocking creature on top of its owner's library. this.getSpellAbility().addEffect(new AethertowEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Conspire this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.ONE)); diff --git a/Mage.Sets/src/mage/cards/a/AffectionateIndrik.java b/Mage.Sets/src/mage/cards/a/AffectionateIndrik.java index 3e469e6ebb1..644bb7447eb 100644 --- a/Mage.Sets/src/mage/cards/a/AffectionateIndrik.java +++ b/Mage.Sets/src/mage/cards/a/AffectionateIndrik.java @@ -9,10 +9,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author TheElk801 */ @@ -32,7 +35,7 @@ public final class AffectionateIndrik extends CardImpl { "(Each deals damage equal to its power to the other.)"), true ); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AgadeemOccultist.java b/Mage.Sets/src/mage/cards/a/AgadeemOccultist.java index b5bf7698444..0db9443e93b 100644 --- a/Mage.Sets/src/mage/cards/a/AgadeemOccultist.java +++ b/Mage.Sets/src/mage/cards/a/AgadeemOccultist.java @@ -5,7 +5,9 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.OneShotEffect; +import mage.abilities.hint.ValueHint; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -13,9 +15,9 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.FilterCard; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreatureCard; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInOpponentsGraveyard; @@ -37,7 +39,10 @@ public final class AgadeemOccultist extends CardImpl { this.toughness = new MageInt(2); // {tap}: Put target creature card from an opponent's graveyard onto the battlefield under your control if its converted mana cost is less than or equal to the number of Allies you control. - this.addAbility(new SimpleActivatedAbility(new AgadeemOccultistEffect(), new TapSourceCost())); + Ability ability = new SimpleActivatedAbility(new AgadeemOccultistEffect(), new TapSourceCost()); + ability.addTarget(new TargetCardInOpponentsGraveyard(new FilterCreatureCard("target creature card from an opponent's graveyard"))); + ability.addHint(new ValueHint("Allies you control", new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.ALLY)))); + this.addAbility(ability); } @@ -50,7 +55,6 @@ public final class AgadeemOccultist extends CardImpl { return new AgadeemOccultist(this); } } - class AgadeemOccultistEffect extends OneShotEffect { AgadeemOccultistEffect() { @@ -70,26 +74,12 @@ class AgadeemOccultistEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - int allycount = 0; - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) { - if (permanent.hasSubtype(SubType.ALLY, game)) { - allycount++; - } - } - FilterCard filter = new FilterCard("creature card in an opponent's graveyard"); - filter.add(CardType.CREATURE.getPredicate()); - TargetCardInOpponentsGraveyard target = new TargetCardInOpponentsGraveyard(1, 1, filter); - if (controller != null) { - if (target.canChoose(source.getControllerId(), source, game) - && controller.choose(Outcome.GainControl, target, source, game)) { - if (!target.getTargets().isEmpty()) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - if (card.getManaValue() <= allycount) { - return controller.moveCards(card, Zone.BATTLEFIELD, source, game); - } - } + Card card = game.getCard(source.getFirstTarget()); + if (card != null) { + int allycount = new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.ALLY)).calculate(game, source, this); + if (card.getManaValue() <= allycount) { + return controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } return true; diff --git a/Mage.Sets/src/mage/cards/a/AgathasChampion.java b/Mage.Sets/src/mage/cards/a/AgathasChampion.java index 7b7fdbaaa69..409195e2c24 100644 --- a/Mage.Sets/src/mage/cards/a/AgathasChampion.java +++ b/Mage.Sets/src/mage/cards/a/AgathasChampion.java @@ -1,10 +1,9 @@ package mage.cards.a; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.BargainedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.FightTargetSourceEffect; import mage.abilities.keyword.BargainAbility; import mage.abilities.keyword.TrampleAbility; @@ -37,14 +36,11 @@ public final class AgathasChampion extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // When Agatha's Champion enters the battlefield, if it was bargained, it fights up to one target creature you don't control. - TriggeredAbility trigger = new EntersBattlefieldTriggeredAbility(new FightTargetSourceEffect()); - trigger.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL, false)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - trigger, - BargainedCondition.instance, - "When {this} enters, if it was bargained, it fights up to one target creature you don't control." + - " (Each deals damage equal to its power to the other.)" - )); + Ability ability = new EntersBattlefieldTriggeredAbility( + new FightTargetSourceEffect().setText("it fights up to one target creature you don't control") + ).withInterveningIf(BargainedCondition.instance); + ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.addAbility(ability); } private AgathasChampion(final AgathasChampion card) { diff --git a/Mage.Sets/src/mage/cards/a/AgentOfAcquisitions.java b/Mage.Sets/src/mage/cards/a/AgentOfAcquisitions.java index abd5645d229..bdbd264c6e9 100644 --- a/Mage.Sets/src/mage/cards/a/AgentOfAcquisitions.java +++ b/Mage.Sets/src/mage/cards/a/AgentOfAcquisitions.java @@ -1,15 +1,16 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.InfoEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.InfoEffect; + +import java.util.UUID; /** * @@ -27,11 +28,11 @@ public final class AgentOfAcquisitions extends CardImpl { // TODO: Draft specific abilities not implemented // Draft Agent of Acquisitions face up. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft Agent of Acquisitions face up - not implemented."))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft {this} face up - not implemented."))); // Instead of drafting a card from a booster pack, you may draft each card in that booster pack, one at a time. If you do, turn Agent of Acquisitions face down and you can’t draft cards for the rest of this draft round. this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Instead of drafting a card from a booster pack, " - + "you may draft each card in that booster pack, one at a time. If you do, turn Agent of Acquisitions face down and " + + "you may draft each card in that booster pack, one at a time. If you do, turn {this} face down and " + "you can't draft cards for the rest of this draft round - not implemented."))); } diff --git a/Mage.Sets/src/mage/cards/a/AggressiveInstinct.java b/Mage.Sets/src/mage/cards/a/AggressiveInstinct.java index 5b7bad83ffd..b2b09bf3928 100644 --- a/Mage.Sets/src/mage/cards/a/AggressiveInstinct.java +++ b/Mage.Sets/src/mage/cards/a/AggressiveInstinct.java @@ -5,11 +5,14 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author TheElk801 */ @@ -21,7 +24,7 @@ public final class AggressiveInstinct extends CardImpl { // Target creature you control deals damage equal to its power to target creature you don't control. this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); } private AggressiveInstinct(final AggressiveInstinct card) { diff --git a/Mage.Sets/src/mage/cards/a/AgonizingDemise.java b/Mage.Sets/src/mage/cards/a/AgonizingDemise.java index 35bca60480d..d55c3c7a4ad 100644 --- a/Mage.Sets/src/mage/cards/a/AgonizingDemise.java +++ b/Mage.Sets/src/mage/cards/a/AgonizingDemise.java @@ -10,10 +10,13 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * @author FenrisulfrX */ @@ -27,7 +30,7 @@ public final class AgonizingDemise extends CardImpl { // Destroy target nonblack creature. It can't be regenerated. this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); // If Agonizing Demise was kicked, it deals damage equal to that creature's power to the creature's controller. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( diff --git a/Mage.Sets/src/mage/cards/a/AgrusKosEternalSoldier.java b/Mage.Sets/src/mage/cards/a/AgrusKosEternalSoldier.java index c2090ee031a..31cbd6f881b 100644 --- a/Mage.Sets/src/mage/cards/a/AgrusKosEternalSoldier.java +++ b/Mage.Sets/src/mage/cards/a/AgrusKosEternalSoldier.java @@ -23,7 +23,6 @@ import mage.game.stack.Spell; import mage.game.stack.StackObject; import mage.players.Player; import mage.target.Target; -import mage.util.CardUtil; import java.util.Collection; import java.util.List; @@ -90,7 +89,7 @@ class AgrusKosEternalSoldierTriggeredAbility extends TriggeredAbilityImpl { if (!event.getTargetId().equals(getSourceId())) { return false; } - StackObject targetingObject = CardUtil.findTargetingStackObject(this.getId().toString(), event, game); + StackObject targetingObject = game.findTargetingStackObject(this.getId().toString(), event); if (targetingObject == null || targetingObject instanceof Spell) { return false; } diff --git a/Mage.Sets/src/mage/cards/a/AidFromTheCowl.java b/Mage.Sets/src/mage/cards/a/AidFromTheCowl.java index 3cd45e595ad..ade3ca20c8f 100644 --- a/Mage.Sets/src/mage/cards/a/AidFromTheCowl.java +++ b/Mage.Sets/src/mage/cards/a/AidFromTheCowl.java @@ -50,7 +50,7 @@ class AidFromTheCowlEffect extends OneShotEffect { AidFromTheCowlEffect() { super(Outcome.PutCreatureInPlay); this.staticText = "reveal the top card of your library. If it's a permanent card, " + - "you may put it onto the battlefield. Otherwise, you may put that card on the bottom of your library"; + "you may put it onto the battlefield. Otherwise, you may put it on the bottom of your library"; } private AidFromTheCowlEffect(final AidFromTheCowlEffect effect) { diff --git a/Mage.Sets/src/mage/cards/a/AirCultElemental.java b/Mage.Sets/src/mage/cards/a/AirCultElemental.java index 173b62f090d..f7689e5385c 100644 --- a/Mage.Sets/src/mage/cards/a/AirCultElemental.java +++ b/Mage.Sets/src/mage/cards/a/AirCultElemental.java @@ -1,21 +1,21 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.ReturnToHandTargetEffect; -import mage.constants.SubType; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author weirddan455 */ public final class AirCultElemental extends CardImpl { @@ -38,7 +38,7 @@ public final class AirCultElemental extends CardImpl { // Whirlwind — When Air-Cult Elemental enters the battlefield, return up to one other target creature to its owner's hand. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()); - ability.addTarget(new TargetCreaturePermanent(0, 1, filter, false)); + ability.addTarget(new TargetPermanent(0, 1, filter)); this.addAbility(ability.withFlavorWord("Whirlwind")); } diff --git a/Mage.Sets/src/mage/cards/a/AirServant.java b/Mage.Sets/src/mage/cards/a/AirServant.java index 59d071fe21f..da105691266 100644 --- a/Mage.Sets/src/mage/cards/a/AirServant.java +++ b/Mage.Sets/src/mage/cards/a/AirServant.java @@ -16,6 +16,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class AirServant extends CardImpl { this.toughness = new MageInt(3); this.addAbility(FlyingAbility.getInstance()); Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new ManaCostsImpl<>("{2}{U}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AjaniFellsTheGodsire.java b/Mage.Sets/src/mage/cards/a/AjaniFellsTheGodsire.java index 96391abd3e0..aaa321844a5 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniFellsTheGodsire.java +++ b/Mage.Sets/src/mage/cards/a/AjaniFellsTheGodsire.java @@ -23,6 +23,8 @@ import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.constants.SagaChapter.CHAPTER_I; + /** * @author Susucr */ @@ -45,8 +47,8 @@ public final class AjaniFellsTheGodsire extends CardImpl { // I -- Exile target creature an opponent controls with power 3 or greater. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_I, - new ExileTargetEffect(), new TargetCreaturePermanent(filter) + this, CHAPTER_I, CHAPTER_I, + new ExileTargetEffect(), new TargetPermanent(filter) ); // II -- Create a 2/1 white Cat Warrior creature token, then put a vigilance counter on a creature you control. @@ -104,4 +106,4 @@ class AjaniFellsTheGodsireCounterEffect extends OneShotEffect { Permanent permanent = game.getPermanent(target.getFirstTarget()); return permanent != null && permanent.addCounters(CounterType.VIGILANCE.createInstance(), source, game); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/a/AjanisMantra.java b/Mage.Sets/src/mage/cards/a/AjanisMantra.java index 24cf9c68bc0..ea8ca8f9a2c 100644 --- a/Mage.Sets/src/mage/cards/a/AjanisMantra.java +++ b/Mage.Sets/src/mage/cards/a/AjanisMantra.java @@ -1,24 +1,22 @@ - - package mage.cards.a; -import java.util.UUID; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.game.events.GameEvent.EventType; + +import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com */ public final class AjanisMantra extends CardImpl { public AjanisMantra(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{W}"); - this.addAbility(new OnEventTriggeredAbility(EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", new GainLifeEffect(1), true)); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new GainLifeEffect(1), true)); } private AjanisMantra(final AjanisMantra card) { @@ -29,5 +27,4 @@ public final class AjanisMantra extends CardImpl { public AjanisMantra copy() { return new AjanisMantra(this); } - } diff --git a/Mage.Sets/src/mage/cards/a/AkroanConscriptor.java b/Mage.Sets/src/mage/cards/a/AkroanConscriptor.java index 519e4086dff..1911476f4a3 100644 --- a/Mage.Sets/src/mage/cards/a/AkroanConscriptor.java +++ b/Mage.Sets/src/mage/cards/a/AkroanConscriptor.java @@ -16,8 +16,11 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * * @author LevelX2 @@ -40,7 +43,7 @@ public final class AkroanConscriptor extends CardImpl { effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); effect.setText("It gains haste until end of turn"); ability.addEffect(effect); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AkutaBornOfAsh.java b/Mage.Sets/src/mage/cards/a/AkutaBornOfAsh.java index 44822285a72..7be6f3b471a 100644 --- a/Mage.Sets/src/mage/cards/a/AkutaBornOfAsh.java +++ b/Mage.Sets/src/mage/cards/a/AkutaBornOfAsh.java @@ -1,12 +1,12 @@ package mage.cards.a; import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.common.MoreCardsInHandThanOpponentsCondition; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; import mage.abilities.keyword.HasteAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -15,18 +15,14 @@ import mage.filter.common.FilterControlledPermanent; import java.util.UUID; /** - * * @author LevelX2 */ public final class AkutaBornOfAsh extends CardImpl { - private static final FilterControlledPermanent filterSwamp = new FilterControlledPermanent("a Swamp"); - static { - filterSwamp.add(SubType.SWAMP.getPredicate()); - } + private static final FilterControlledPermanent filterSwamp = new FilterControlledPermanent(SubType.SWAMP, "a Swamp"); public AkutaBornOfAsh(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.SPIRIT); @@ -37,9 +33,14 @@ public final class AkutaBornOfAsh extends CardImpl { this.addAbility(HasteAbility.getInstance()); // At the beginning of your upkeep, if you have more cards in hand than each opponent, you may sacrifice a Swamp. If you do, return Akuta, Born of Ash from your graveyard to the battlefield. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.GRAVEYARD, - TargetController.YOU, new DoIfCostPaid(new ReturnSourceFromGraveyardToBattlefieldEffect(), new SacrificeTargetCost(filterSwamp)), - false).withInterveningIf(MoreCardsInHandThanOpponentsCondition.instance)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + Zone.GRAVEYARD, TargetController.YOU, + new DoIfCostPaid( + new ReturnSourceFromGraveyardToBattlefieldEffect() + .setText("return {this} from your graveyard to the battlefield"), + new SacrificeTargetCost(filterSwamp) + ), false + ).withInterveningIf(MoreCardsInHandThanOpponentsCondition.instance)); } private AkutaBornOfAsh(final AkutaBornOfAsh card) { diff --git a/Mage.Sets/src/mage/cards/a/AlabornVeteran.java b/Mage.Sets/src/mage/cards/a/AlabornVeteran.java index a9280a62891..80ade8c4ea7 100644 --- a/Mage.Sets/src/mage/cards/a/AlabornVeteran.java +++ b/Mage.Sets/src/mage/cards/a/AlabornVeteran.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -13,25 +11,27 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class AlabornVeteran extends CardImpl { public AlabornVeteran(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.KNIGHT); this.power = new MageInt(2); this.toughness = new MageInt(2); // {tap}: Target creature gets +2/+2 until end of turn. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new BoostTargetEffect(2, 2, Duration.EndOfTurn), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new BoostTargetEffect(2, 2, Duration.EndOfTurn), + new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance + ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AlaniaDivergentStorm.java b/Mage.Sets/src/mage/cards/a/AlaniaDivergentStorm.java index 25aaa3ed729..5b73990ab2e 100644 --- a/Mage.Sets/src/mage/cards/a/AlaniaDivergentStorm.java +++ b/Mage.Sets/src/mage/cards/a/AlaniaDivergentStorm.java @@ -1,8 +1,5 @@ package mage.cards.a; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; @@ -11,12 +8,11 @@ import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CopyTargetStackObjectEffect; import mage.abilities.effects.common.DoIfCostPaid; -import mage.constants.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -25,15 +21,18 @@ import mage.players.Player; import mage.target.common.TargetOpponent; import mage.watchers.Watcher; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** - * * @author jimga150 */ public final class AlaniaDivergentStorm extends CardImpl { public AlaniaDivergentStorm(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{R}"); - + this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.OTTER); this.subtype.add(SubType.WIZARD); @@ -43,18 +42,13 @@ public final class AlaniaDivergentStorm extends CardImpl { // Whenever you cast a spell, if it's the first instant spell, the first sorcery spell, or the first Otter // spell other than Alania you've cast this turn, you may have target opponent draw a card. If you do, copy // that spell. You may choose new targets for the copy. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new SpellCastControllerTriggeredAbility(new DoIfCostPaid( - new CopyTargetStackObjectEffect(true), - new AlaniaDivergentStormCost() - ), null, false, SetTargetPointer.SPELL) - .setTriggerPhrase("Whenever you cast a spell, if it's the first instant spell, the first sorcery " + - "spell, or the first Otter spell other than Alania you've cast this turn, "), - AlaniaDivergentStormCondition.instance, "" - ); - ability.addWatcher(new AlaniaDivergentStormWatcher()); - this.addAbility(ability); - + Ability ability = new SpellCastControllerTriggeredAbility( + new DoIfCostPaid(new CopyTargetStackObjectEffect(true).setText("copy that spell. You may choose new targets for the copy") + , new AlaniaDivergentStormCost()), + null, false, SetTargetPointer.SPELL + ).withInterveningIf(AlaniaDivergentStormCondition.instance); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability, new AlaniaDivergentStormWatcher()); } private AlaniaDivergentStorm(final AlaniaDivergentStorm card) { @@ -67,12 +61,10 @@ public final class AlaniaDivergentStorm extends CardImpl { } } -// Based on MarathWillOfTheWildRemoveCountersCost class AlaniaDivergentStormCost extends CostImpl { AlaniaDivergentStormCost() { this.text = "have target opponent draw a card"; - this.addTarget(new TargetOpponent()); } private AlaniaDivergentStormCost(AlaniaDivergentStormCost cost) { @@ -82,32 +74,18 @@ class AlaniaDivergentStormCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { Player player = game.getPlayer(controllerId); - if (player == null) { - return false; - } - for (UUID opponentID : game.getOpponents(controllerId)){ - Player opponent = game.getPlayer(opponentID); - if (opponent == null) { - continue; - } - if (opponent.canBeTargetedBy(source.getSourceObject(game), controllerId, source, game)) { - return true; - } - } - return false; + Player opponent = game.getPlayer(source.getFirstTarget()); + return player != null && opponent != null; } @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - this.getTargets().clearChosen(); paid = false; - if (this.getTargets().choose(Outcome.DrawCard, controllerId, source.getSourceId(), source, game)) { - Player opponent = game.getPlayer(this.getTargets().getFirstTarget()); - if (opponent == null || !opponent.canRespond()){ - return false; - } - paid = opponent.drawCards(1, source, game) > 0; + Player opponent = game.getPlayer(source.getFirstTarget()); + if (opponent == null || !opponent.canRespond()) { + return false; } + paid = opponent.drawCards(1, source, game) > 0; return paid; } @@ -137,6 +115,11 @@ enum AlaniaDivergentStormCondition implements Condition { MageObjectReference spellMOR = new MageObjectReference(spell, game); return watcher.spellIsFirstISOCast(spellControllerID, spellMOR, sourceSpellMOR); } + + @Override + public String toString() { + return "it's the first instant spell, the first sorcery spell, or the first Otter spell other than {this} you've cast this turn"; + } } // Based on FirstSpellCastThisTurnWatcher diff --git a/Mage.Sets/src/mage/cards/a/Alarum.java b/Mage.Sets/src/mage/cards/a/Alarum.java index 5c00fd4bc74..42489867e0f 100644 --- a/Mage.Sets/src/mage/cards/a/Alarum.java +++ b/Mage.Sets/src/mage/cards/a/Alarum.java @@ -12,6 +12,7 @@ import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.AttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -34,7 +35,7 @@ public final class Alarum extends CardImpl { Effect effect = new BoostTargetEffect(1, 3, Duration.EndOfTurn); effect.setText("It gets +1/+3 until end of turn"); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private Alarum(final Alarum card) { diff --git a/Mage.Sets/src/mage/cards/a/AlchemistsTalent.java b/Mage.Sets/src/mage/cards/a/AlchemistsTalent.java index 65dfb59a6c2..47f1f7f5c33 100644 --- a/Mage.Sets/src/mage/cards/a/AlchemistsTalent.java +++ b/Mage.Sets/src/mage/cards/a/AlchemistsTalent.java @@ -66,7 +66,7 @@ public final class AlchemistsTalent extends CardImpl { new SpellCastControllerTriggeredAbility( new DamagePlayersEffect(AlchemistsTalentValue.instance, TargetController.OPPONENT) .setText("{this} deals damage equal to that spell's mana value to each opponent"), - StaticFilters.FILTER_SPELL, false, SetTargetPointer.SPELL + StaticFilters.FILTER_SPELL_A, false, SetTargetPointer.SPELL ).withInterveningIf(AlchemistsTalentCondition.instance), 3 ))); } diff --git a/Mage.Sets/src/mage/cards/a/AlibansTower.java b/Mage.Sets/src/mage/cards/a/AlibansTower.java index 5f05ea33259..7eb354c3f1e 100644 --- a/Mage.Sets/src/mage/cards/a/AlibansTower.java +++ b/Mage.Sets/src/mage/cards/a/AlibansTower.java @@ -8,6 +8,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.common.FilterBlockingCreature; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -21,7 +22,7 @@ public final class AlibansTower extends CardImpl { // Target blocking creature gets +3/+1 until end of turn. this.getSpellAbility().addEffect(new BoostTargetEffect(3, 1, Duration.EndOfTurn)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterBlockingCreature())); + this.getSpellAbility().addTarget(new TargetPermanent(new FilterBlockingCreature())); } private AlibansTower(final AlibansTower card) { diff --git a/Mage.Sets/src/mage/cards/a/AlluringSiren.java b/Mage.Sets/src/mage/cards/a/AlluringSiren.java index 14dc35dbfae..389bae04d87 100644 --- a/Mage.Sets/src/mage/cards/a/AlluringSiren.java +++ b/Mage.Sets/src/mage/cards/a/AlluringSiren.java @@ -12,8 +12,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author BetaSteward_at_googlemail.com @@ -29,7 +32,7 @@ public final class AlluringSiren extends CardImpl { // {T}: Target creature an opponent controls attacks you this turn if able. Ability ability = new SimpleActivatedAbility(new AttacksIfAbleTargetEffect(Duration.EndOfTurn, TargetController.YOU), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AlphaBrawl.java b/Mage.Sets/src/mage/cards/a/AlphaBrawl.java index 096cb3bbe81..f22422b10bf 100644 --- a/Mage.Sets/src/mage/cards/a/AlphaBrawl.java +++ b/Mage.Sets/src/mage/cards/a/AlphaBrawl.java @@ -14,8 +14,11 @@ import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author BetaSteward @@ -27,7 +30,7 @@ public final class AlphaBrawl extends CardImpl { // Target creature an opponent controls deals damage equal to its power to each other creature that player controls, then each of those creatures deals damage equal to its power to that creature. this.getSpellAbility().addEffect(new AlphaBrawlEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); } diff --git a/Mage.Sets/src/mage/cards/a/AlphaKavu.java b/Mage.Sets/src/mage/cards/a/AlphaKavu.java index 15dd7d09277..c26d92e0eea 100644 --- a/Mage.Sets/src/mage/cards/a/AlphaKavu.java +++ b/Mage.Sets/src/mage/cards/a/AlphaKavu.java @@ -14,6 +14,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class AlphaKavu extends CardImpl { // {1}{G}: Target Kavu creature gets -1/+1 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(-1, 1, Duration.EndOfTurn), new ManaCostsImpl<>("{1}{G}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AlpharaelDreamingAcolyte.java b/Mage.Sets/src/mage/cards/a/AlpharaelDreamingAcolyte.java new file mode 100644 index 00000000000..e3a4313bdb4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AlpharaelDreamingAcolyte.java @@ -0,0 +1,63 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AlpharaelDreamingAcolyte extends CardImpl { + + public AlpharaelDreamingAcolyte(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // When Alpharael enters, draw two cards. Then discard two cards unless you discard an artifact card. + Ability ability = new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(2)); + ability.addEffect(new DoIfCostPaid( + null, new DiscardControllerEffect(2), + new DiscardCardCost(StaticFilters.FILTER_CARD_ARTIFACT) + .setText("discard an artifact card instead of discarding two cards") + ).setText("Then discard two cards unless you discard an artifact card")); + this.addAbility(ability); + + // During your turn, Alpharael has deathtouch. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(DeathtouchAbility.getInstance(), Duration.WhileOnBattlefield), + MyTurnCondition.instance, "during your turn, {this} has deathtouch" + ))); + } + + private AlpharaelDreamingAcolyte(final AlpharaelDreamingAcolyte card) { + super(card); + } + + @Override + public AlpharaelDreamingAcolyte copy() { + return new AlpharaelDreamingAcolyte(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AltarGolem.java b/Mage.Sets/src/mage/cards/a/AltarGolem.java index 31b8571ab1a..403b8c6e9c1 100644 --- a/Mage.Sets/src/mage/cards/a/AltarGolem.java +++ b/Mage.Sets/src/mage/cards/a/AltarGolem.java @@ -1,7 +1,6 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -17,24 +16,17 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; /** - * * @author jeffwadsworth - * */ public final class AltarGolem extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); - - static { - filter.add(TappedPredicate.UNTAPPED); - } - public AltarGolem(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{7}"); this.subtype.add(SubType.GOLEM); @@ -53,7 +45,7 @@ public final class AltarGolem extends CardImpl { this.addAbility(new SimpleStaticAbility(new DontUntapInControllersUntapStepSourceEffect())); // Tap five untapped creatures you control: Untap Altar Golem. - this.addAbility(new SimpleActivatedAbility(new UntapSourceEffect(), new TapTargetCost(new TargetControlledCreaturePermanent(5, 5, filter, true)))); + this.addAbility(new SimpleActivatedAbility(new UntapSourceEffect(), new TapTargetCost(new TargetControlledPermanent(5, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES)))); } diff --git a/Mage.Sets/src/mage/cards/a/AmbitiousFarmhand.java b/Mage.Sets/src/mage/cards/a/AmbitiousFarmhand.java index 63256a34839..cf911245785 100644 --- a/Mage.Sets/src/mage/cards/a/AmbitiousFarmhand.java +++ b/Mage.Sets/src/mage/cards/a/AmbitiousFarmhand.java @@ -11,7 +11,10 @@ import mage.abilities.hint.common.CovenHint; import mage.abilities.keyword.TransformAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.FilterCard; import mage.target.common.TargetCardInLibrary; @@ -46,8 +49,7 @@ public final class AmbitiousFarmhand extends CardImpl { // Coven—{1}{W}{W}: Transform Ambitious Farmhand. Activate only if you control three or more creatures with different powers. this.addAbility(new TransformAbility()); this.addAbility(new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new TransformSourceEffect(), - new ManaCostsImpl<>("{1}{W}{W}"), CovenCondition.instance + new TransformSourceEffect(), new ManaCostsImpl<>("{1}{W}{W}"), CovenCondition.instance ).setAbilityWord(AbilityWord.COVEN).addHint(CovenHint.instance)); } diff --git a/Mage.Sets/src/mage/cards/a/AminatouTheFateshifter.java b/Mage.Sets/src/mage/cards/a/AminatouTheFateshifter.java index ae9c55446d9..041b6e123a2 100644 --- a/Mage.Sets/src/mage/cards/a/AminatouTheFateshifter.java +++ b/Mage.Sets/src/mage/cards/a/AminatouTheFateshifter.java @@ -118,8 +118,8 @@ class AminatouUltimateEffect extends OneShotEffect { AminatouUltimateEffect() { super(Outcome.Benefit); - staticText = "Choose left or right. Each player gains control of all nonland permanents other than Aminatou," - + " the Fateshifter controlled by the next player in the chosen direction."; + staticText = "Choose left or right. Each player gains control of all nonland permanents other than {this}" + + " controlled by the next player in the chosen direction."; } private AminatouUltimateEffect(final AminatouUltimateEffect effect) { diff --git a/Mage.Sets/src/mage/cards/a/AmyRose.java b/Mage.Sets/src/mage/cards/a/AmyRose.java new file mode 100644 index 00000000000..ddc0fb6fa88 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AmyRose.java @@ -0,0 +1,94 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterAttackingCreature; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AmyRose extends CardImpl { + + private static final FilterPermanent filter = new FilterAttackingCreature("other attacking creature"); + + static { + filter.add(AnotherPredicate.instance); + } + + public AmyRose(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HEDGEHOG); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Whenever Amy Rose attacks, attach up to one target Equipment to her. Then up to one other target attacking creature gets +X/+0 until end of turn, where X is Amy Rose's power. + Ability ability = new AttacksTriggeredAbility(new AmyRoseEffect()); + ability.addEffect(new BoostTargetEffect( + SourcePermanentPowerValue.NOT_NEGATIVE, StaticValue.get(0) + ).setTargetPointer(new SecondTargetPointer()) + .setText("Then up to one other target attacking creature gets +X/+0 until end of turn, where X is {this}'s power")); + ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_PERMANENT_EQUIPMENT)); + ability.addTarget(new TargetPermanent(0, 1, filter)); + this.addAbility(ability); + } + + private AmyRose(final AmyRose card) { + super(card); + } + + @Override + public AmyRose copy() { + return new AmyRose(this); + } +} + +class AmyRoseEffect extends OneShotEffect { + + AmyRoseEffect() { + super(Outcome.Benefit); + staticText = "attach up to one target Equipment to her"; + } + + private AmyRoseEffect(final AmyRoseEffect effect) { + super(effect); + } + + @Override + public AmyRoseEffect copy() { + return new AmyRoseEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + Permanent equipment = game.getPermanent(getTargetPointer().getFirst(game, source)); + return permanent != null && equipment != null && permanent.addAttachment(equipment.getId(), source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AnaBattlemage.java b/Mage.Sets/src/mage/cards/a/AnaBattlemage.java index f33df1df178..1def7d10026 100644 --- a/Mage.Sets/src/mage/cards/a/AnaBattlemage.java +++ b/Mage.Sets/src/mage/cards/a/AnaBattlemage.java @@ -19,6 +19,7 @@ import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; @@ -58,7 +59,7 @@ public final class AnaBattlemage extends CardImpl { // When Ana Battlemage enters the battlefield, if it was kicked with its {1}{B} kicker, tap target untapped creature and that creature deals damage equal to its power to its controller. ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()).withInterveningIf(condition2); ability.addEffect(new AnaBattlemageEffect()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } @@ -76,7 +77,7 @@ class AnaBattlemageEffect extends OneShotEffect { AnaBattlemageEffect() { super(Outcome.Detriment); - this.staticText = "and it deals damage equal to its power to its controller"; + this.staticText = "and that creature deals damage equal to its power to its controller"; } private AnaBattlemageEffect(final AnaBattlemageEffect effect) { diff --git a/Mage.Sets/src/mage/cards/a/AnaSanctuary.java b/Mage.Sets/src/mage/cards/a/AnaSanctuary.java index 0b18e54890b..0c6a8f9ae49 100644 --- a/Mage.Sets/src/mage/cards/a/AnaSanctuary.java +++ b/Mage.Sets/src/mage/cards/a/AnaSanctuary.java @@ -1,24 +1,18 @@ - package mage.cards.a; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.common.SanctuaryInterveningIfTriggeredAbility; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.common.SanctuaryTriggeredAbility; +import mage.abilities.effects.common.AddContinuousEffectToGame; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.game.Game; import mage.target.common.TargetCreaturePermanent; -import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class AnaSanctuary extends CardImpl { @@ -27,10 +21,11 @@ public final class AnaSanctuary extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); // At the beginning of your upkeep, if you control a blue or black permanent, target creature gets +1/+1 until end of turn. If you control a blue permanent and a black permanent, that creature gets +5/+5 until end of turn instead. - Ability ability = new SanctuaryInterveningIfTriggeredAbility( - new BoostEffect(1), new BoostEffect(5), ObjectColor.BLACK, ObjectColor.BLUE, - "At the beginning of your upkeep, if you control a blue or black permanent, " - + "target creature gets +1/+1 until end of turn. If you control a blue permanent and a black permanent, that creature gets +5/+5 until end of turn instead." + Ability ability = new SanctuaryTriggeredAbility( + new AddContinuousEffectToGame(new BoostTargetEffect(1, 1)), + new AddContinuousEffectToGame(new BoostTargetEffect(5, 5)), + ObjectColor.BLACK, ObjectColor.BLUE, "target creature gets +1/+1 until end of turn. " + + "If you control a blue permanent and a black permanent, that creature gets +5/+5 until end of turn instead." ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); @@ -45,31 +40,3 @@ public final class AnaSanctuary extends CardImpl { return new AnaSanctuary(this); } } - -class BoostEffect extends OneShotEffect { - - private final int amount; - - BoostEffect(int amount) { - super(Outcome.Benefit); - this.amount = amount; - } - - private BoostEffect(final BoostEffect effect) { - super(effect); - this.amount = effect.amount; - } - - @Override - public BoostEffect copy() { - return new BoostEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - ContinuousEffect effect = new BoostTargetEffect(amount, amount, Duration.EndOfTurn); - effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game)); - game.addEffect(effect, source); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/a/AnabaAncestor.java b/Mage.Sets/src/mage/cards/a/AnabaAncestor.java index 3510bc6d5c9..0604bd824fb 100644 --- a/Mage.Sets/src/mage/cards/a/AnabaAncestor.java +++ b/Mage.Sets/src/mage/cards/a/AnabaAncestor.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class AnabaAncestor extends CardImpl { // {T}: Another target Minotaur creature gets +1/+1 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(1, 1, Duration.EndOfTurn), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AnafenzaTheForemost.java b/Mage.Sets/src/mage/cards/a/AnafenzaTheForemost.java index 0dc09db1b19..6c90ec2fa41 100644 --- a/Mage.Sets/src/mage/cards/a/AnafenzaTheForemost.java +++ b/Mage.Sets/src/mage/cards/a/AnafenzaTheForemost.java @@ -21,7 +21,7 @@ import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentToken; import mage.players.Player; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -48,7 +48,7 @@ public final class AnafenzaTheForemost extends CardImpl { // Whenever Anafenza, the Foremost attacks, put a +1/+1 counter on another target tapped creature you control. Ability ability = new AttacksTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false); - ability.addTarget(new TargetControlledCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // If a nontoken creature an opponent owns would die or a creature card not on the battlefield would be put into an opponent's graveyard, exile that card instead. diff --git a/Mage.Sets/src/mage/cards/a/Anavolver.java b/Mage.Sets/src/mage/cards/a/Anavolver.java index bfbae67c81e..a3b08559f11 100644 --- a/Mage.Sets/src/mage/cards/a/Anavolver.java +++ b/Mage.Sets/src/mage/cards/a/Anavolver.java @@ -2,7 +2,6 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -19,9 +18,10 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.counters.CounterType; +import java.util.UUID; + /** * @author Loki */ @@ -49,9 +49,9 @@ public final class Anavolver extends CardImpl { // If Anavolver was kicked with its {B} kicker, it enters with a +1/+1 counter on it and with "Pay 3 life: Regenerate Anavolver." EntersBattlefieldAbility ability2 = new EntersBattlefieldAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance(1),false), new KickedCostCondition("{B}"), - "If {this} was kicked with its {B} kicker, it enters with a +1/+1 counter on it and with \"Pay 3 life: Regenerate Anavolver.\"", - "{this} enters with a +1/+1 counter on it and with \"Pay 3 life: Regenerate Anavolver.\""); + new AddCountersSourceEffect(CounterType.P1P1.createInstance(1), false), new KickedCostCondition("{B}"), + "If {this} was kicked with its {B} kicker, it enters with a +1/+1 counter on it and with \"Pay 3 life: Regenerate {this}.\"", + "{this} enters with a +1/+1 counter on it and with \"Pay 3 life: Regenerate {this}.\""); ((EntersBattlefieldEffect)ability2.getEffects().get(0)).addEffect(new GainAbilitySourceEffect(new SimpleActivatedAbility(new RegenerateSourceEffect(), new PayLifeCost(3)), Duration.WhileOnBattlefield)); this.addAbility(ability2); } diff --git a/Mage.Sets/src/mage/cards/a/AncientHellkite.java b/Mage.Sets/src/mage/cards/a/AncientHellkite.java index e6fa96d7495..f8c7be121be 100644 --- a/Mage.Sets/src/mage/cards/a/AncientHellkite.java +++ b/Mage.Sets/src/mage/cards/a/AncientHellkite.java @@ -1,18 +1,16 @@ - package mage.cards.a; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.common.SourceAttackingCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPredicate; import mage.target.TargetPermanent; @@ -42,7 +40,9 @@ public final class AncientHellkite extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // {R}: Ancient Hellkite deals 1 damage to target creature defending player controls. Activate this ability only if Ancient Hellkite is attacking. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new ManaCostsImpl<>("{R}"), SourceAttackingCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DamageTargetEffect(1), new ManaCostsImpl<>("{R}"), SourceAttackingCondition.instance + ); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AngelOfCondemnation.java b/Mage.Sets/src/mage/cards/a/AngelOfCondemnation.java index acfc126d0b0..91f9e12bf74 100644 --- a/Mage.Sets/src/mage/cards/a/AngelOfCondemnation.java +++ b/Mage.Sets/src/mage/cards/a/AngelOfCondemnation.java @@ -15,10 +15,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * @author emerald000 */ @@ -42,14 +45,14 @@ public final class AngelOfCondemnation extends CardImpl { new ExileReturnBattlefieldNextEndStepTargetEffect(), new ManaCostsImpl<>("{2}{W}") ); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); // {2}{W}, {T}, Exert Angel of Condemnation: Exile another target creature until Angel of Condemnation leaves the battlefield. ability = new SimpleActivatedAbility(new ExileUntilSourceLeavesEffect(), new ManaCostsImpl<>("{2}{W}")); ability.addCost(new TapSourceCost()); ability.addCost(new ExertSourceCost()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AngelicPage.java b/Mage.Sets/src/mage/cards/a/AngelicPage.java index c7a1124a229..4fc2c89dbc9 100644 --- a/Mage.Sets/src/mage/cards/a/AngelicPage.java +++ b/Mage.Sets/src/mage/cards/a/AngelicPage.java @@ -15,6 +15,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterAttackingOrBlockingCreature; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -35,7 +36,7 @@ public final class AngelicPage extends CardImpl { //{T}: Target attacking or blocking creature gets +1/+1 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(1, 1, Duration.EndOfTurn), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(new FilterAttackingOrBlockingCreature())); + ability.addTarget(new TargetPermanent(new FilterAttackingOrBlockingCreature())); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AngelsTrumpet.java b/Mage.Sets/src/mage/cards/a/AngelsTrumpet.java index 082613a8c32..225e4ca3a92 100644 --- a/Mage.Sets/src/mage/cards/a/AngelsTrumpet.java +++ b/Mage.Sets/src/mage/cards/a/AngelsTrumpet.java @@ -2,14 +2,17 @@ package mage.cards.a; import mage.MageObjectReference; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; @@ -47,7 +50,7 @@ class AngelsTrumpetTapEffect extends OneShotEffect { AngelsTrumpetTapEffect() { super(Outcome.Tap); - this.staticText = "tap all untapped creatures that player controls that didn't attack this turn. Angel's Trumpet deals damage to the player equal to the number of creatures tapped this way"; + this.staticText = "tap all untapped creatures that player controls that didn't attack this turn. {this} deals damage to the player equal to the number of creatures tapped this way"; } private AngelsTrumpetTapEffect(final AngelsTrumpetTapEffect effect) { diff --git a/Mage.Sets/src/mage/cards/a/AngusMackenzie.java b/Mage.Sets/src/mage/cards/a/AngusMackenzie.java index 1657c3914e2..8245670a062 100644 --- a/Mage.Sets/src/mage/cards/a/AngusMackenzie.java +++ b/Mage.Sets/src/mage/cards/a/AngusMackenzie.java @@ -1,28 +1,26 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.PreventAllDamageByAllPermanentsEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.game.Game; +import java.util.UUID; + /** - * * @author shieldal */ public final class AngusMackenzie extends CardImpl { public AngusMackenzie(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}{W}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{W}{U}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); @@ -30,14 +28,11 @@ public final class AngusMackenzie extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); - Effect effect = new PreventAllDamageByAllPermanentsEffect(Duration.EndOfTurn, true); - effect.setText("Prevent all combat damage that would be dealt this turn"); // {G}{W}{U}, {tap}: Prevent all combat damage that would be dealt this turn. Activate this ability only before the combat damage step. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - effect, - new ManaCostsImpl<>("{G}{W}{U}"), - BeforeCombatDamageCondition.getInstance() + new PreventAllDamageByAllPermanentsEffect(Duration.EndOfTurn, true) + .setText("Prevent all combat damage that would be dealt this turn"), + new ManaCostsImpl<>("{G}{W}{U}"), BeforeCombatDamageCondition.getInstance() ); ability.addCost(new TapSourceCost()); this.addAbility(ability); @@ -62,15 +57,15 @@ class BeforeCombatDamageCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PhaseStep phaseStep = game.getTurnStepType(); - if(phaseStep.getIndex() < PhaseStep.FIRST_COMBAT_DAMAGE.getIndex()) { - return true; - } + PhaseStep phaseStep = game.getTurnStepType(); + if (phaseStep.getIndex() < PhaseStep.FIRST_COMBAT_DAMAGE.getIndex()) { + return true; + } return false; } @Override public String toString() { - return "before the combat damage step"; + return "before the combat damage step"; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/a/AnimateWall.java b/Mage.Sets/src/mage/cards/a/AnimateWall.java index 7b852039321..a9ee511d475 100644 --- a/Mage.Sets/src/mage/cards/a/AnimateWall.java +++ b/Mage.Sets/src/mage/cards/a/AnimateWall.java @@ -34,7 +34,7 @@ public final class AnimateWall extends CardImpl { // Enchant Wall - TargetPermanent auraTarget = new TargetCreaturePermanent(filter); + TargetPermanent auraTarget = new TargetPermanent(filter); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); Ability ability = new EnchantAbility(auraTarget); diff --git a/Mage.Sets/src/mage/cards/a/Annihilate.java b/Mage.Sets/src/mage/cards/a/Annihilate.java index 20a4d080bb5..e12a50d9ffe 100644 --- a/Mage.Sets/src/mage/cards/a/Annihilate.java +++ b/Mage.Sets/src/mage/cards/a/Annihilate.java @@ -7,8 +7,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author LevelX2 @@ -20,7 +23,7 @@ public final class Annihilate extends CardImpl { // Destroy target nonblack creature. It can't be regenerated. this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } diff --git a/Mage.Sets/src/mage/cards/a/AnointedDeacon.java b/Mage.Sets/src/mage/cards/a/AnointedDeacon.java index 139850bd6ad..cc5f6f5b894 100644 --- a/Mage.Sets/src/mage/cards/a/AnointedDeacon.java +++ b/Mage.Sets/src/mage/cards/a/AnointedDeacon.java @@ -10,6 +10,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -36,7 +37,7 @@ public final class AnointedDeacon extends CardImpl { // At the beginning of combat on your turn, you may have target Vampire get +2/+0 until end of turn. Ability ability = new BeginningOfCombatTriggeredAbility( new BoostTargetEffect(2, 0, Duration.EndOfTurn), true); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AnotherRound.java b/Mage.Sets/src/mage/cards/a/AnotherRound.java index 8353ebb028f..4ede5800889 100644 --- a/Mage.Sets/src/mage/cards/a/AnotherRound.java +++ b/Mage.Sets/src/mage/cards/a/AnotherRound.java @@ -9,9 +9,9 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.targetpointer.FixedTargets; @@ -61,12 +61,8 @@ class AnotherRoundEffect extends OneShotEffect { } int xValue = GetXValue.instance.calculate(game, source, this); - TargetControlledCreaturePermanent target = - new TargetControlledCreaturePermanent( - 0, Integer.MAX_VALUE, - StaticFilters.FILTER_CONTROLLED_CREATURE, true - ); - + TargetPermanent target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE); + target.withNotTarget(true); for (int i = 0; i <= xValue; ++i) { target.clearChosen(); controller.chooseTarget(Outcome.Benefit, target, source, game); diff --git a/Mage.Sets/src/mage/cards/a/AnticausalVestige.java b/Mage.Sets/src/mage/cards/a/AnticausalVestige.java new file mode 100644 index 00000000000..f2a1d07588e --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AnticausalVestige.java @@ -0,0 +1,71 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.LandsYouControlCount; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect; +import mage.abilities.hint.common.LandsYouControlHint; +import mage.abilities.keyword.WarpAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AnticausalVestige extends CardImpl { + + private static final FilterCard filter = new FilterPermanentCard( + "a permanent card with mana value less than or equal to the number of lands you control" + ); + + static { + filter.add(AnticausalVestigePredicate.instance); + } + + public AnticausalVestige(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}"); + + this.subtype.add(SubType.ELDRAZI); + this.power = new MageInt(7); + this.toughness = new MageInt(5); + + // When this creature leaves the battlefield, draw a card, then you may put a permanent card with mana value less than or equal to the number of lands you control from your hand onto the battlefield tapped. + Ability ability = new LeavesBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)); + ability.addEffect(new PutCardFromHandOntoBattlefieldEffect(filter, false, true).concatBy(", then")); + this.addAbility(ability.addHint(LandsYouControlHint.instance)); + + // Warp {4} + this.addAbility(new WarpAbility(this, "{4}")); + } + + private AnticausalVestige(final AnticausalVestige card) { + super(card); + } + + @Override + public AnticausalVestige copy() { + return new AnticausalVestige(this); + } +} + +enum AnticausalVestigePredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return input.getObject().getManaValue() + <= LandsYouControlCount.instance.calculate(game, input.getSource(), null); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AntlerSkulkin.java b/Mage.Sets/src/mage/cards/a/AntlerSkulkin.java index 924656efdb4..0970db0a0c5 100644 --- a/Mage.Sets/src/mage/cards/a/AntlerSkulkin.java +++ b/Mage.Sets/src/mage/cards/a/AntlerSkulkin.java @@ -17,6 +17,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -41,7 +42,7 @@ public final class AntlerSkulkin extends CardImpl { // {2}: Target white creature gains persist until end of turn. Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(new PersistAbility(), Duration.EndOfTurn), new ManaCostsImpl<>("{2}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/ApexObservatory.java b/Mage.Sets/src/mage/cards/a/ApexObservatory.java index 2e6cbf27f24..47f9acc8c89 100644 --- a/Mage.Sets/src/mage/cards/a/ApexObservatory.java +++ b/Mage.Sets/src/mage/cards/a/ApexObservatory.java @@ -78,7 +78,8 @@ class ChooseCardTypeEffect extends OneShotEffect { if (permanent == null) { return false; } - ExileZone exileZone = (ExileZone) game.getExile().getExileZone(CardUtil.getExileZoneId(game, source, +1)); + // chase the exile zone down... + ExileZone exileZone = game.getState().getExile().getExileZone(CardUtil.getExileZoneId(game, source, game.getState().getZoneChangeCounter(mageObject.getId()) - 1)); if (exileZone == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/a/ApprenticeSorcerer.java b/Mage.Sets/src/mage/cards/a/ApprenticeSorcerer.java index 8576032e6e7..355e39e2a0c 100644 --- a/Mage.Sets/src/mage/cards/a/ApprenticeSorcerer.java +++ b/Mage.Sets/src/mage/cards/a/ApprenticeSorcerer.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -12,25 +10,27 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author fireshoes */ public final class ApprenticeSorcerer extends CardImpl { public ApprenticeSorcerer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(1); this.toughness = new MageInt(1); // {tap}: Apprentice Sorcerer deals 1 damage to any target. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new DamageTargetEffect(1), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DamageTargetEffect(1), new TapSourceCost(), + MyTurnBeforeAttackersDeclaredCondition.instance + ); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java b/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java index 1d8e5653f06..70aa146da9c 100644 --- a/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java +++ b/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java @@ -48,7 +48,7 @@ class ApproachOfTheSecondSunEffect extends OneShotEffect { ApproachOfTheSecondSunEffect() { super(Outcome.Win); this.staticText - = "If this spell was cast from your hand and you've cast another spell named {this} this game, you win the game. " + = "If this spell was cast from your hand and you've cast another spell named Approach of the Second Sun this game, you win the game. " + "Otherwise, put {this} into its owner's library seventh from the top and you gain 7 life."; } diff --git a/Mage.Sets/src/mage/cards/a/AquastrandSpider.java b/Mage.Sets/src/mage/cards/a/AquastrandSpider.java index c7baca16d32..061d37ceb52 100644 --- a/Mage.Sets/src/mage/cards/a/AquastrandSpider.java +++ b/Mage.Sets/src/mage/cards/a/AquastrandSpider.java @@ -16,8 +16,11 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_CREATURE_P1P1; + /** * * @author JotaPeRL @@ -38,7 +41,7 @@ public final class AquastrandSpider extends CardImpl { Ability ability = new SimpleActivatedAbility( new GainAbilityTargetEffect(ReachAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{G}")); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_P1P1)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_P1P1)); this.addAbility(ability.addCustomOutcome(Outcome.Benefit)); } diff --git a/Mage.Sets/src/mage/cards/a/ArahboRoarOfTheWorld.java b/Mage.Sets/src/mage/cards/a/ArahboRoarOfTheWorld.java index 34f18a49990..257d810031d 100644 --- a/Mage.Sets/src/mage/cards/a/ArahboRoarOfTheWorld.java +++ b/Mage.Sets/src/mage/cards/a/ArahboRoarOfTheWorld.java @@ -20,6 +20,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -56,7 +57,7 @@ public final class ArahboRoarOfTheWorld extends CardImpl { TargetController.YOU, new BoostTargetEffect(3, 3, Duration.EndOfTurn), false).withInterveningIf( SourceOnBattlefieldOrCommandZoneCondition.instance); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); ability.setAbilityWord(AbilityWord.EMINENCE); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/ArashinForemost.java b/Mage.Sets/src/mage/cards/a/ArashinForemost.java index 943af6b4556..64e6a20e7a0 100644 --- a/Mage.Sets/src/mage/cards/a/ArashinForemost.java +++ b/Mage.Sets/src/mage/cards/a/ArashinForemost.java @@ -1,7 +1,6 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; @@ -14,10 +13,11 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author fireshoes */ public final class ArashinForemost extends CardImpl { @@ -41,7 +41,7 @@ public final class ArashinForemost extends CardImpl { // Whenever Arashin Foremost enters the battlefield or attacks, another target Warrior creature you control gains double strike until end of turn. Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn)); - ability.addTarget(new TargetControlledCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/ArborColossus.java b/Mage.Sets/src/mage/cards/a/ArborColossus.java index 81ebd250b90..82edb9fc531 100644 --- a/Mage.Sets/src/mage/cards/a/ArborColossus.java +++ b/Mage.Sets/src/mage/cards/a/ArborColossus.java @@ -17,6 +17,7 @@ import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -44,7 +45,7 @@ public final class ArborColossus extends CardImpl { this.addAbility(new MonstrosityAbility("{3}{G}{G}{G}", 3)); // When Arbor Colossus becomes monstrous, destroy target creature with flying an opponent controls. Ability ability = new BecomesMonstrousSourceTriggeredAbility(new DestroyTargetEffect()); - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); ability.addTarget(target); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/ArcRunner.java b/Mage.Sets/src/mage/cards/a/ArcRunner.java index d78e7e5f3bc..a71884c9b00 100644 --- a/Mage.Sets/src/mage/cards/a/ArcRunner.java +++ b/Mage.Sets/src/mage/cards/a/ArcRunner.java @@ -1,26 +1,24 @@ - - package mage.cards.a; -import java.util.UUID; import mage.MageInt; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.keyword.HasteAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.events.GameEvent.EventType; +import mage.constants.TargetController; + +import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com */ public final class ArcRunner extends CardImpl { public ArcRunner(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); this.subtype.add(SubType.ELEMENTAL); this.subtype.add(SubType.OX); @@ -28,7 +26,10 @@ public final class ArcRunner extends CardImpl { this.toughness = new MageInt(1); this.addAbility(HasteAbility.getInstance()); - this.addAbility(new OnEventTriggeredAbility(EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new SacrificeSourceEffect())); + + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.NEXT, new SacrificeSourceEffect(), false + )); } private ArcRunner(final ArcRunner card) { diff --git a/Mage.Sets/src/mage/cards/a/ArcadesTheStrategist.java b/Mage.Sets/src/mage/cards/a/ArcadesTheStrategist.java index 511f2d74e1d..40235c7d597 100644 --- a/Mage.Sets/src/mage/cards/a/ArcadesTheStrategist.java +++ b/Mage.Sets/src/mage/cards/a/ArcadesTheStrategist.java @@ -2,7 +2,7 @@ package mage.cards.a; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderAllEffect; @@ -12,7 +12,11 @@ import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; @@ -24,7 +28,7 @@ import java.util.UUID; */ public final class ArcadesTheStrategist extends CardImpl { - private static final FilterControlledCreaturePermanent defenderSingle = new FilterControlledCreaturePermanent("a creature with defender"); + private static final FilterPermanent defenderSingle = new FilterControlledCreaturePermanent("a creature you control with defender"); private static final FilterCreaturePermanent defenderPlural = new FilterCreaturePermanent("creature you control with defender"); static { @@ -48,7 +52,7 @@ public final class ArcadesTheStrategist extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // Whenever a creature with defender you control enters, draw a card. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + this.addAbility(new EntersBattlefieldAllTriggeredAbility( new DrawCardSourceControllerEffect(1), defenderSingle )); diff --git a/Mage.Sets/src/mage/cards/a/ArcboundOverseer.java b/Mage.Sets/src/mage/cards/a/ArcboundOverseer.java index 2fd4ffb9a12..408d815fc1f 100644 --- a/Mage.Sets/src/mage/cards/a/ArcboundOverseer.java +++ b/Mage.Sets/src/mage/cards/a/ArcboundOverseer.java @@ -1,27 +1,26 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersAllEffect; import mage.abilities.keyword.ModularAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.game.events.GameEvent; + +import java.util.UUID; /** - * * @author jonubuu */ public final class ArcboundOverseer extends CardImpl { - private static final FilterControlledCreaturePermanent filter; + private static final FilterPermanent filter; static { filter = new FilterControlledCreaturePermanent("creature you control with modular"); @@ -29,16 +28,16 @@ public final class ArcboundOverseer extends CardImpl { } public ArcboundOverseer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{8}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{8}"); this.subtype.add(SubType.GOLEM); this.power = new MageInt(0); this.toughness = new MageInt(0); // At the beginning of your upkeep, put a +1/+1 counter on each creature with modular you control. - this.addAbility(new OnEventTriggeredAbility( - GameEvent.EventType.UPKEEP_STEP_PRE, - "beginning of your upkeep", - new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter))); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter) + )); + // Modular 6 this.addAbility(new ModularAbility(this, 6)); } diff --git a/Mage.Sets/src/mage/cards/a/ArchOfOrazca.java b/Mage.Sets/src/mage/cards/a/ArchOfOrazca.java index 4adb04546f0..b4c32e6729b 100644 --- a/Mage.Sets/src/mage/cards/a/ArchOfOrazca.java +++ b/Mage.Sets/src/mage/cards/a/ArchOfOrazca.java @@ -4,7 +4,7 @@ import mage.abilities.Ability; import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; @@ -12,7 +12,6 @@ import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import java.util.UUID; @@ -31,10 +30,9 @@ public final class ArchOfOrazca extends CardImpl { this.addAbility(new ColorlessManaAbility()); // {5}, {T}: Draw a card. Activate this ability only if you have the city's blessing. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new DrawCardSourceControllerEffect(1), - new GenericManaCost(5), - CitysBlessingCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DrawCardSourceControllerEffect(1), new GenericManaCost(5), CitysBlessingCondition.instance + ); ability.addCost(new TapSourceCost()); ability.addHint(CitysBlessingHint.instance); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/ArchdemonOfGreed.java b/Mage.Sets/src/mage/cards/a/ArchdemonOfGreed.java index cf60947b69f..b4c8c7a0518 100644 --- a/Mage.Sets/src/mage/cards/a/ArchdemonOfGreed.java +++ b/Mage.Sets/src/mage/cards/a/ArchdemonOfGreed.java @@ -2,10 +2,10 @@ package mage.cards.a; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -13,7 +13,6 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.common.FilterControlledPermanent; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetSacrifice; @@ -43,8 +42,9 @@ public final class ArchdemonOfGreed extends CardImpl { this.addAbility(FlyingAbility.getInstance()); this.addAbility(TrampleAbility.getInstance()); + // At the beginning of your upkeep, sacrifice a Human. If you can't, tap Archdemon of Greed and it deals 9 damage to you. - this.addAbility(new OnEventTriggeredAbility(GameEvent.EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", new ArchdemonOfGreedEffect(), false)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new ArchdemonOfGreedEffect())); } private ArchdemonOfGreed(final ArchdemonOfGreed card) { @@ -60,7 +60,7 @@ public final class ArchdemonOfGreed extends CardImpl { public ArchdemonOfGreedEffect() { super(Outcome.Damage); - this.staticText = "Sacrifice a Human. If you can't, tap {this} and it deals 9 damage to you."; + this.staticText = "sacrifice a Human. If you can't, tap {this} and it deals 9 damage to you."; } private ArchdemonOfGreedEffect(final ArchdemonOfGreedEffect effect) { diff --git a/Mage.Sets/src/mage/cards/a/ArchdemonOfPaliano.java b/Mage.Sets/src/mage/cards/a/ArchdemonOfPaliano.java index b0d10693a7e..36b1783e9a6 100644 --- a/Mage.Sets/src/mage/cards/a/ArchdemonOfPaliano.java +++ b/Mage.Sets/src/mage/cards/a/ArchdemonOfPaliano.java @@ -1,14 +1,14 @@ package mage.cards.a; import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.InfoEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.InfoEffect; import java.util.UUID; @@ -27,12 +27,12 @@ public final class ArchdemonOfPaliano extends CardImpl { // TODO: Draft specific abilities not implemented // Draft Archdemon of Paliano face up. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft Archdemon of Paliano face up - not implemented."))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft {this} face up - not implemented."))); // As long as Archdemon of Paliano is face up during the draft, you can’t look at booster packs and must draft cards at random. After you draft three cards this way, turn Archdemon of Paliano face down. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("As long as Archdemon of Paliano is face up during the draft, " + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("As long as {this} is face up during the draft, " + "you can't look at booster packs and must draft cards at random. " - + "After you draft three cards this way, turn Archdemon of Paliano face down. - not implemented."))); + + "After you draft three cards this way, turn {this} face down. - not implemented."))); // Flying this.addAbility(FlyingAbility.getInstance()); diff --git a/Mage.Sets/src/mage/cards/a/ArchdruidsCharm.java b/Mage.Sets/src/mage/cards/a/ArchdruidsCharm.java index 7f9b0caa593..5dd587a2e5e 100644 --- a/Mage.Sets/src/mage/cards/a/ArchdruidsCharm.java +++ b/Mage.Sets/src/mage/cards/a/ArchdruidsCharm.java @@ -25,6 +25,8 @@ import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import mage.util.CardUtil; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * * @author jimga150 @@ -50,7 +52,7 @@ public final class ArchdruidsCharm extends CardImpl { Mode mode2 = new Mode(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); mode2.addTarget(new TargetControlledCreaturePermanent()); mode2.addEffect(new DamageWithPowerFromOneToAnotherTargetEffect("it")); - mode2.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + mode2.addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.getSpellAbility().addMode(mode2); // * Exile target artifact or enchantment. diff --git a/Mage.Sets/src/mage/cards/a/ArchelosLagoonMystic.java b/Mage.Sets/src/mage/cards/a/ArchelosLagoonMystic.java index c7c8872e7fe..e8518bf64d4 100644 --- a/Mage.Sets/src/mage/cards/a/ArchelosLagoonMystic.java +++ b/Mage.Sets/src/mage/cards/a/ArchelosLagoonMystic.java @@ -53,7 +53,7 @@ class ArchelosLagoonMysticEffect extends ReplacementEffectImpl { super(Duration.WhileOnBattlefield, Outcome.Benefit); this.tapped = tapped; staticText = "as long as {this} is " - + (tapped ? "" : "un") + "tapped, other permanents enter the battlefield " + + (tapped ? "" : "un") + "tapped, other permanents enter " + (tapped ? "" : "un") + "tapped"; } diff --git a/Mage.Sets/src/mage/cards/a/ArchmageAscension.java b/Mage.Sets/src/mage/cards/a/ArchmageAscension.java index 2ae3ec86cfd..3437c7391de 100644 --- a/Mage.Sets/src/mage/cards/a/ArchmageAscension.java +++ b/Mage.Sets/src/mage/cards/a/ArchmageAscension.java @@ -30,7 +30,7 @@ public final class ArchmageAscension extends CardImpl { // At the beginning of each end step, if you drew two or more cards this turn, you may put a quest counter on Archmage Ascension. this.addAbility(new BeginningOfEndStepTriggeredAbility( - TargetController.EACH_PLAYER, new AddCountersSourceEffect(CounterType.QUEST.createInstance()), + TargetController.ANY, new AddCountersSourceEffect(CounterType.QUEST.createInstance()), true, ArchmageAscensionCondition.instance ), new CardsAmountDrawnThisTurnWatcher()); diff --git a/Mage.Sets/src/mage/cards/a/ArcticMerfolk.java b/Mage.Sets/src/mage/cards/a/ArcticMerfolk.java index 87c0e234f97..e55cbf13bf8 100644 --- a/Mage.Sets/src/mage/cards/a/ArcticMerfolk.java +++ b/Mage.Sets/src/mage/cards/a/ArcticMerfolk.java @@ -12,7 +12,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; -import mage.filter.StaticFilters; import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; @@ -30,9 +29,9 @@ public final class ArcticMerfolk extends CardImpl { this.toughness = new MageInt(1); // Kicker—Return a creature you control to its owner's hand. (You may return a creature you control to its owner's hand in addition to any other costs as you cast this spell.) - this.addAbility(new KickerAbility(new ReturnToHandChosenControlledPermanentCost( - new TargetControlledCreaturePermanent(1, 1, StaticFilters.FILTER_CONTROLLED_CREATURE, true) - ))); + this.addAbility(new KickerAbility( + new ReturnToHandChosenControlledPermanentCost(new TargetControlledCreaturePermanent()) + )); // If Arctic Merfolk was kicked, it enters with a +1/+1 counter on it. this.addAbility(new EntersBattlefieldAbility( diff --git a/Mage.Sets/src/mage/cards/a/ArcumsSleigh.java b/Mage.Sets/src/mage/cards/a/ArcumsSleigh.java index 8601c8c0fe5..2939f784eb1 100644 --- a/Mage.Sets/src/mage/cards/a/ArcumsSleigh.java +++ b/Mage.Sets/src/mage/cards/a/ArcumsSleigh.java @@ -8,7 +8,7 @@ import mage.abilities.condition.common.DefendingPlayerControlsNoSourceCondition; import mage.abilities.condition.common.IsPhaseCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; @@ -41,7 +41,7 @@ public final class ArcumsSleigh extends CardImpl { new DefendingPlayerControlsNoSourceCondition(filter) // Only if defending player controls a snow land ); - Ability ability = new ConditionalActivatedAbility( + Ability ability = new ActivateIfConditionActivatedAbility( new GainAbilityTargetEffect(VigilanceAbility.getInstance()), new GenericManaCost(2), condition); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/a/ArdenAngel.java b/Mage.Sets/src/mage/cards/a/ArdenAngel.java index b67b4dc5947..2742b2f918f 100644 --- a/Mage.Sets/src/mage/cards/a/ArdenAngel.java +++ b/Mage.Sets/src/mage/cards/a/ArdenAngel.java @@ -49,7 +49,7 @@ class ArdenAngelEffect extends OneShotEffect { ArdenAngelEffect() { super(Outcome.Benefit); - this.staticText = "roll a four-sided die. If the result is 1, return {this} from your graveyard to the battlefield"; + this.staticText = "roll a four-sided die. If the result is 1, return this card from your graveyard to the battlefield"; } private ArdenAngelEffect(final ArdenAngelEffect effect) { diff --git a/Mage.Sets/src/mage/cards/a/ArenaAthlete.java b/Mage.Sets/src/mage/cards/a/ArenaAthlete.java index 2e79284fd8b..5372fa8fddf 100644 --- a/Mage.Sets/src/mage/cards/a/ArenaAthlete.java +++ b/Mage.Sets/src/mage/cards/a/ArenaAthlete.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.effects.common.combat.CantBlockTargetEffect; @@ -11,17 +9,17 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.filter.StaticFilters; -import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; /** - * * @author Plopman */ public final class ArenaAthlete extends CardImpl { - + public ArenaAthlete(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); this.subtype.add(SubType.HUMAN); this.power = new MageInt(2); @@ -29,8 +27,7 @@ public final class ArenaAthlete extends CardImpl { // Heroic Whenever you cast a spell that targets Arena Athlete, target creature an opponent controls can't block this turn. Ability ability = new HeroicAbility(new CantBlockTargetEffect(Duration.EndOfTurn)); - TargetCreaturePermanent target = new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE); - ability.addTarget(target); + ability.addTarget(new TargetOpponentsCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/ArgentSphinx.java b/Mage.Sets/src/mage/cards/a/ArgentSphinx.java index 807b1241d4e..c23ce165654 100644 --- a/Mage.Sets/src/mage/cards/a/ArgentSphinx.java +++ b/Mage.Sets/src/mage/cards/a/ArgentSphinx.java @@ -37,13 +37,9 @@ public final class ArgentSphinx extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Metalcraft — {U}: Exile Argent Sphinx. Return it to the battlefield under your control at the beginning of the next end step. Activate this ability only if you control three or more artifacts. - Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new ArgentSphinxEffect(), - new ManaCostsImpl<>("{U}"), MetalcraftCondition.instance - ); - ability.setAbilityWord(AbilityWord.METALCRAFT); - ability.addHint(MetalcraftHint.instance); - this.addAbility(ability); + this.addAbility(new ActivateIfConditionActivatedAbility( + new ArgentSphinxEffect(), new ManaCostsImpl<>("{U}"), MetalcraftCondition.instance + ).setAbilityWord(AbilityWord.METALCRAFT).addHint(MetalcraftHint.instance)); } private ArgentSphinx(final ArgentSphinx card) { diff --git a/Mage.Sets/src/mage/cards/a/AriaOfFlame.java b/Mage.Sets/src/mage/cards/a/AriaOfFlame.java index 2856347067a..ae2fbda0afd 100644 --- a/Mage.Sets/src/mage/cards/a/AriaOfFlame.java +++ b/Mage.Sets/src/mage/cards/a/AriaOfFlame.java @@ -5,17 +5,15 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CountersSourceCount; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.GainLifeAllEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; +import mage.constants.TargetController; import mage.counters.CounterType; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; import mage.target.common.TargetPlayerOrPlaneswalker; import java.util.UUID; @@ -31,7 +29,7 @@ public final class AriaOfFlame extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); // When Aria of Flame enters the battlefield, each opponent gains 10 life. - this.addAbility(new EntersBattlefieldTriggeredAbility(new AriaOfFlameEffect())); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeAllEffect(10, TargetController.OPPONENT))); // Whenever you cast an instant or sorcery spell, put a verse counter on Aria of Flame, then it deals damage equal to the number of verse counters on it to target player or planeswalker. Ability ability = new SpellCastControllerTriggeredAbility( @@ -54,31 +52,3 @@ public final class AriaOfFlame extends CardImpl { return new AriaOfFlame(this); } } - -class AriaOfFlameEffect extends OneShotEffect { - - AriaOfFlameEffect() { - super(Outcome.Benefit); - staticText = "each opponent gains 10 life"; - } - - private AriaOfFlameEffect(AriaOfFlameEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - for (UUID playerId : game.getOpponents(source.getControllerId())) { - Player player = game.getPlayer(playerId); - if (player != null) { - player.gainLife(10, game, source); - } - } - return true; - } - - @Override - public AriaOfFlameEffect copy() { - return new AriaOfFlameEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/ArmTheCathars.java b/Mage.Sets/src/mage/cards/a/ArmTheCathars.java index f81384f8255..13d4cf1d25f 100644 --- a/Mage.Sets/src/mage/cards/a/ArmTheCathars.java +++ b/Mage.Sets/src/mage/cards/a/ArmTheCathars.java @@ -8,7 +8,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.other.AnotherTargetPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.targetpointer.EachTargetPointer; import mage.target.targetpointer.SecondTargetPointer; import mage.target.targetpointer.ThirdTargetPointer; @@ -35,28 +35,22 @@ public final class ArmTheCathars extends CardImpl { // Until end of turn, target creature gets +3/+3, up to one other target creature gets +2/+2, and up to one other target creature gets +1/+1. Those creatures gain vigilance until end of turn. this.getSpellAbility().addEffect(new BoostTargetEffect(3, 3) .setText("until end of turn, target creature gets +3/+3")); - TargetCreaturePermanent target1 = new TargetCreaturePermanent(filter1); - target1.setTargetTag(1); - this.getSpellAbility().addTarget(target1.withChooseHint("+3/+3")); + this.getSpellAbility().addTarget(new TargetPermanent(filter1).setTargetTag(1).withChooseHint("+3/+3")); this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2) .setTargetPointer(new SecondTargetPointer()) .setText(", up to one other target creature gets +2/+2")); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(0, 1, filter2, false); - target2.setTargetTag(2); - this.getSpellAbility().addTarget(target2.withChooseHint("+2/+2")); + this.getSpellAbility().addTarget(new TargetPermanent(0, 1, filter2).setTargetTag(2).withChooseHint("+2/+2")); this.getSpellAbility().addEffect(new BoostTargetEffect(1, 1) .setTargetPointer(new ThirdTargetPointer()) .setText(", and up to one other target creature gets +1/+1")); - TargetCreaturePermanent target3 = new TargetCreaturePermanent(0, 1, filter3, false); - target3.setTargetTag(3); - this.getSpellAbility().addTarget(target3.withChooseHint("+1/+1")); + this.getSpellAbility().addTarget(new TargetPermanent(0, 1, filter3).setTargetTag(3).withChooseHint("+1/+1")); this.getSpellAbility().addEffect( new GainAbilityTargetEffect(VigilanceAbility.getInstance()) - .setTargetPointer(new EachTargetPointer()) - .setText("Those creatures gain vigilance until end of turn")); + .setTargetPointer(new EachTargetPointer()) + .setText("Those creatures gain vigilance until end of turn")); } private ArmTheCathars(final ArmTheCathars card) { diff --git a/Mage.Sets/src/mage/cards/a/ArmageddonClock.java b/Mage.Sets/src/mage/cards/a/ArmageddonClock.java index e373888d3ca..8d02db5fa89 100644 --- a/Mage.Sets/src/mage/cards/a/ArmageddonClock.java +++ b/Mage.Sets/src/mage/cards/a/ArmageddonClock.java @@ -1,19 +1,21 @@ package mage.cards.a; -import mage.abilities.ActivatedAbilityImpl; -import mage.abilities.triggers.BeginningOfDrawTriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.IsStepCondition; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.dynamicvalue.common.CountersSourceCount; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; +import mage.abilities.triggers.BeginningOfDrawTriggeredAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.constants.TargetController; import mage.counters.CounterType; import java.util.UUID; @@ -23,24 +25,24 @@ import java.util.UUID; */ public final class ArmageddonClock extends CardImpl { + private static final Condition condition = new IsStepCondition(PhaseStep.UPKEEP, false); + public ArmageddonClock(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}"); // At the beginning of your upkeep, put a doom counter on Armageddon Clock. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.DOOM.createInstance(), StaticValue.get(1), true))); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.DOOM.createInstance()))); // At the beginning of your draw step, Armageddon Clock deals damage equal to the number of doom counters on it to each player. - this.addAbility(new BeginningOfDrawTriggeredAbility(new DamagePlayersEffect(Outcome.Damage, new CountersSourceCount(CounterType.DOOM)) - .setText("{this} deals damage equal to the number of doom counters on it to each player"), false)); + this.addAbility(new BeginningOfDrawTriggeredAbility( + new DamagePlayersEffect(Outcome.Damage, new CountersSourceCount(CounterType.DOOM)) + .setText("{this} deals damage equal to the number of doom counters on it to each player"), false + )); // {4}: Remove a doom counter from Armageddon Clock. Any player may activate this ability but only during any upkeep step. - ActivatedAbilityImpl ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new RemoveCounterSourceEffect(CounterType.DOOM.createInstance()), new ManaCostsImpl<>("{4}"), new IsStepCondition(PhaseStep.UPKEEP, false), - "{4}: Remove a doom counter from {this}. Any player may activate this ability but only during any upkeep step."); - - ability.setMayActivate(TargetController.ANY); - this.addAbility(ability); - + this.addAbility(new ActivateIfConditionActivatedAbility( + new RemoveCounterSourceEffect(CounterType.DOOM.createInstance()), new GenericManaCost(4), condition + ).withConditionText("any player may activate this ability but only during any upkeep step").setMayActivate(TargetController.ANY)); } private ArmageddonClock(final ArmageddonClock card) { diff --git a/Mage.Sets/src/mage/cards/a/ArmedProtocolDroid.java b/Mage.Sets/src/mage/cards/a/ArmedProtocolDroid.java index 861c904c6ec..45928233f06 100644 --- a/Mage.Sets/src/mage/cards/a/ArmedProtocolDroid.java +++ b/Mage.Sets/src/mage/cards/a/ArmedProtocolDroid.java @@ -14,6 +14,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class ArmedProtocolDroid extends CardImpl { // When {this} enters, target nonartifact creature gets -2/-0 until end of turn. Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-2, 0, Duration.EndOfTurn), false); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Repair 3 diff --git a/Mage.Sets/src/mage/cards/a/ArmorOfThorns.java b/Mage.Sets/src/mage/cards/a/ArmorOfThorns.java index 6f2740c6efd..9017a215ad3 100644 --- a/Mage.Sets/src/mage/cards/a/ArmorOfThorns.java +++ b/Mage.Sets/src/mage/cards/a/ArmorOfThorns.java @@ -15,6 +15,8 @@ import mage.filter.StaticFilters; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author LoneFox @@ -29,7 +31,7 @@ public final class ArmorOfThorns extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.ALL, new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame))); this.addAbility(new SacrificeIfCastAtInstantTimeTriggeredAbility()); // Enchant nonblack creature - TargetPermanent auraTarget = new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK); + TargetPermanent auraTarget = new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); Ability ability = new EnchantAbility(auraTarget); diff --git a/Mage.Sets/src/mage/cards/a/ArtfulTakedown.java b/Mage.Sets/src/mage/cards/a/ArtfulTakedown.java index 0cd8dd68646..e661ab5ce18 100644 --- a/Mage.Sets/src/mage/cards/a/ArtfulTakedown.java +++ b/Mage.Sets/src/mage/cards/a/ArtfulTakedown.java @@ -8,6 +8,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -33,14 +34,14 @@ public final class ArtfulTakedown extends CardImpl { this.getSpellAbility().addEffect( new TapTargetEffect("tap target creature") ); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter1).withChooseHint("tap")); + this.getSpellAbility().addTarget(new TargetPermanent(filter1).withChooseHint("tap")); // • Target creature gets -2/-4 until end of turn. Mode mode = new Mode( new BoostTargetEffect(-2, -4, Duration.EndOfTurn) .setText("target creature gets -2/-4 until end of turn") ); - mode.addTarget(new TargetCreaturePermanent(filter2).withChooseHint("gets -2/-4 until end of turn")); + mode.addTarget(new TargetPermanent(filter2).withChooseHint("gets -2/-4 until end of turn")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/ArtifactPossession.java b/Mage.Sets/src/mage/cards/a/ArtifactPossession.java index 5b0981dc1c0..981e1a181c6 100644 --- a/Mage.Sets/src/mage/cards/a/ArtifactPossession.java +++ b/Mage.Sets/src/mage/cards/a/ArtifactPossession.java @@ -1,7 +1,6 @@ package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.common.AttachEffect; @@ -19,6 +18,8 @@ import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetArtifactPermanent; +import java.util.UUID; + /** * * @author MarcoMarin @@ -87,6 +88,6 @@ class AbilityActivatedTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever enchanted artifact becomes tapped or a player activates an ability of enchanted artifact without {T} in its activation cost, Artifact Possession deals 2 damage to that artifact's controller."; + return "Whenever enchanted artifact becomes tapped or a player activates an ability of enchanted artifact without {T} in its activation cost, {this} deals 2 damage to that artifact's controller."; } } diff --git a/Mage.Sets/src/mage/cards/a/ArtilleryBlast.java b/Mage.Sets/src/mage/cards/a/ArtilleryBlast.java index 10172041867..8688ff875fc 100644 --- a/Mage.Sets/src/mage/cards/a/ArtilleryBlast.java +++ b/Mage.Sets/src/mage/cards/a/ArtilleryBlast.java @@ -12,6 +12,7 @@ import mage.constants.AbilityWord; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -32,7 +33,7 @@ public final class ArtilleryBlast extends CardImpl { // Domain--Artillery Blast deals X damage to target tapped creature, where X is 1 plus the number of basic land types among lands you control. this.getSpellAbility().addEffect(new DamageTargetEffect(new IntPlusDynamicValue(1, DomainValue.REGULAR)) .setText("{this} deals X damage to target tapped creature, where X is 1 plus the number of basic land types among lands you control")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().setAbilityWord(AbilityWord.DOMAIN); this.getSpellAbility().addHint(DomainHint.instance); } diff --git a/Mage.Sets/src/mage/cards/a/AshenGhoul.java b/Mage.Sets/src/mage/cards/a/AshenGhoul.java index 739c9488d1e..5e9a82f57e3 100644 --- a/Mage.Sets/src/mage/cards/a/AshenGhoul.java +++ b/Mage.Sets/src/mage/cards/a/AshenGhoul.java @@ -1,12 +1,11 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; import mage.abilities.keyword.HasteAbility; import mage.cards.Card; @@ -19,8 +18,9 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class AshenGhoul extends CardImpl { @@ -36,7 +36,7 @@ public final class AshenGhoul extends CardImpl { this.addAbility(HasteAbility.getInstance()); // {B}: Return Ashen Ghoul from your graveyard to the battlefield. Activate this ability only during your upkeep and only if three or more creature cards are above Ashen Ghoul. - this.addAbility(new ConditionalActivatedAbility( + this.addAbility(new ActivateIfConditionActivatedAbility( Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(), new ManaCostsImpl<>("{B}"), @@ -85,6 +85,6 @@ enum AshenGhoulCondition implements Condition { @Override public String toString() { - return "only during your upkeep and only if three or more creature cards are above {this}"; + return "during your upkeep and only if three or more creature cards are above this card"; } } diff --git a/Mage.Sets/src/mage/cards/a/AshnodsTransmogrant.java b/Mage.Sets/src/mage/cards/a/AshnodsTransmogrant.java index d0a58762aa3..ad1872df42b 100644 --- a/Mage.Sets/src/mage/cards/a/AshnodsTransmogrant.java +++ b/Mage.Sets/src/mage/cards/a/AshnodsTransmogrant.java @@ -17,6 +17,7 @@ import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -41,7 +42,7 @@ public final class AshnodsTransmogrant extends CardImpl { Effect effect = new AddCardTypeTargetEffect(Duration.WhileOnBattlefield, CardType.ARTIFACT); effect.setText("That creature becomes an artifact in addition to its other types"); ability.addEffect(effect); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AshrootAnimist.java b/Mage.Sets/src/mage/cards/a/AshrootAnimist.java index 7de59b0f0a3..e7cabaea139 100644 --- a/Mage.Sets/src/mage/cards/a/AshrootAnimist.java +++ b/Mage.Sets/src/mage/cards/a/AshrootAnimist.java @@ -14,19 +14,17 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.filter.StaticFilters; import mage.target.TargetPermanent; -import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; /** - * * @author ciaccona007 */ public final class AshrootAnimist extends CardImpl { public AshrootAnimist(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{G}"); - + this.subtype.add(SubType.LIZARD); this.subtype.add(SubType.DRUID); this.power = new MageInt(4); @@ -40,9 +38,9 @@ public final class AshrootAnimist extends CardImpl { new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn).setText("another target creature you control gains trample"), false ); - ability.addEffect( new BoostTargetEffect(SourcePermanentPowerValue.NOT_NEGATIVE, SourcePermanentPowerValue.NOT_NEGATIVE, Duration.EndOfTurn) + ability.addEffect(new BoostTargetEffect(SourcePermanentPowerValue.NOT_NEGATIVE, SourcePermanentPowerValue.NOT_NEGATIVE, Duration.EndOfTurn) .setText("and gets +X/+X until end of turn, where X is this creature's power")); - ability.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/Asphyxiate.java b/Mage.Sets/src/mage/cards/a/Asphyxiate.java index adf83884a2a..794f196ea4b 100644 --- a/Mage.Sets/src/mage/cards/a/Asphyxiate.java +++ b/Mage.Sets/src/mage/cards/a/Asphyxiate.java @@ -8,6 +8,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -28,7 +29,7 @@ public final class Asphyxiate extends CardImpl { // Destroy target untapped creature. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private Asphyxiate(final Asphyxiate card) { diff --git a/Mage.Sets/src/mage/cards/a/Assassinate.java b/Mage.Sets/src/mage/cards/a/Assassinate.java index 63c1d2eca44..8c8ae1ea963 100644 --- a/Mage.Sets/src/mage/cards/a/Assassinate.java +++ b/Mage.Sets/src/mage/cards/a/Assassinate.java @@ -9,6 +9,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -26,7 +27,7 @@ public final class Assassinate extends CardImpl { public Assassinate(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{B}"); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/a/AssassinsBlade.java b/Mage.Sets/src/mage/cards/a/AssassinsBlade.java index 9db8d9510d6..501b3e06b28 100644 --- a/Mage.Sets/src/mage/cards/a/AssassinsBlade.java +++ b/Mage.Sets/src/mage/cards/a/AssassinsBlade.java @@ -16,6 +16,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.permanent.AttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.watchers.common.PlayerAttackedStepWatcher; @@ -45,7 +46,7 @@ public final class AssassinsBlade extends CardImpl { // Destroy target nonblack attacking creature. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private AssassinsBlade(final AssassinsBlade card) { diff --git a/Mage.Sets/src/mage/cards/a/AssaultBattery.java b/Mage.Sets/src/mage/cards/a/AssaultBattery.java index 4c7a4ddba94..58bd8fa7d39 100644 --- a/Mage.Sets/src/mage/cards/a/AssaultBattery.java +++ b/Mage.Sets/src/mage/cards/a/AssaultBattery.java @@ -1,7 +1,6 @@ package mage.cards.a; -import java.util.UUID; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DamageTargetEffect; @@ -12,6 +11,8 @@ import mage.constants.SpellAbilityType; import mage.game.permanent.token.ElephantToken; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + public final class AssaultBattery extends SplitCard { public AssaultBattery(UUID ownerId, CardSetInfo setInfo) { @@ -20,7 +21,7 @@ public final class AssaultBattery extends SplitCard { // Assault // Assault deals 2 damage to any target. Effect effect = new DamageTargetEffect(2); - effect.setText("Assault deals 2 damage to any target"); + effect.setText("{this} deals 2 damage to any target"); getLeftHalfCard().getSpellAbility().addEffect(effect); getLeftHalfCard().getSpellAbility().addTarget(new TargetAnyTarget()); diff --git a/Mage.Sets/src/mage/cards/a/AssaultFormation.java b/Mage.Sets/src/mage/cards/a/AssaultFormation.java index 5b4e7179c4c..9f546d6edd0 100644 --- a/Mage.Sets/src/mage/cards/a/AssaultFormation.java +++ b/Mage.Sets/src/mage/cards/a/AssaultFormation.java @@ -15,6 +15,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -38,7 +39,7 @@ public final class AssaultFormation extends CardImpl { // {G}: Target creature with defender can attack this turn as though it didn't have defender. Ability ability = new SimpleActivatedAbility(new CanAttackAsThoughItDidntHaveDefenderTargetEffect(Duration.EndOfTurn), new ManaCostsImpl<>("{G}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // {2}{G}: Creatures you control get +0/+1 until end of turn. diff --git a/Mage.Sets/src/mage/cards/a/AstromechDroid.java b/Mage.Sets/src/mage/cards/a/AstromechDroid.java index b856816dbb0..02ead94b018 100644 --- a/Mage.Sets/src/mage/cards/a/AstromechDroid.java +++ b/Mage.Sets/src/mage/cards/a/AstromechDroid.java @@ -16,6 +16,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -44,7 +45,7 @@ public final class AstromechDroid extends CardImpl { new TapSourceCost()); ability.addEffect(new GainAbilityTargetEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn) .setText("and gains vigilance until end of turn")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Repair 4 diff --git a/Mage.Sets/src/mage/cards/a/AsylumVisitor.java b/Mage.Sets/src/mage/cards/a/AsylumVisitor.java index 3d01de1043e..2e9eafc3189 100644 --- a/Mage.Sets/src/mage/cards/a/AsylumVisitor.java +++ b/Mage.Sets/src/mage/cards/a/AsylumVisitor.java @@ -34,7 +34,7 @@ public final class AsylumVisitor extends CardImpl { // At the beginning of each player's upkeep, if that player has no cards in hand, you draw a card and you lose 1 life. Ability ability = new BeginningOfUpkeepTriggeredAbility( - TargetController.ANY, new DrawCardSourceControllerEffect(1, true), false + TargetController.EACH_PLAYER, new DrawCardSourceControllerEffect(1, true), false ).withInterveningIf(condition); ability.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and")); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/AtarkaBeastbreaker.java b/Mage.Sets/src/mage/cards/a/AtarkaBeastbreaker.java index e7013ddb2af..97681efaafd 100644 --- a/Mage.Sets/src/mage/cards/a/AtarkaBeastbreaker.java +++ b/Mage.Sets/src/mage/cards/a/AtarkaBeastbreaker.java @@ -1,38 +1,36 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.FormidableCondition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class AtarkaBeastbreaker extends CardImpl { public AtarkaBeastbreaker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WARRIOR); this.power = new MageInt(2); this.toughness = new MageInt(2); // Formidable — {4}{G}: Atarka Beastbreaker gets +4/+4 until end of turn. Activate this only if creatures you control have total power 8 or greater. - Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new BoostSourceEffect(4,4, Duration.EndOfTurn), - new ManaCostsImpl<>("{4}{G}"), - FormidableCondition.instance); - ability.setAbilityWord(AbilityWord.FORMIDABLE); - this.addAbility(ability); + this.addAbility(new ActivateIfConditionActivatedAbility( + new BoostSourceEffect(4, 4, Duration.EndOfTurn), + new ManaCostsImpl<>("{4}{G}"), FormidableCondition.instance + ).setAbilityWord(AbilityWord.FORMIDABLE)); } private AtarkaBeastbreaker(final AtarkaBeastbreaker card) { diff --git a/Mage.Sets/src/mage/cards/a/AtarkaPummeler.java b/Mage.Sets/src/mage/cards/a/AtarkaPummeler.java index a42c030a66a..c01968c39af 100644 --- a/Mage.Sets/src/mage/cards/a/AtarkaPummeler.java +++ b/Mage.Sets/src/mage/cards/a/AtarkaPummeler.java @@ -1,8 +1,6 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.FormidableCondition; import mage.abilities.costs.mana.ManaCostsImpl; @@ -10,31 +8,30 @@ import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.keyword.MenaceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class AtarkaPummeler extends CardImpl { public AtarkaPummeler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); this.subtype.add(SubType.OGRE); this.subtype.add(SubType.WARRIOR); this.power = new MageInt(4); this.toughness = new MageInt(5); // Formidable — {3}{R}{R}: Creatures you control gain menace until end of turn. Activate this ability only if creature you control have total power 8 or greater. (They can't be blocked except by two or more creatures.) - Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new GainAbilityAllEffect(new MenaceAbility(), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES), - new ManaCostsImpl<>("{3}{R}{R}"), - FormidableCondition.instance); - ability.setAbilityWord(AbilityWord.FORMIDABLE); - this.addAbility(ability); - + this.addAbility(new ActivateIfConditionActivatedAbility(new GainAbilityAllEffect( + new MenaceAbility(false), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES + ), new ManaCostsImpl<>("{3}{R}{R}"), FormidableCondition.instance).setAbilityWord(AbilityWord.FORMIDABLE)); } private AtarkaPummeler(final AtarkaPummeler card) { diff --git a/Mage.Sets/src/mage/cards/a/AtraxiWarden.java b/Mage.Sets/src/mage/cards/a/AtraxiWarden.java index 00c4b0e3474..8103813cf06 100644 --- a/Mage.Sets/src/mage/cards/a/AtraxiWarden.java +++ b/Mage.Sets/src/mage/cards/a/AtraxiWarden.java @@ -13,7 +13,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -28,7 +28,6 @@ public final class AtraxiWarden extends CardImpl { filter.add(TappedPredicate.TAPPED); } - public AtraxiWarden(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}"); @@ -42,7 +41,7 @@ public final class AtraxiWarden extends CardImpl { // When Atraxi Warden enters the battlefield, exile up to one target tapped creature. Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetEffect()); - ability.addTarget(new TargetCreaturePermanent(0, 1, filter, false)); + ability.addTarget(new TargetPermanent(0, 1, filter)); this.addAbility(ability); // Suspend 5--{1}{W} diff --git a/Mage.Sets/src/mage/cards/a/Attrition.java b/Mage.Sets/src/mage/cards/a/Attrition.java index c662c24a2ef..bda95864562 100644 --- a/Mage.Sets/src/mage/cards/a/Attrition.java +++ b/Mage.Sets/src/mage/cards/a/Attrition.java @@ -10,9 +10,12 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ColoredManaSymbol; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author Backfir3 @@ -25,7 +28,7 @@ public final class Attrition extends CardImpl { //{B}, Sacrifice a creature: Destroy target nonblack creature. SimpleActivatedAbility ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ColoredManaCost(ColoredManaSymbol.B)); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK).withChooseHint("to destroy")); + ability.addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK).withChooseHint("to destroy")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AtzocanArcher.java b/Mage.Sets/src/mage/cards/a/AtzocanArcher.java index 4e7ca252211..dda10676363 100644 --- a/Mage.Sets/src/mage/cards/a/AtzocanArcher.java +++ b/Mage.Sets/src/mage/cards/a/AtzocanArcher.java @@ -13,8 +13,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * * @author TheElk801 @@ -37,7 +40,7 @@ public final class AtzocanArcher extends CardImpl { effect.setText("you may have it fight another target creature. " + "(Each deals damage equal to its power to the other.)"); Ability ability = new EntersBattlefieldTriggeredAbility(effect, true); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AugurIlVec.java b/Mage.Sets/src/mage/cards/a/AugurIlVec.java index 82ee55d7db2..36f5a8ac220 100644 --- a/Mage.Sets/src/mage/cards/a/AugurIlVec.java +++ b/Mage.Sets/src/mage/cards/a/AugurIlVec.java @@ -1,28 +1,25 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.SacrificeSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.keyword.ShadowAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.PhaseStep; import mage.constants.SubType; -import mage.constants.Zone; + +import java.util.UUID; /** - * * @author fireshoes */ public final class AugurIlVec extends CardImpl { public AugurIlVec(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); this.power = new MageInt(1); @@ -30,12 +27,11 @@ public final class AugurIlVec extends CardImpl { // Shadow this.addAbility(ShadowAbility.getInstance()); - + // Sacrifice Augur il-Vec: You gain 4 life. Activate this ability only during your upkeep. - this.addAbility(new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new GainLifeEffect(4), - new SacrificeSourceCost(), - new IsStepCondition(PhaseStep.UPKEEP))); + this.addAbility(new ActivateIfConditionActivatedAbility( + new GainLifeEffect(4), new SacrificeSourceCost(), IsStepCondition.getMyUpkeep() + )); } private AugurIlVec(final AugurIlVec card) { diff --git a/Mage.Sets/src/mage/cards/a/AugurOfSkulls.java b/Mage.Sets/src/mage/cards/a/AugurOfSkulls.java index 249ab1a1faa..ac611228f2f 100644 --- a/Mage.Sets/src/mage/cards/a/AugurOfSkulls.java +++ b/Mage.Sets/src/mage/cards/a/AugurOfSkulls.java @@ -1,32 +1,29 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.RegenerateSourceEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.PhaseStep; import mage.constants.SubType; -import mage.constants.Zone; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author fireshoes */ public final class AugurOfSkulls extends CardImpl { public AugurOfSkulls(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); this.subtype.add(SubType.SKELETON); this.subtype.add(SubType.WIZARD); this.power = new MageInt(1); @@ -34,11 +31,10 @@ public final class AugurOfSkulls extends CardImpl { // {1}{B}: Regenerate Augur of Skulls. this.addAbility(new SimpleActivatedAbility(new RegenerateSourceEffect(), new ManaCostsImpl<>("{1}{B}"))); + // Sacrifice Augur of Skulls: Target player discards two cards. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new DiscardTargetEffect(2), - new SacrificeSourceCost(), - new IsStepCondition(PhaseStep.UPKEEP) + Ability ability = new ActivateIfConditionActivatedAbility( + new DiscardTargetEffect(2), new SacrificeSourceCost(), IsStepCondition.getMyUpkeep() ); ability.addTarget(new TargetPlayer()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/AuntiesSnitch.java b/Mage.Sets/src/mage/cards/a/AuntiesSnitch.java index cc27792c2ed..7f05cabec0f 100644 --- a/Mage.Sets/src/mage/cards/a/AuntiesSnitch.java +++ b/Mage.Sets/src/mage/cards/a/AuntiesSnitch.java @@ -44,7 +44,7 @@ public final class AuntiesSnitch extends CardImpl { // Whenever a Goblin or Rogue you control deals combat damage to a player, if Auntie's Snitch is in your graveyard, you may return Auntie's Snitch to your hand. this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility(Zone.GRAVEYARD, - new ReturnSourceFromGraveyardToHandEffect().setText("return {this} to your hand"), + new ReturnSourceFromGraveyardToHandEffect().setText("return this card to your hand"), filter, true, SetTargetPointer.NONE, true, false ).withInterveningIf(SourceInGraveyardCondition.instance)); } diff --git a/Mage.Sets/src/mage/cards/a/AuraOfDominion.java b/Mage.Sets/src/mage/cards/a/AuraOfDominion.java index 9b68395a9f7..33795e7c34a 100644 --- a/Mage.Sets/src/mage/cards/a/AuraOfDominion.java +++ b/Mage.Sets/src/mage/cards/a/AuraOfDominion.java @@ -1,8 +1,5 @@ - - package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapTargetCost; @@ -15,35 +12,29 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; +import mage.filter.StaticFilters; import mage.target.TargetPermanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * @author Loki */ public final class AuraOfDominion extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); - - static { - filter.add(TappedPredicate.UNTAPPED); - } - - public AuraOfDominion(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}{U}"); this.subtype.add(SubType.AURA); TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Untap)); this.addAbility(new EnchantAbility(auraTarget)); + Ability ability = new SimpleActivatedAbility(new UntapAttachedEffect(), new GenericManaCost(1)); - ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, false))); + ability.addCost(new TapTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AuriokSiegeSled.java b/Mage.Sets/src/mage/cards/a/AuriokSiegeSled.java index bb360508011..46e06b9eefb 100644 --- a/Mage.Sets/src/mage/cards/a/AuriokSiegeSled.java +++ b/Mage.Sets/src/mage/cards/a/AuriokSiegeSled.java @@ -13,8 +13,11 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE; + /** * * @author Galatolol @@ -31,7 +34,7 @@ public final class AuriokSiegeSled extends CardImpl { MustBeBlockedByTargetSourceEffect effect = new MustBeBlockedByTargetSourceEffect(Duration.EndOfTurn); effect.setText("target artifact creature blocks {this} this turn if able"); Ability ability1 = new SimpleActivatedAbility(effect, new GenericManaCost(1)); - ability1.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE)); + ability1.addTarget(new TargetPermanent(FILTER_PERMANENT_ARTIFACT_CREATURE)); this.addAbility(ability1); // {1}: Target artifact creature can't block Auriok Siege Sled this turn. @@ -39,7 +42,7 @@ public final class AuriokSiegeSled extends CardImpl { new CantBeBlockedByTargetSourceEffect(Duration.EndOfTurn), new GenericManaCost(1) ); - ability2.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE)); + ability2.addTarget(new TargetPermanent(FILTER_PERMANENT_ARTIFACT_CREATURE)); this.addAbility(ability2); } diff --git a/Mage.Sets/src/mage/cards/a/AutomatedAssemblyLine.java b/Mage.Sets/src/mage/cards/a/AutomatedAssemblyLine.java index 3bf19b3aff3..ba1f028e7de 100644 --- a/Mage.Sets/src/mage/cards/a/AutomatedAssemblyLine.java +++ b/Mage.Sets/src/mage/cards/a/AutomatedAssemblyLine.java @@ -11,7 +11,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; -import mage.game.permanent.token.RobotToken; +import mage.game.permanent.token.Robot33Token; /** * @author Cguy7777 @@ -27,7 +27,7 @@ public final class AutomatedAssemblyLine extends CardImpl { // Pay {E}{E}{E}: Create a tapped 3/3 colorless Robot artifact creature token. this.addAbility(new SimpleActivatedAbility( - new CreateTokenEffect(new RobotToken(), 1, true), + new CreateTokenEffect(new Robot33Token(), 1, true), new PayEnergyCost(3))); } diff --git a/Mage.Sets/src/mage/cards/a/AutumnWillow.java b/Mage.Sets/src/mage/cards/a/AutumnWillow.java index a85dc1b5875..065302601e9 100644 --- a/Mage.Sets/src/mage/cards/a/AutumnWillow.java +++ b/Mage.Sets/src/mage/cards/a/AutumnWillow.java @@ -1,7 +1,6 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -15,6 +14,8 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPlayer; +import java.util.UUID; + /** * * @author L_J @@ -51,7 +52,7 @@ class AutumnWillowEffect extends AsThoughEffectImpl { AutumnWillowEffect() { super(AsThoughEffectType.SHROUD, Duration.EndOfTurn, Outcome.Benefit); - staticText = "Until end of turn, Autumn Willow can be the target of spells and abilities controlled by target player as though it didn't have shroud"; + staticText = "Until end of turn, {this} can be the target of spells and abilities controlled by target player as though it didn't have shroud"; } private AutumnWillowEffect(final AutumnWillowEffect effect) { diff --git a/Mage.Sets/src/mage/cards/a/AvacynGuardianAngel.java b/Mage.Sets/src/mage/cards/a/AvacynGuardianAngel.java index 9ab15663f99..f29f15689ee 100644 --- a/Mage.Sets/src/mage/cards/a/AvacynGuardianAngel.java +++ b/Mage.Sets/src/mage/cards/a/AvacynGuardianAngel.java @@ -18,11 +18,14 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetPlayerOrPlaneswalker; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * @author LevelX2 */ @@ -44,7 +47,7 @@ public final class AvacynGuardianAngel extends CardImpl { Ability ability = new SimpleActivatedAbility( new AvacynGuardianAngelPreventToCreatureEffect(), new ManaCostsImpl<>("{1}{W}")); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); // {5}{W}{W}: Prevent all damage that would be dealt to target player this turn by sources of the color of your choice. diff --git a/Mage.Sets/src/mage/cards/a/AvacynianPriest.java b/Mage.Sets/src/mage/cards/a/AvacynianPriest.java index 889728f9d37..de66425a2af 100644 --- a/Mage.Sets/src/mage/cards/a/AvacynianPriest.java +++ b/Mage.Sets/src/mage/cards/a/AvacynianPriest.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class AvacynianPriest extends CardImpl { // {1}, {T}: Tap target non-Human creature. Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AvalancheTusker.java b/Mage.Sets/src/mage/cards/a/AvalancheTusker.java index 0606733a476..c14155cfaec 100644 --- a/Mage.Sets/src/mage/cards/a/AvalancheTusker.java +++ b/Mage.Sets/src/mage/cards/a/AvalancheTusker.java @@ -1,21 +1,20 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.effects.common.combat.MustBeBlockedByTargetSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.SetTargetPointer; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; -import mage.game.events.GameEvent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; + +import java.util.UUID; /** * @@ -32,7 +31,11 @@ public final class AvalancheTusker extends CardImpl { this.toughness = new MageInt(4); // Whenever Avalanche Tusker attacks, target creature defending player controls blocks it this turn if able. - this.addAbility(new AvalancheTuskerAbility()); + Ability ability = new AttacksTriggeredAbility(new MustBeBlockedByTargetSourceEffect(Duration.EndOfCombat) + .setText("target creature defending player controls blocks it this combat if able"), false, null, SetTargetPointer.PLAYER); + ability.addTarget(new TargetCreaturePermanent()); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); + this.addAbility(ability); } private AvalancheTusker(final AvalancheTusker card) { @@ -44,44 +47,3 @@ public final class AvalancheTusker extends CardImpl { return new AvalancheTusker(this); } } - -class AvalancheTuskerAbility extends TriggeredAbilityImpl { - - public AvalancheTuskerAbility() { - super(Zone.BATTLEFIELD, new MustBeBlockedByTargetSourceEffect(Duration.EndOfCombat), false); - } - - private AvalancheTuskerAbility(final AvalancheTuskerAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ATTACKER_DECLARED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getSourceId().equals(this.getSourceId())) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); - UUID defenderId = game.getCombat().getDefendingPlayerId(sourceId, game); - filter.add(new ControllerIdPredicate(defenderId)); - - this.getTargets().clear(); - TargetCreaturePermanent target = new TargetCreaturePermanent(filter); - this.addTarget(target); - return true; - } - return false; - } - - @Override - public String getRule() { - return "Whenever {this} attacks, target creature defending player controls blocks it this combat if able."; - } - - @Override - public AvalancheTuskerAbility copy() { - return new AvalancheTuskerAbility(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AvenAugur.java b/Mage.Sets/src/mage/cards/a/AvenAugur.java index a5e4429c544..ff46d3db90c 100644 --- a/Mage.Sets/src/mage/cards/a/AvenAugur.java +++ b/Mage.Sets/src/mage/cards/a/AvenAugur.java @@ -1,30 +1,27 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.SacrificeSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.PhaseStep; import mage.constants.SubType; -import mage.constants.Zone; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class AvenAugur extends CardImpl { public AvenAugur(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); this.subtype.add(SubType.BIRD); this.subtype.add(SubType.WIZARD); this.power = new MageInt(2); @@ -32,12 +29,11 @@ public final class AvenAugur extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // Sacrifice Aven Augur: Return up to two target creatures to their owners' hands. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new ReturnToHandTargetEffect(), - new SacrificeSourceCost(), - new IsStepCondition(PhaseStep.UPKEEP)); + Ability ability = new ActivateIfConditionActivatedAbility( + new ReturnToHandTargetEffect(), new SacrificeSourceCost(), IsStepCondition.getMyUpkeep() + ); ability.addTarget(new TargetCreaturePermanent(0, 2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AvenSoulgazer.java b/Mage.Sets/src/mage/cards/a/AvenSoulgazer.java index b2838c20677..2587e2e60b5 100644 --- a/Mage.Sets/src/mage/cards/a/AvenSoulgazer.java +++ b/Mage.Sets/src/mage/cards/a/AvenSoulgazer.java @@ -19,6 +19,7 @@ import mage.filter.predicate.card.FaceDownPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -47,7 +48,7 @@ public final class AvenSoulgazer extends CardImpl { // {2}{W}: Look at target face-down creature. Ability ability = new SimpleActivatedAbility(new AvenSoulgazerLookFaceDownEffect(), new ManaCostsImpl<>("{2}{W}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AyarasOathsworn.java b/Mage.Sets/src/mage/cards/a/AyarasOathsworn.java index 2ba67a29ba1..dec15fd7839 100644 --- a/Mage.Sets/src/mage/cards/a/AyarasOathsworn.java +++ b/Mage.Sets/src/mage/cards/a/AyarasOathsworn.java @@ -5,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceHasCounterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; @@ -40,15 +39,14 @@ public final class AyarasOathsworn extends CardImpl { this.addAbility(new MenaceAbility(false)); // Whenever Ayara's Oathsworn deals combat damage to a player, if it has fewer than four +1/+1 counters on it, put a +1/+1 counter on it. Then if it has exactly four +1/+1 counters on it, search your library for a card, put it into your hand, then shuffle. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new DealsCombatDamageToAPlayerTriggeredAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false - ), condition1, "Whenever {this} deals combat damage to a player, if it has fewer than four " + - "+1/+1 counters on it, put a +1/+1 counter on it. Then if it has exactly four +1/+1 counters on it, " + - "search your library for a card, put it into your hand, then shuffle." - ); + Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()) + .setText("put a +1/+1 counter on it"), false + ).withInterveningIf(condition1).withRuleTextReplacement(true); ability.addEffect(new ConditionalOneShotEffect( - new SearchLibraryPutInHandEffect(new TargetCardInLibrary(), false), condition2 + new SearchLibraryPutInHandEffect(new TargetCardInLibrary(), false), + condition2, "Then if it has exactly four +1/+1 counters on it, " + + "search your library for a card, put it into your hand, then shuffle" )); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AyliEternalPilgrim.java b/Mage.Sets/src/mage/cards/a/AyliEternalPilgrim.java index 69dbeb75a4d..5a88961c075 100644 --- a/Mage.Sets/src/mage/cards/a/AyliEternalPilgrim.java +++ b/Mage.Sets/src/mage/cards/a/AyliEternalPilgrim.java @@ -7,7 +7,7 @@ import mage.abilities.condition.common.MoreThanStartingLifeTotalCondition; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.dynamicvalue.common.SacrificeCostCreaturesToughness; import mage.abilities.effects.Effect; import mage.abilities.effects.common.ExileTargetEffect; @@ -18,7 +18,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.target.common.TargetNonlandPermanent; @@ -47,11 +46,8 @@ public final class AyliEternalPilgrim extends CardImpl { this.addAbility(ability); // {1}{W}{B}, Sacrifice another creature: Exile target nonland permanent. Activate only if you have at least 10 life more than your starting life total. - ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, - new ExileTargetEffect(), - new ManaCostsImpl<>("{1}{W}{B}"), - MoreThanStartingLifeTotalCondition.TEN + ability = new ActivateIfConditionActivatedAbility( + new ExileTargetEffect(), new ManaCostsImpl<>("{1}{W}{B}"), MoreThanStartingLifeTotalCondition.TEN ); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); ability.addTarget(new TargetNonlandPermanent().withChooseHint("to exile")); diff --git a/Mage.Sets/src/mage/cards/a/AysenBureaucrats.java b/Mage.Sets/src/mage/cards/a/AysenBureaucrats.java index 4c6b5280596..f29dbe22230 100644 --- a/Mage.Sets/src/mage/cards/a/AysenBureaucrats.java +++ b/Mage.Sets/src/mage/cards/a/AysenBureaucrats.java @@ -16,6 +16,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class AysenBureaucrats extends CardImpl { // {tap}: Tap target creature with power 2 or less. Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new TapSourceCost()); - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); ability.addTarget(target); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AzoriusArrester.java b/Mage.Sets/src/mage/cards/a/AzoriusArrester.java index 689a8c32388..92cdbdd1731 100644 --- a/Mage.Sets/src/mage/cards/a/AzoriusArrester.java +++ b/Mage.Sets/src/mage/cards/a/AzoriusArrester.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -10,17 +8,17 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.StaticFilters; -import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class AzoriusArrester extends CardImpl { - + public AzoriusArrester(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); @@ -29,8 +27,7 @@ public final class AzoriusArrester extends CardImpl { // When Azorius Arrester enters the battlefield, detain target creature an opponent controls. Ability ability = new EntersBattlefieldTriggeredAbility(new DetainTargetEffect(), false); - TargetCreaturePermanent target = new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE); - ability.addTarget(target); + ability.addTarget(new TargetOpponentsCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AzoriusPloy.java b/Mage.Sets/src/mage/cards/a/AzoriusPloy.java index b2b1517383a..cc6ce3218e1 100644 --- a/Mage.Sets/src/mage/cards/a/AzoriusPloy.java +++ b/Mage.Sets/src/mage/cards/a/AzoriusPloy.java @@ -11,6 +11,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.SecondTargetPointer; @@ -28,7 +29,7 @@ public final class AzoriusPloy extends CardImpl { Effect effect = new PreventDamageByTargetEffect( Duration.EndOfTurn, true); effect.setText("Prevent all combat damage target creature would deal this turn."); this.getSpellAbility().addEffect(effect); - Target target = new TargetCreaturePermanent(new FilterCreaturePermanent("first creature")); + Target target = new TargetPermanent(new FilterCreaturePermanent("first creature")); this.getSpellAbility().addTarget(target); // Prevent all combat damage that would be dealt to target creature this turn. @@ -36,7 +37,7 @@ public final class AzoriusPloy extends CardImpl { effect2.setText("

Prevent all combat damage that would be dealt to target creature this turn."); effect2.setTargetPointer(new SecondTargetPointer()); this.getSpellAbility().addEffect(effect2); - target = new TargetCreaturePermanent(new FilterCreaturePermanent("second creature (can be the same as the first)")); + target = new TargetPermanent(new FilterCreaturePermanent("second creature (can be the same as the first)")); this.getSpellAbility().addTarget(target); } @@ -49,4 +50,4 @@ public final class AzoriusPloy extends CardImpl { public AzoriusPloy copy() { return new AzoriusPloy(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/a/AzorsGateway.java b/Mage.Sets/src/mage/cards/a/AzorsGateway.java index a5c4062569b..6ac44610cf8 100644 --- a/Mage.Sets/src/mage/cards/a/AzorsGateway.java +++ b/Mage.Sets/src/mage/cards/a/AzorsGateway.java @@ -1,10 +1,6 @@ package mage.cards.a; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -20,13 +16,16 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SuperType; -import mage.constants.Zone; import mage.game.ExileZone; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInHand; import mage.util.CardUtil; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** * @author LevelX2 */ @@ -63,7 +62,7 @@ class AzorsGatewayEffect extends OneShotEffect { super(Outcome.Benefit); this.staticText = "Draw a card, then exile a card from your hand. " + "If cards with five or more different mana values are exiled with {this}, " + - "you gain 5 life, untap Azor's Gateway, and transform it"; + "you gain 5 life, untap {this}, and transform it"; } private AzorsGatewayEffect(final AzorsGatewayEffect effect) { diff --git a/Mage.Sets/src/mage/cards/b/Backlash.java b/Mage.Sets/src/mage/cards/b/Backlash.java index 526ad3e8ede..194f482c527 100644 --- a/Mage.Sets/src/mage/cards/b/Backlash.java +++ b/Mage.Sets/src/mage/cards/b/Backlash.java @@ -11,6 +11,7 @@ import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -30,7 +31,7 @@ public final class Backlash extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}{R}"); // Tap target untapped creature. That creature deals damage equal to its power to its controller. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new BacklashEffect()); } diff --git a/Mage.Sets/src/mage/cards/b/Backslide.java b/Mage.Sets/src/mage/cards/b/Backslide.java index 55244f2a08e..ad4b9c58451 100644 --- a/Mage.Sets/src/mage/cards/b/Backslide.java +++ b/Mage.Sets/src/mage/cards/b/Backslide.java @@ -19,6 +19,7 @@ import mage.filter.predicate.mageobject.AbilityPredicate; import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class Backslide extends CardImpl { // Turn target creature with a morph ability face down. this.getSpellAbility().addEffect(new BackslideEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Cycling {U} this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{U}"))); diff --git a/Mage.Sets/src/mage/cards/b/BakisCurse.java b/Mage.Sets/src/mage/cards/b/BakisCurse.java index 5ef672b66dc..3d9620bc454 100644 --- a/Mage.Sets/src/mage/cards/b/BakisCurse.java +++ b/Mage.Sets/src/mage/cards/b/BakisCurse.java @@ -1,8 +1,6 @@ package mage.cards.b; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -14,6 +12,9 @@ import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.List; +import java.util.UUID; + /** * * @author L_J @@ -40,8 +41,8 @@ public final class BakisCurse extends CardImpl { class BakisCurseEffect extends OneShotEffect { public BakisCurseEffect() { - super(Outcome.Detriment); - staticText = "Baki's Curse deals 2 damage to each creature for each Aura attached to that creature."; + super(Outcome.Detriment); + staticText = "{this} deals 2 damage to each creature for each Aura attached to that creature."; } private BakisCurseEffect(final BakisCurseEffect effect) { diff --git a/Mage.Sets/src/mage/cards/b/BalaGedScorpion.java b/Mage.Sets/src/mage/cards/b/BalaGedScorpion.java index 715f714f211..3f9017502b7 100644 --- a/Mage.Sets/src/mage/cards/b/BalaGedScorpion.java +++ b/Mage.Sets/src/mage/cards/b/BalaGedScorpion.java @@ -12,6 +12,7 @@ import mage.constants.ComparisonType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -34,7 +35,7 @@ public final class BalaGedScorpion extends CardImpl { this.toughness = new MageInt(3); EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), true); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BalduvianHydra.java b/Mage.Sets/src/mage/cards/b/BalduvianHydra.java index a73a65fe5af..a4ea88e3b0d 100644 --- a/Mage.Sets/src/mage/cards/b/BalduvianHydra.java +++ b/Mage.Sets/src/mage/cards/b/BalduvianHydra.java @@ -1,4 +1,3 @@ - package mage.cards.b; import mage.MageInt; @@ -7,19 +6,20 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.RemoveCountersSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.EntersBattlefieldWithXCountersEffect; import mage.abilities.effects.common.PreventDamageToSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.counters.CounterType; import java.util.UUID; /** - * * @author TheElk801 */ public final class BalduvianHydra extends CardImpl { @@ -35,11 +35,16 @@ public final class BalduvianHydra extends CardImpl { this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.P1P0.createInstance()))); // Remove a +1/+0 counter from Balduvian Hydra: Prevent the next 1 damage that would be dealt to Balduvian Hydra this turn. - this.addAbility(new SimpleActivatedAbility(new PreventDamageToSourceEffect(Duration.EndOfTurn, 1), new RemoveCountersSourceCost(CounterType.P1P0.createInstance()))); + this.addAbility(new SimpleActivatedAbility( + new PreventDamageToSourceEffect(Duration.EndOfTurn, 1), + new RemoveCountersSourceCost(CounterType.P1P0.createInstance()) + )); // {R}{R}{R}: Put a +1/+0 counter on Balduvian Hydra. Activate this ability only during your upkeep. - this.addAbility(new ConditionalActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P0.createInstance(1)), new ManaCostsImpl<>("{R}{R}{R}"), new IsStepCondition(PhaseStep.UPKEEP), null)); - + this.addAbility(new ActivateIfConditionActivatedAbility( + new AddCountersSourceEffect(CounterType.P1P0.createInstance(1)), + new ManaCostsImpl<>("{R}{R}{R}"), IsStepCondition.getMyUpkeep() + )); } private BalduvianHydra(final BalduvianHydra card) { diff --git a/Mage.Sets/src/mage/cards/b/BalduvianRage.java b/Mage.Sets/src/mage/cards/b/BalduvianRage.java index 8adf853365b..bca99675940 100644 --- a/Mage.Sets/src/mage/cards/b/BalduvianRage.java +++ b/Mage.Sets/src/mage/cards/b/BalduvianRage.java @@ -13,6 +13,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.common.FilterAttackingCreature; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; @@ -26,7 +27,7 @@ public final class BalduvianRage extends CardImpl { // Target attacking creature gets +X/+0 until end of turn. this.getSpellAbility().addEffect(new BoostTargetEffect(GetXValue.instance, StaticValue.get(0), Duration.EndOfTurn)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterAttackingCreature())); + this.getSpellAbility().addTarget(new TargetPermanent(new FilterAttackingCreature())); // Draw a card at the beginning of the next turn's upkeep. this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect( diff --git a/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java b/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java index 43420c8bd1a..40e0af18fb4 100644 --- a/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java +++ b/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java @@ -5,13 +5,16 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.RemoveFromCombatTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.constants.SubType; import mage.filter.common.FilterAttackingCreature; import mage.filter.common.FilterBlockingCreature; import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate; @@ -38,7 +41,7 @@ public final class BalduvianWarlord extends CardImpl { this.toughness = new MageInt(2); // {T}: Remove target blocking creature from combat. Creatures it was blocking that hadn't become blocked by another creature this combat become unblocked, then it blocks an attacking creature of your choice. Activate this ability only during the declare blockers step. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new BalduvianWarlordUnblockEffect(), new TapSourceCost(), new IsStepCondition(PhaseStep.DECLARE_BLOCKERS, false)); + Ability ability = new ActivateIfConditionActivatedAbility(new BalduvianWarlordUnblockEffect(), new TapSourceCost(), new IsStepCondition(PhaseStep.DECLARE_BLOCKERS, false)); ability.addTarget(new TargetPermanent(new FilterBlockingCreature())); this.addAbility(ability, new BlockedByOnlyOneCreatureThisCombatWatcher()); } diff --git a/Mage.Sets/src/mage/cards/b/BallLightning.java b/Mage.Sets/src/mage/cards/b/BallLightning.java index 697df3a9446..45a6e9a2c15 100644 --- a/Mage.Sets/src/mage/cards/b/BallLightning.java +++ b/Mage.Sets/src/mage/cards/b/BallLightning.java @@ -1,27 +1,25 @@ - - package mage.cards.b; -import java.util.UUID; import mage.MageInt; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.events.GameEvent.EventType; +import mage.constants.TargetController; + +import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com */ public final class BallLightning extends CardImpl { public BallLightning(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{R}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{R}{R}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(6); @@ -29,7 +27,9 @@ public final class BallLightning extends CardImpl { this.addAbility(TrampleAbility.getInstance()); this.addAbility(HasteAbility.getInstance()); - this.addAbility(new OnEventTriggeredAbility(EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new SacrificeSourceEffect())); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.NEXT, new SacrificeSourceEffect(), false + )); } private BallLightning(final BallLightning card) { diff --git a/Mage.Sets/src/mage/cards/b/BalladOfTheBlackFlag.java b/Mage.Sets/src/mage/cards/b/BalladOfTheBlackFlag.java index a6a9df732da..786bd942454 100644 --- a/Mage.Sets/src/mage/cards/b/BalladOfTheBlackFlag.java +++ b/Mage.Sets/src/mage/cards/b/BalladOfTheBlackFlag.java @@ -6,6 +6,7 @@ import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SagaChapter; import mage.constants.SubType; import mage.filter.FilterCard; @@ -40,7 +41,8 @@ public final class BalladOfTheBlackFlag extends CardImpl { // IV - Historic spells you cast this turn cost {2} less to cast. sagaAbility.addChapterEffect( this, SagaChapter.CHAPTER_IV, - new SpellsCostReductionControllerEffect(filter, 2) + new SpellsCostReductionControllerEffect(filter, 2).setDuration(Duration.EndOfTurn) + .setText("historic spells you cast this turn cost {2} less to cast") ); this.addAbility(sagaAbility); diff --git a/Mage.Sets/src/mage/cards/b/BalustradeWurm.java b/Mage.Sets/src/mage/cards/b/BalustradeWurm.java index e81434332fb..f25e700c470 100644 --- a/Mage.Sets/src/mage/cards/b/BalustradeWurm.java +++ b/Mage.Sets/src/mage/cards/b/BalustradeWurm.java @@ -41,8 +41,8 @@ public final class BalustradeWurm extends CardImpl { this.addAbility(new ActivateIfConditionActivatedAbility( Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldWithCounterEffect(CounterType.FINALITY.createInstance(), false), - new ManaCostsImpl<>("{2}{G}{G}"), DeliriumCondition.instance, TimingRule.SORCERY - ).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); + new ManaCostsImpl<>("{2}{G}{G}"), DeliriumCondition.instance + ).setTiming(TimingRule.SORCERY).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); } private BalustradeWurm(final BalustradeWurm card) { diff --git a/Mage.Sets/src/mage/cards/b/Banshee.java b/Mage.Sets/src/mage/cards/b/Banshee.java index 0f3c320bf73..e37dd596e2b 100644 --- a/Mage.Sets/src/mage/cards/b/Banshee.java +++ b/Mage.Sets/src/mage/cards/b/Banshee.java @@ -1,23 +1,23 @@ package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.dynamicvalue.common.HalfValue; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.dynamicvalue.common.HalfValue; import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** * * @author L_J @@ -31,7 +31,7 @@ public final class Banshee extends CardImpl { this.toughness = new MageInt(1); // {X}, {T}: Banshee deals half X damage, rounded down, to any target, and half X damage, rounded up, to you. - Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(new HalfValue(GetXValue.instance, false)).setText("Banshee deals half X damage, rounded down, to any target,"), new ManaCostsImpl<>("{X}")); + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(new HalfValue(GetXValue.instance, false)).setText("{this} deals half X damage, rounded down, to any target,"), new ManaCostsImpl<>("{X}")); ability.addCost(new TapSourceCost()); ability.addEffect(new DamageControllerEffect(new HalfValue(GetXValue.instance, true)).setText(" and half X damage, rounded up, to you")); ability.addTarget(new TargetAnyTarget()); diff --git a/Mage.Sets/src/mage/cards/b/BaradDur.java b/Mage.Sets/src/mage/cards/b/BaradDur.java index 18328b28d58..d51f2572517 100644 --- a/Mage.Sets/src/mage/cards/b/BaradDur.java +++ b/Mage.Sets/src/mage/cards/b/BaradDur.java @@ -9,13 +9,13 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.effects.keyword.AmassEffect; +import mage.abilities.hint.common.MorbidHint; import mage.abilities.mana.BlackManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; @@ -47,13 +47,11 @@ public final class BaradDur extends CardImpl { // {X}{X}{B}, {T}: Amass Orcs X. Activate only if a creature died this turn. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new AmassEffect(GetXValue.instance, SubType.ORC, false), - new ManaCostsImpl<>("{X}{X}{B}"), - MorbidCondition.instance + new ManaCostsImpl<>("{X}{X}{B}"), MorbidCondition.instance ); ability.addCost(new TapSourceCost()); - this.addAbility(ability); + this.addAbility(ability.addHint(MorbidHint.instance)); } private BaradDur(final BaradDur card) { diff --git a/Mage.Sets/src/mage/cards/b/BarbarianRing.java b/Mage.Sets/src/mage/cards/b/BarbarianRing.java index bc645427ae1..8b6de7af953 100644 --- a/Mage.Sets/src/mage/cards/b/BarbarianRing.java +++ b/Mage.Sets/src/mage/cards/b/BarbarianRing.java @@ -5,7 +5,7 @@ import mage.abilities.condition.common.ThresholdCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.mana.RedManaAbility; @@ -31,7 +31,7 @@ public final class BarbarianRing extends CardImpl { this.addAbility(redManaAbility); // Threshold - {R}, {T}, Sacrifice Barbarian Ring: Barbarian Ring deals 2 damage to any target. Activate this ability only if seven or more cards are in your graveyard. - Ability thresholdAbility = new ConditionalActivatedAbility( + Ability thresholdAbility = new ActivateIfConditionActivatedAbility( new DamageTargetEffect(2, "it"), new ManaCostsImpl<>("{R}"), ThresholdCondition.instance ); diff --git a/Mage.Sets/src/mage/cards/b/BaronSengir.java b/Mage.Sets/src/mage/cards/b/BaronSengir.java index 3ee91c88308..65dab278ccc 100644 --- a/Mage.Sets/src/mage/cards/b/BaronSengir.java +++ b/Mage.Sets/src/mage/cards/b/BaronSengir.java @@ -17,6 +17,7 @@ import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -48,7 +49,7 @@ public final class BaronSengir extends CardImpl { // {tap}: Regenerate another target Vampire. Ability ability = new SimpleActivatedAbility(new RegenerateTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BarrinTolarianArchmage.java b/Mage.Sets/src/mage/cards/b/BarrinTolarianArchmage.java index e18e185f475..c998c308c4a 100644 --- a/Mage.Sets/src/mage/cards/b/BarrinTolarianArchmage.java +++ b/Mage.Sets/src/mage/cards/b/BarrinTolarianArchmage.java @@ -15,7 +15,7 @@ import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; -import mage.target.common.TargetCreatureOrPlaneswalker; +import mage.target.TargetPermanent; import mage.watchers.Watcher; import java.util.HashSet; @@ -45,7 +45,7 @@ public final class BarrinTolarianArchmage extends CardImpl { // When Barrin, Tolarian Archmage enters the battlefield, return up to one other target creature or planeswalker to its owner's hand. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()); - ability.addTarget(new TargetCreatureOrPlaneswalker(0, 1, filter, false)); + ability.addTarget(new TargetPermanent(0, 1, filter)); this.addAbility(ability); // At the beginning of your end step, if a permanent was put into your hand from the battlefield this turn, draw a card. diff --git a/Mage.Sets/src/mage/cards/b/BattleOfHooverDam.java b/Mage.Sets/src/mage/cards/b/BattleOfHooverDam.java index b8e39e72ee1..10b56ed7e5e 100644 --- a/Mage.Sets/src/mage/cards/b/BattleOfHooverDam.java +++ b/Mage.Sets/src/mage/cards/b/BattleOfHooverDam.java @@ -29,7 +29,7 @@ import java.util.UUID; */ public final class BattleOfHooverDam extends CardImpl { - private static final FilterCard filter = new FilterCreatureCard(); + private static final FilterCard filter = new FilterCreatureCard("creature card with mana value 3 or less from your graveyard"); static { filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); diff --git a/Mage.Sets/src/mage/cards/b/BattleScreech.java b/Mage.Sets/src/mage/cards/b/BattleScreech.java index feb673697ce..5e3273f9b47 100644 --- a/Mage.Sets/src/mage/cards/b/BattleScreech.java +++ b/Mage.Sets/src/mage/cards/b/BattleScreech.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.costs.common.TapTargetCost; import mage.abilities.effects.common.CreateTokenEffect; @@ -9,15 +7,15 @@ import mage.abilities.keyword.FlashbackAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.TimingRule; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.permanent.token.BirdToken; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class BattleScreech extends CardImpl { @@ -30,14 +28,13 @@ public final class BattleScreech extends CardImpl { } public BattleScreech(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{W}{W}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}{W}"); // Create two 1/1 white Bird creature tokens with flying. this.getSpellAbility().addEffect(new CreateTokenEffect(new BirdToken(), 2)); // Flashback-Tap three untapped white creatures you control. - this.addAbility(new FlashbackAbility(this, new TapTargetCost(new TargetControlledCreaturePermanent(3,3, filter, true)))); + this.addAbility(new FlashbackAbility(this, new TapTargetCost(new TargetControlledPermanent(3, filter)))); } private BattleScreech(final BattleScreech card) { diff --git a/Mage.Sets/src/mage/cards/b/BeaconBehemoth.java b/Mage.Sets/src/mage/cards/b/BeaconBehemoth.java index 800b4d308b5..83fc438b83a 100644 --- a/Mage.Sets/src/mage/cards/b/BeaconBehemoth.java +++ b/Mage.Sets/src/mage/cards/b/BeaconBehemoth.java @@ -14,6 +14,7 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -36,7 +37,7 @@ public final class BeaconBehemoth extends CardImpl { this.toughness = new MageInt(3); Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{1}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BeastbondOutcaster.java b/Mage.Sets/src/mage/cards/b/BeastbondOutcaster.java index 9034f4f66da..a8da380d01b 100644 --- a/Mage.Sets/src/mage/cards/b/BeastbondOutcaster.java +++ b/Mage.Sets/src/mage/cards/b/BeastbondOutcaster.java @@ -3,7 +3,6 @@ package mage.cards.b; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.FerociousCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.hint.common.FerociousHint; import mage.abilities.keyword.PlotAbility; @@ -28,11 +27,8 @@ public final class BeastbondOutcaster extends CardImpl { this.toughness = new MageInt(3); // When Beastbond Outcaster enters the battlefield, if you control a creature with power 4 or greater, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)), - FerociousCondition.instance, "When {this} enters, " + - "if you control a creature with power 4 or greater, draw a card." - ).addHint(FerociousHint.instance)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .withInterveningIf(FerociousCondition.instance).addHint(FerociousHint.instance)); // Plot {1}{G} this.addAbility(new PlotAbility("{1}{G}")); diff --git a/Mage.Sets/src/mage/cards/b/BelakorTheDarkMaster.java b/Mage.Sets/src/mage/cards/b/BelakorTheDarkMaster.java index a4c07480b7a..e0b2171298d 100644 --- a/Mage.Sets/src/mage/cards/b/BelakorTheDarkMaster.java +++ b/Mage.Sets/src/mage/cards/b/BelakorTheDarkMaster.java @@ -56,7 +56,7 @@ public final class BelakorTheDarkMaster extends CardImpl { // Prince of Chaos -- When Be'lakor, the Dark Master enters the battlefield, you draw X cards and you lose X life, where X is the number of Demons you control. Ability ability = new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(xValue).setText("you draw X cards")); - ability.addEffect(new LoseLifeSourceControllerEffect(xValue).concatBy("and")); + ability.addEffect(new LoseLifeSourceControllerEffect(xValue).setText("and you lose X life, where X is the number of Demons you control")); this.addAbility(ability.withFlavorWord("Prince of Chaos").addHint(hint)); // Lord of Torment -- Whenever another Demon you control enters, it deals damage equal to its power to any target. diff --git a/Mage.Sets/src/mage/cards/b/BenalishMissionary.java b/Mage.Sets/src/mage/cards/b/BenalishMissionary.java index e98cd1183e2..6b86c406e3e 100644 --- a/Mage.Sets/src/mage/cards/b/BenalishMissionary.java +++ b/Mage.Sets/src/mage/cards/b/BenalishMissionary.java @@ -16,6 +16,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.BlockedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class BenalishMissionary extends CardImpl { // {1}{W}, {tap}: Prevent all combat damage that would be dealt by target blocked creature this turn. Ability ability = new SimpleActivatedAbility(new PreventDamageByTargetEffect(Duration.EndOfTurn, true), new ManaCostsImpl<>("{1}{W}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BenthicAnomaly.java b/Mage.Sets/src/mage/cards/b/BenthicAnomaly.java index cb20790df48..d802d095be0 100644 --- a/Mage.Sets/src/mage/cards/b/BenthicAnomaly.java +++ b/Mage.Sets/src/mage/cards/b/BenthicAnomaly.java @@ -1,7 +1,6 @@ package mage.cards.b; import mage.MageInt; -import mage.MageItem; import mage.MageObject; import mage.ObjectColor; import mage.abilities.Ability; @@ -16,9 +15,8 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -28,7 +26,6 @@ import mage.util.RandomUtil; import java.util.HashSet; import java.util.Set; import java.util.UUID; -import java.util.stream.Collectors; /** * @author TheElk801 @@ -114,13 +111,7 @@ class BenthicAnomalyEffect extends OneShotEffect { break; default: FilterPermanent filter = new FilterPermanent("a creature to create a copy of"); - filter.add(Predicates.or( - permanents - .stream() - .map(MageItem::getId) - .map(PermanentIdPredicate::new) - .collect(Collectors.toSet()) - )); + filter.add(new PermanentReferenceInCollectionPredicate(permanents, game)); TargetPermanent target = new TargetPermanent(filter); target.withNotTarget(true); player.choose(outcome, target, source, game); diff --git a/Mage.Sets/src/mage/cards/b/BessieTheDoctorsRoadster.java b/Mage.Sets/src/mage/cards/b/BessieTheDoctorsRoadster.java index e4d53e394d4..54742663dde 100644 --- a/Mage.Sets/src/mage/cards/b/BessieTheDoctorsRoadster.java +++ b/Mage.Sets/src/mage/cards/b/BessieTheDoctorsRoadster.java @@ -13,6 +13,7 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -42,7 +43,7 @@ public final class BessieTheDoctorsRoadster extends CardImpl { // Whenever Bessie attacks, another target legendary creature can't be blocked this turn. Ability ability = new AttacksTriggeredAbility(new CantBeBlockedTargetEffect()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Crew 2 diff --git a/Mage.Sets/src/mage/cards/b/BetorAncestorsVoice.java b/Mage.Sets/src/mage/cards/b/BetorAncestorsVoice.java index 88e1cac8d2a..fece40d434f 100644 --- a/Mage.Sets/src/mage/cards/b/BetorAncestorsVoice.java +++ b/Mage.Sets/src/mage/cards/b/BetorAncestorsVoice.java @@ -1,6 +1,5 @@ package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -8,27 +7,28 @@ import mage.abilities.dynamicvalue.common.ControllerGainedLifeCount; import mage.abilities.dynamicvalue.common.ControllerLostLifeCount; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.constants.SubType; -import mage.constants.SuperType; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInGraveyard; -import mage.target.common.TargetControlledCreaturePermanent; import mage.target.targetpointer.SecondTargetPointer; import mage.watchers.common.PlayerGainedLifeWatcher; +import java.util.UUID; + /** - * * @author Grath */ public final class BetorAncestorsVoice extends CardImpl { @@ -43,7 +43,7 @@ public final class BetorAncestorsVoice extends CardImpl { public BetorAncestorsVoice(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{B}{G}"); - + this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.SPIRIT); this.subtype.add(SubType.DRAGON); @@ -64,7 +64,7 @@ public final class BetorAncestorsVoice extends CardImpl { .setText("put a number of +1/+1 counters on up to one other target creature you " + "control equal to the amount of life you gained this turn.") ); - ability.addTarget(new TargetControlledCreaturePermanent(0, 1, StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL, false)); + ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); ability.addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect().setTargetPointer(new SecondTargetPointer()) .setText("Return up to one target creature card with mana value less than or equal to the amount of " + "life you lost this turn from your graveyard to the battlefield.")); @@ -96,4 +96,4 @@ enum BetorPredicate implements ObjectSourcePlayerPredicate { public String toString() { return "mana value less than or equal to the amount of life you lost this turn"; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/b/Betray.java b/Mage.Sets/src/mage/cards/b/Betray.java index 3043c4c4709..b89dc0cb507 100644 --- a/Mage.Sets/src/mage/cards/b/Betray.java +++ b/Mage.Sets/src/mage/cards/b/Betray.java @@ -10,7 +10,7 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -18,13 +18,13 @@ import java.util.UUID; * @author Merlingilb */ public class Betray extends CardImpl { + public Betray(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); //Target creature an opponent controls deals damage to its controller equal to that creature's power. this.getSpellAbility().addEffect(new BetrayEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(1, 1, - StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, false)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); } private Betray(final Betray card) { diff --git a/Mage.Sets/src/mage/cards/b/Betrayal.java b/Mage.Sets/src/mage/cards/b/Betrayal.java index 7ad39a0f421..3daefdac019 100644 --- a/Mage.Sets/src/mage/cards/b/Betrayal.java +++ b/Mage.Sets/src/mage/cards/b/Betrayal.java @@ -16,6 +16,8 @@ import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * @author LoneFox */ @@ -26,7 +28,7 @@ public final class Betrayal extends CardImpl { this.subtype.add(SubType.AURA); // Enchant creature an opponent controls - TargetPermanent auraTarget = new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE); + TargetPermanent auraTarget = new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); Ability ability = new EnchantAbility(auraTarget); diff --git a/Mage.Sets/src/mage/cards/b/BetrayalAtTheVault.java b/Mage.Sets/src/mage/cards/b/BetrayalAtTheVault.java index 206c7c0f4ee..764f21e7d54 100644 --- a/Mage.Sets/src/mage/cards/b/BetrayalAtTheVault.java +++ b/Mage.Sets/src/mage/cards/b/BetrayalAtTheVault.java @@ -11,8 +11,8 @@ import mage.filter.predicate.other.AnotherTargetPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; import java.util.List; import java.util.Objects; @@ -35,7 +35,7 @@ public final class BetrayalAtTheVault extends CardImpl { // Target creature you control deals damage equal to its power to each of two other target creatures. this.getSpellAbility().addEffect(new BetrayalAtTheVaultEffect()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent().setTargetTag(1)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(2, 2, filter, false).setTargetTag(2)); + this.getSpellAbility().addTarget(new TargetPermanent(2, filter).setTargetTag(2)); } private BetrayalAtTheVault(final BetrayalAtTheVault card) { @@ -81,4 +81,4 @@ class BetrayalAtTheVaultEffect extends OneShotEffect { .forEach(p -> p.damage(creature.getPower().getValue(), creature.getId(), source, game)); return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/b/Bifurcate.java b/Mage.Sets/src/mage/cards/b/Bifurcate.java index da513140c6e..51c2b09685b 100644 --- a/Mage.Sets/src/mage/cards/b/Bifurcate.java +++ b/Mage.Sets/src/mage/cards/b/Bifurcate.java @@ -15,6 +15,7 @@ import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCreaturePermanent; @@ -35,7 +36,7 @@ public final class Bifurcate extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}"); // Search your library for a permanent card with the same name as target nontoken creature and put that card onto the battlefield. Then shuffle your library. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new BifurcateEffect()); } diff --git a/Mage.Sets/src/mage/cards/b/BigGameHunter.java b/Mage.Sets/src/mage/cards/b/BigGameHunter.java index 8967f907e69..26544e30cc1 100644 --- a/Mage.Sets/src/mage/cards/b/BigGameHunter.java +++ b/Mage.Sets/src/mage/cards/b/BigGameHunter.java @@ -15,6 +15,7 @@ import mage.constants.ComparisonType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class BigGameHunter extends CardImpl { // When Big Game Hunter enters the battlefield, destroy target creature with power 4 or greater. It can't be regenerated. Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(true)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Madness {B} this.addAbility(new MadnessAbility(new ManaCostsImpl<>("{B}"))); diff --git a/Mage.Sets/src/mage/cards/b/BilboBirthdayCelebrant.java b/Mage.Sets/src/mage/cards/b/BilboBirthdayCelebrant.java index 036502e3560..943349de552 100644 --- a/Mage.Sets/src/mage/cards/b/BilboBirthdayCelebrant.java +++ b/Mage.Sets/src/mage/cards/b/BilboBirthdayCelebrant.java @@ -7,7 +7,7 @@ import mage.abilities.condition.Condition; import mage.abilities.costs.common.ExileSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.replacement.GainPlusOneLifeReplacementEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.cards.CardImpl; @@ -39,7 +39,7 @@ public final class BilboBirthdayCelebrant extends CardImpl { this.addAbility(new SimpleStaticAbility(new GainPlusOneLifeReplacementEffect())); // {2}{W}{B}{G}, {T}, Exile Bilbo, Birthday Celebrant: Search your library for any number of creature cards, put them onto the battlefield, then shuffle. Activate only if you have 111 or more life. - Ability ability = new ConditionalActivatedAbility(new SearchLibraryPutInPlayEffect( + Ability ability = new ActivateIfConditionActivatedAbility(new SearchLibraryPutInPlayEffect( new TargetCardInLibrary(0, Integer.MAX_VALUE, StaticFilters.FILTER_CARD_CREATURES) ), new ManaCostsImpl<>("{2}{W}{B}{G}"), BilboBirthdayCelebrantCondition.instance); ability.addCost(new TapSourceCost()); @@ -69,4 +69,4 @@ enum BilboBirthdayCelebrantCondition implements Condition { public String toString() { return "you have 111 or more life"; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/b/Bioshift.java b/Mage.Sets/src/mage/cards/b/Bioshift.java index b9946b01b63..6a0b81e28c0 100644 --- a/Mage.Sets/src/mage/cards/b/Bioshift.java +++ b/Mage.Sets/src/mage/cards/b/Bioshift.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageItem; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -10,6 +8,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; @@ -18,34 +17,33 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.stack.StackObject; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Bioshift extends CardImpl { - public Bioshift(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{G/U}"); + private static final FilterPermanent filter = new FilterCreaturePermanent("another target creature with the same controller"); - // Move any number of +1/+1 counters from target creature onto another target creature with the same controller. - getSpellAbility().addEffect(new MoveCounterFromTargetToTargetEffect()); - - TargetCreaturePermanent target = new TargetCreaturePermanent( - new FilterCreaturePermanent("creature (you take counters from)")); - target.setTargetTag(1); - this.getSpellAbility().addTarget(target); - - FilterCreaturePermanent filter = new FilterCreaturePermanent( - "another target creature with the same controller (counters go to)"); + static { filter.add(new AnotherTargetPredicate(2)); filter.add(new SameControllerPredicate()); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter); - target2.setTargetTag(2); - this.getSpellAbility().addTarget(target2); } - + + public Bioshift(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G/U}"); + + // Move any number of +1/+1 counters from target creature onto another target creature with the same controller. + this.getSpellAbility().addEffect(new MoveCounterFromTargetToTargetEffect()); + + this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("to take counters from").setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanent(filter).withChooseHint("to put counter on").setTargetTag(2)); + } + private Bioshift(final Bioshift card) { super(card); @@ -107,7 +105,7 @@ class SameControllerPredicate implements ObjectSourcePlayerPredicate { StackObject source = game.getStack().getStackObject(input.getSourceId()); if (source != null) { if (source.getStackAbility().getTargets().isEmpty() - || source.getStackAbility().getTargets().get(0).getTargets().isEmpty()) { + || source.getStackAbility().getTargets().get(0).getTargets().isEmpty()) { return true; } Permanent firstTarget = game.getPermanent( @@ -124,5 +122,5 @@ class SameControllerPredicate implements ObjectSourcePlayerPredicate { public String toString() { return "Target with the same controller"; } - + } diff --git a/Mage.Sets/src/mage/cards/b/BiotechSpecialist.java b/Mage.Sets/src/mage/cards/b/BiotechSpecialist.java new file mode 100644 index 00000000000..3a070aa68cc --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BiotechSpecialist.java @@ -0,0 +1,51 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SacrificePermanentTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.LanderToken; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BiotechSpecialist extends CardImpl { + + public BiotechSpecialist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{G}"); + + this.subtype.add(SubType.INSECT); + this.subtype.add(SubType.SCIENTIST); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // When this creature enters, create a Lander token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new LanderToken()))); + + // Whenever you sacrifice an artifact, this creature deals 2 damage to target opponent. + Ability ability = new SacrificePermanentTriggeredAbility( + new DamageTargetEffect(2), StaticFilters.FILTER_PERMANENT_ARTIFACT + ); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + private BiotechSpecialist(final BiotechSpecialist card) { + super(card); + } + + @Override + public BiotechSpecialist copy() { + return new BiotechSpecialist(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BirchloreRangers.java b/Mage.Sets/src/mage/cards/b/BirchloreRangers.java index 0ef117efbe6..b50024b3bde 100644 --- a/Mage.Sets/src/mage/cards/b/BirchloreRangers.java +++ b/Mage.Sets/src/mage/cards/b/BirchloreRangers.java @@ -1,8 +1,5 @@ package mage.cards.b; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.Mana; import mage.abilities.Ability; @@ -15,19 +12,27 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; /** - * * @author LevelX2 */ public final class BirchloreRangers extends CardImpl { + private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.ELF, "untapped Elves you control"); + + static { + filter.add(TappedPredicate.UNTAPPED); + } + public BirchloreRangers(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); this.subtype.add(SubType.ELF, SubType.DRUID, SubType.RANGER); @@ -36,14 +41,11 @@ public final class BirchloreRangers extends CardImpl { this.toughness = new MageInt(1); // Tap two untapped Elves you control: Add one mana of any color. - FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Elves you control"); - filter.add(TappedPredicate.UNTAPPED); - filter.add(SubType.ELF.getPredicate()); this.addAbility(new SimpleManaAbility( - Zone.BATTLEFIELD, new BirchloreRangersManaEffect(filter), - new TapTargetCost(new TargetControlledCreaturePermanent(2, 2, filter, false)))); - + new TapTargetCost(new TargetControlledPermanent(2, filter)) + )); + // Morph {G} this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{G}"))); } @@ -90,4 +92,4 @@ class BirchloreRangersManaEffect extends AddManaOfAnyColorEffect { return super.getNetMana(game, source); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/b/BishopOfBinding.java b/Mage.Sets/src/mage/cards/b/BishopOfBinding.java index 3d7086c4845..cdfe4492213 100644 --- a/Mage.Sets/src/mage/cards/b/BishopOfBinding.java +++ b/Mage.Sets/src/mage/cards/b/BishopOfBinding.java @@ -23,9 +23,12 @@ import mage.filter.common.FilterCreaturePermanent; import mage.game.ExileZone; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.util.CardUtil; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -42,12 +45,12 @@ public final class BishopOfBinding extends CardImpl { // When Bishop of Binding enters the battlefield, exile target creature an opponent controls until Bishop of Binding leaves the battlefield. Ability ability = new EntersBattlefieldTriggeredAbility(new BishopOfBindingExileEffect()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); // Whenever Bishop of Binding attacks, target Vampire gets +X/+X until end of turn, where X is the power of the exiled card. ability = new AttacksTriggeredAbility(new BoostTargetEffect(BishopOfBindingValue.instance, BishopOfBindingValue.instance, Duration.EndOfTurn)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BiteDownOnCrime.java b/Mage.Sets/src/mage/cards/b/BiteDownOnCrime.java index b705cba0318..067cabe2f2a 100644 --- a/Mage.Sets/src/mage/cards/b/BiteDownOnCrime.java +++ b/Mage.Sets/src/mage/cards/b/BiteDownOnCrime.java @@ -14,12 +14,15 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; import mage.game.Game; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import mage.util.CardUtil; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * * @author notgreat @@ -40,7 +43,7 @@ public final class BiteDownOnCrime extends CardImpl { // It deals damage equal to its power to target creature you don't control. this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect("It")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); } private BiteDownOnCrime(final BiteDownOnCrime card) { diff --git a/Mage.Sets/src/mage/cards/b/BlackCarriage.java b/Mage.Sets/src/mage/cards/b/BlackCarriage.java index 78d9afde558..661c507e0ca 100644 --- a/Mage.Sets/src/mage/cards/b/BlackCarriage.java +++ b/Mage.Sets/src/mage/cards/b/BlackCarriage.java @@ -1,26 +1,22 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect; import mage.abilities.effects.common.UntapSourceEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.PhaseStep; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author fireshoes */ public final class BlackCarriage extends CardImpl { @@ -38,9 +34,10 @@ public final class BlackCarriage extends CardImpl { this.addAbility(new SimpleStaticAbility(new DontUntapInControllersUntapStepSourceEffect())); // Sacrifice a creature: Untap Black Carriage. Activate this ability only during your upkeep. - this.addAbility(new ConditionalActivatedAbility(Zone.BATTLEFIELD, + this.addAbility(new ActivateIfConditionActivatedAbility( new UntapSourceEffect(), new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE), - new IsStepCondition(PhaseStep.UPKEEP), "Sacrifice a creature: Untap {this}. Activate only during your upkeep.")); + IsStepCondition.getMyUpkeep() + )); } private BlackCarriage(final BlackCarriage card) { diff --git a/Mage.Sets/src/mage/cards/b/BlackMarket.java b/Mage.Sets/src/mage/cards/b/BlackMarket.java index 044d39de677..e458e91e67a 100644 --- a/Mage.Sets/src/mage/cards/b/BlackMarket.java +++ b/Mage.Sets/src/mage/cards/b/BlackMarket.java @@ -1,13 +1,12 @@ package mage.cards.b; -import java.util.UUID; import mage.Mana; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -17,6 +16,8 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** * * @author markedagain @@ -47,7 +48,7 @@ class BlackMarketEffect extends OneShotEffect { BlackMarketEffect() { super(Outcome.PutManaInPool); - this.staticText = "add {B} for each charge counter on Black Market"; + this.staticText = "add {B} for each charge counter on {this}"; } private BlackMarketEffect(final BlackMarketEffect effect) { diff --git a/Mage.Sets/src/mage/cards/b/BlackOakOfOdunos.java b/Mage.Sets/src/mage/cards/b/BlackOakOfOdunos.java index ba97419e572..4a52644b3a5 100644 --- a/Mage.Sets/src/mage/cards/b/BlackOakOfOdunos.java +++ b/Mage.Sets/src/mage/cards/b/BlackOakOfOdunos.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -14,27 +12,28 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; /** - * * @author Quercitron */ public final class BlackOakOfOdunos extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another untapped creature you control"); + private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("another untapped creature you control"); static { filter.add(AnotherPredicate.instance); filter.add(TappedPredicate.UNTAPPED); } - + public BlackOakOfOdunos(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.ZOMBIE, SubType.TREEFOLK); this.power = new MageInt(0); @@ -42,9 +41,12 @@ public final class BlackOakOfOdunos extends CardImpl { // Defender this.addAbility(DefenderAbility.getInstance()); + // {B}, Tap another untapped creature you control: Black Oak of Odunos gets +1/+1 until end of turn. - Ability ability = new SimpleActivatedAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn), new ManaCostsImpl<>("{B}")); - ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, true))); + Ability ability = new SimpleActivatedAbility( + new BoostSourceEffect(1, 1, Duration.EndOfTurn), new ManaCostsImpl<>("{B}") + ); + ability.addCost(new TapTargetCost(new TargetControlledPermanent(filter))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BlackbladeReforged.java b/Mage.Sets/src/mage/cards/b/BlackbladeReforged.java index 4cf85be7bfe..9321dafa470 100644 --- a/Mage.Sets/src/mage/cards/b/BlackbladeReforged.java +++ b/Mage.Sets/src/mage/cards/b/BlackbladeReforged.java @@ -9,12 +9,15 @@ import mage.abilities.hint.ValueHint; import mage.abilities.keyword.EquipAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; -import mage.target.common.TargetControlledCreaturePermanent; /** * @author Rystan @@ -39,7 +42,7 @@ public final class BlackbladeReforged extends CardImpl { this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(count, count)).addHint(new ValueHint("Lands you control", count))); // Equip legendary creature (3) - this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(3), new TargetControlledCreaturePermanent(filter), false)); + this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(3), new TargetPermanent(filter), false)); // Equip {7} this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(7), false)); diff --git a/Mage.Sets/src/mage/cards/b/BlacklanceParagon.java b/Mage.Sets/src/mage/cards/b/BlacklanceParagon.java index 9f488f29c39..cbf3d169236 100644 --- a/Mage.Sets/src/mage/cards/b/BlacklanceParagon.java +++ b/Mage.Sets/src/mage/cards/b/BlacklanceParagon.java @@ -16,6 +16,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -45,7 +46,7 @@ public final class BlacklanceParagon extends CardImpl { effect = new GainAbilityTargetEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn); effect.setText("and lifelink until end of turn"); ability.addEffect(effect); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BladegraftAspirant.java b/Mage.Sets/src/mage/cards/b/BladegraftAspirant.java index 2517e1981b6..fce3464a4dc 100644 --- a/Mage.Sets/src/mage/cards/b/BladegraftAspirant.java +++ b/Mage.Sets/src/mage/cards/b/BladegraftAspirant.java @@ -62,7 +62,7 @@ public final class BladegraftAspirant extends CardImpl { class BladegraftAspirantCostReductionEffect extends CostModificationEffectImpl { - private static final String effectText = "Activated abilities of Equipment you control that target Bladegraft Aspirant cost {1} less to activate."; + private static final String effectText = "Activated abilities of Equipment you control that target {this} cost {1} less to activate."; BladegraftAspirantCostReductionEffect() { super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST); diff --git a/Mage.Sets/src/mage/cards/b/BladegriffPrototype.java b/Mage.Sets/src/mage/cards/b/BladegriffPrototype.java index 64655b2405f..a08f871db1a 100644 --- a/Mage.Sets/src/mage/cards/b/BladegriffPrototype.java +++ b/Mage.Sets/src/mage/cards/b/BladegriffPrototype.java @@ -1,32 +1,37 @@ package mage.cards.b; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.FilterPermanent; import mage.filter.common.FilterNonlandPermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Controllable; import mage.game.Game; -import mage.game.events.DamagedEvent; -import mage.game.events.GameEvent; -import mage.players.Player; +import mage.target.Target; import mage.target.TargetPermanent; +import mage.target.targetadjustment.GenericTargetAdjuster; +import mage.target.targetpointer.FirstTargetPointer; import java.util.UUID; -import java.util.stream.Collectors; /** * @author TheElk801 */ public final class BladegriffPrototype extends CardImpl { + private static final FilterNonlandPermanent filter = new FilterNonlandPermanent("nonland permanent of that player's choice that one of your opponents controls"); + + static { + filter.add(BladegriffSourceOpponentControlsPredicate.instance); + } + public BladegriffPrototype(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{5}"); @@ -38,7 +43,10 @@ public final class BladegriffPrototype extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever Bladegriff Prototype deals combat damage to a player, destroy target nonland permanent of that player's choice that one of your opponents controls. - this.addAbility(new BladegriffPrototypeAbility()); + Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DestroyTargetEffect(), false, true); + ability.addTarget(new TargetPermanent(filter)); + ability.setTargetAdjuster(new ThatPlayersChoiceTargetAdjuster()); + this.addAbility(ability); } private BladegriffPrototype(final BladegriffPrototype card) { @@ -51,54 +59,27 @@ public final class BladegriffPrototype extends CardImpl { } } -class BladegriffPrototypeAbility extends TriggeredAbilityImpl { - - BladegriffPrototypeAbility() { - super(Zone.BATTLEFIELD, new DestroyTargetEffect(), false); - } - - private BladegriffPrototypeAbility(final BladegriffPrototypeAbility ability) { - super(ability); - } +enum BladegriffSourceOpponentControlsPredicate implements ObjectSourcePlayerPredicate { + instance; @Override - public BladegriffPrototypeAbility copy() { - return new BladegriffPrototypeAbility(this); - } + public boolean apply(ObjectSourcePlayer input, Game game) { + Controllable object = input.getObject(); + UUID playerId = input.getSource().getControllerId(); - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Player player = game.getPlayer(getControllerId()); - if (player == null - || !event.getSourceId().equals(this.sourceId) - || !((DamagedEvent) event).isCombatDamage()) { - return false; - } - FilterPermanent filter = new FilterNonlandPermanent( - "nonland permanent controlled by an opponent of " + player.getName() - ); - filter.add(Predicates.or( - game.getOpponents(getControllerId()) - .stream() - .map(ControllerIdPredicate::new) - .collect(Collectors.toSet()) - )); - TargetPermanent target = new TargetPermanent(filter); - target.setTargetController(event.getPlayerId()); - this.getTargets().clear(); - this.addTarget(target); - return true; - } - - @Override - public String getRule() { - return "Whenever {this} deals combat damage to a player, " + - "destroy target nonland permanent of that player's choice " + - "that one of your opponents controls."; + return !object.isControlledBy(playerId) + && game.getPlayer(playerId).hasOpponent(object.getControllerId(), game); + } +} + +class ThatPlayersChoiceTargetAdjuster extends GenericTargetAdjuster { + @Override + public void adjustTargets(Ability ability, Game game) { + UUID opponentId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability); + ability.getTargets().clear(); + ability.getAllEffects().setTargetPointer(new FirstTargetPointer()); + Target newTarget = blueprintTarget.copy(); + newTarget.setTargetController(opponentId); + ability.addTarget(newTarget); } } diff --git a/Mage.Sets/src/mage/cards/b/BlazeOfGlory.java b/Mage.Sets/src/mage/cards/b/BlazeOfGlory.java index b77aee8c7f5..ea41cf87049 100644 --- a/Mage.Sets/src/mage/cards/b/BlazeOfGlory.java +++ b/Mage.Sets/src/mage/cards/b/BlazeOfGlory.java @@ -14,6 +14,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.DefendingPlayerControlsNoSourcePredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -36,7 +37,7 @@ public final class BlazeOfGlory extends CardImpl { this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(TurnPhase.COMBAT, BeforeBlockersAreDeclaredCondition.instance)); // Target creature defending player controls can block any number of creatures this turn. It blocks each attacking creature this turn if able. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new CanBlockAdditionalCreatureTargetEffect(Duration.EndOfTurn, 0) .setText("target creature defending player controls can block any number of creatures this turn")); this.getSpellAbility().addEffect(new BlazeOfGloryRequirementEffect()); diff --git a/Mage.Sets/src/mage/cards/b/BlazingHope.java b/Mage.Sets/src/mage/cards/b/BlazingHope.java index da94b2584e6..4fc35abe721 100644 --- a/Mage.Sets/src/mage/cards/b/BlazingHope.java +++ b/Mage.Sets/src/mage/cards/b/BlazingHope.java @@ -11,7 +11,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -38,7 +38,7 @@ public final class BlazingHope extends CardImpl { } } -class BlazingHopeTarget extends TargetCreaturePermanent { +class BlazingHopeTarget extends TargetPermanent { public BlazingHopeTarget() { super(new FilterCreaturePermanent("creature with power greater than or equal to your life total")); diff --git a/Mage.Sets/src/mage/cards/b/BlessedAlliance.java b/Mage.Sets/src/mage/cards/b/BlessedAlliance.java index 1edb08eed24..3c99a3b6cad 100644 --- a/Mage.Sets/src/mage/cards/b/BlessedAlliance.java +++ b/Mage.Sets/src/mage/cards/b/BlessedAlliance.java @@ -2,7 +2,6 @@ package mage.cards.b; import mage.abilities.Mode; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.GainLifeTargetEffect; import mage.abilities.effects.common.SacrificeEffect; import mage.abilities.effects.common.UntapTargetEffect; @@ -10,10 +9,7 @@ import mage.abilities.keyword.EscalateAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.TargetController; -import mage.filter.FilterPlayer; import mage.filter.common.FilterAttackingCreature; -import mage.filter.common.FilterCreaturePermanent; import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; @@ -24,14 +20,6 @@ import java.util.UUID; */ public final class BlessedAlliance extends CardImpl { - private static final FilterPlayer filterSacrifice = new FilterPlayer("opponent to sacrifice an attacking creature"); - private static final FilterCreaturePermanent filterCreature = new FilterCreaturePermanent("creatures to untap"); - private static final FilterPlayer filterGainLife = new FilterPlayer("player to gain life"); - - static { - filterSacrifice.add(TargetController.OPPONENT.getPlayerPredicate()); - } - public BlessedAlliance(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); @@ -43,21 +31,17 @@ public final class BlessedAlliance extends CardImpl { this.getSpellAbility().getModes().setMaxModes(3); // Target player gains 4 life. - Effect effect = new GainLifeTargetEffect(4); - effect.setText("Target player gains 4 life"); - this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterGainLife).withChooseHint("player gains 4 life")); + this.getSpellAbility().addEffect(new GainLifeTargetEffect(4)); + this.getSpellAbility().addTarget(new TargetPlayer().withChooseHint("player gains 4 life")); // Untap up to two target creatures. - effect = new UntapTargetEffect(); - effect.setText("Untap up to two target creatures"); - Mode mode = new Mode(effect); - mode.addTarget(new TargetCreaturePermanent(0, 2, filterCreature, false).withChooseHint("untap")); + Mode mode = new Mode(new UntapTargetEffect()); + mode.addTarget(new TargetCreaturePermanent(0, 2).withChooseHint("untap")); this.getSpellAbility().addMode(mode); // Target opponent sacrifices an attacking creature. mode = new Mode(new SacrificeEffect(new FilterAttackingCreature(), 1, "Target opponent")); - mode.addTarget(new TargetPlayer(1, 1, false, filterSacrifice).withChooseHint("sacrifices an attacking creature")); + mode.addTarget(new TargetPlayer().withChooseHint("sacrifices an attacking creature")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/b/BlessedReincarnation.java b/Mage.Sets/src/mage/cards/b/BlessedReincarnation.java index de3561bb8c2..ae6a744003b 100644 --- a/Mage.Sets/src/mage/cards/b/BlessedReincarnation.java +++ b/Mage.Sets/src/mage/cards/b/BlessedReincarnation.java @@ -14,8 +14,11 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Library; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author fireshoes @@ -29,7 +32,7 @@ public final class BlessedReincarnation extends CardImpl { // That player reveals cards from the top of their library until a creature card is revealed. // The player puts that card onto the battlefield, then shuffles the rest into their library. this.getSpellAbility().addEffect(new BlessedReincarnationEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); // Rebound this.addAbility(new ReboundAbility()); diff --git a/Mage.Sets/src/mage/cards/b/BlindWithAnger.java b/Mage.Sets/src/mage/cards/b/BlindWithAnger.java index d9df645c333..59372af554c 100644 --- a/Mage.Sets/src/mage/cards/b/BlindWithAnger.java +++ b/Mage.Sets/src/mage/cards/b/BlindWithAnger.java @@ -14,6 +14,7 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -34,7 +35,7 @@ public final class BlindWithAnger extends CardImpl { this.getSpellAbility().addEffect(new UntapTargetEffect().setText("Untap target nonlegendary creature")); this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfTurn).setText("and gain control of it until end of turn")); this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn).setText("It gains haste until end of turn.")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private BlindWithAnger(final BlindWithAnger card) { diff --git a/Mage.Sets/src/mage/cards/b/BlisteringFirecat.java b/Mage.Sets/src/mage/cards/b/BlisteringFirecat.java index a614548fed7..e4b3d23da5e 100644 --- a/Mage.Sets/src/mage/cards/b/BlisteringFirecat.java +++ b/Mage.Sets/src/mage/cards/b/BlisteringFirecat.java @@ -1,28 +1,28 @@ package mage.cards.b; -import java.util.UUID; import mage.MageInt; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.MorphAbility; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.events.GameEvent; +import mage.constants.TargetController; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class BlisteringFirecat extends CardImpl { public BlisteringFirecat(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}{R}"); this.subtype.add(SubType.ELEMENTAL, SubType.CAT); this.power = new MageInt(7); @@ -30,10 +30,15 @@ public final class BlisteringFirecat extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); + // Haste this.addAbility(HasteAbility.getInstance()); + // At the beginning of the end step, sacrifice Blistering Firecat. - this.addAbility(new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new SacrificeSourceEffect())); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.NEXT, new SacrificeSourceEffect(), false + )); + // Morph {R}{R} this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{R}{R}"))); } diff --git a/Mage.Sets/src/mage/cards/b/BlizzardStrix.java b/Mage.Sets/src/mage/cards/b/BlizzardStrix.java index b412fd2f57f..f4b0f7f9fd5 100644 --- a/Mage.Sets/src/mage/cards/b/BlizzardStrix.java +++ b/Mage.Sets/src/mage/cards/b/BlizzardStrix.java @@ -52,7 +52,7 @@ public final class BlizzardStrix extends CardImpl { // When Blizzard Strix enters the battlefield, if you control another snow permanent, exile target permanent other than Blizzard Strix. Return that card to the battlefield under its owner's control at the beginning of the next end step. Ability ability = new EntersBattlefieldTriggeredAbility(new ExileReturnBattlefieldNextEndStepTargetEffect() .setText("exile target permanent other than {this}. Return that card to the " + - "battlefield under its owner's control at the beginning of the next end step")); + "battlefield under its owner's control at the beginning of the next end step")).withInterveningIf(condition); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BloatflySwarm.java b/Mage.Sets/src/mage/cards/b/BloatflySwarm.java index 2d8bd4db927..64c03583d53 100644 --- a/Mage.Sets/src/mage/cards/b/BloatflySwarm.java +++ b/Mage.Sets/src/mage/cards/b/BloatflySwarm.java @@ -59,7 +59,8 @@ class BloatflySwarmPreventionEffect extends PreventDamageAndRemoveCountersEffect BloatflySwarmPreventionEffect() { super(true, true, true); - staticText += ", then give each player a rad counter for each +1/+1 counter removed this way"; + staticText = "If damage would be dealt to {this} while it has a +1/+1 counter on it, prevent that damage, remove that many +1/+1 counters from it, " + + "then give each player a rad counter for each +1/+1 counter removed this way"; } private BloatflySwarmPreventionEffect(final BloatflySwarmPreventionEffect effect) { @@ -77,4 +78,4 @@ class BloatflySwarmPreventionEffect extends PreventDamageAndRemoveCountersEffect new AddCountersPlayersEffect(CounterType.RAD.createInstance(amountRemovedThisTime), TargetController.EACH_PLAYER) .apply(game, source); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/b/BloodFeud.java b/Mage.Sets/src/mage/cards/b/BloodFeud.java index d111a6aca6e..6f22087df5b 100644 --- a/Mage.Sets/src/mage/cards/b/BloodFeud.java +++ b/Mage.Sets/src/mage/cards/b/BloodFeud.java @@ -4,11 +4,13 @@ import mage.abilities.effects.common.FightTargetsEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2; + /** * @author intimidatingant */ @@ -19,13 +21,8 @@ public final class BloodFeud extends CardImpl { // Target creature fights another target creature. this.getSpellAbility().addEffect(new FightTargetsEffect()); - TargetCreaturePermanent target = new TargetCreaturePermanent(); - target.setTargetTag(1); - this.getSpellAbility().addTarget(target); - - TargetCreaturePermanent target2 = new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2); - target2.setTargetTag(2); - this.getSpellAbility().addTarget(target2); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_ANOTHER_CREATURE_TARGET_2).setTargetTag(2)); } private BloodFeud(final BloodFeud card) { diff --git a/Mage.Sets/src/mage/cards/b/BloodOperative.java b/Mage.Sets/src/mage/cards/b/BloodOperative.java index 15708ace750..cfa2b514498 100644 --- a/Mage.Sets/src/mage/cards/b/BloodOperative.java +++ b/Mage.Sets/src/mage/cards/b/BloodOperative.java @@ -1,6 +1,5 @@ package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -18,8 +17,9 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.target.common.TargetCardInGraveyard; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class BloodOperative extends CardImpl { @@ -42,7 +42,7 @@ public final class BloodOperative extends CardImpl { // Whenever you surveil, if Blood Operative is in your graveyard, you may pay 3 life. If you do, return Blood Operative to your hand. this.addAbility(new SurveilTriggeredAbility(Zone.GRAVEYARD, new DoIfCostPaid( - new ReturnSourceFromGraveyardToHandEffect().setText("return {this} to your hand"), new PayLifeCost(3) + new ReturnSourceFromGraveyardToHandEffect().setText("return this card to your hand"), new PayLifeCost(3) )).withInterveningIf(SourceInGraveyardCondition.instance)); } diff --git a/Mage.Sets/src/mage/cards/b/BloodchiefAscension.java b/Mage.Sets/src/mage/cards/b/BloodchiefAscension.java index a93045dbc35..d67884081cd 100644 --- a/Mage.Sets/src/mage/cards/b/BloodchiefAscension.java +++ b/Mage.Sets/src/mage/cards/b/BloodchiefAscension.java @@ -38,7 +38,7 @@ public final class BloodchiefAscension extends CardImpl { // Whenever a card is put into an opponent's graveyard from anywhere, if Bloodchief Ascension has three or more quest counters on it, you may have that player lose 2 life. If you do, you gain 2 life. Ability ability = new PutCardIntoGraveFromAnywhereAllTriggeredAbility( - new LoseLifeTargetEffect(2), true, StaticFilters.FILTER_CARD_A, + new LoseLifeTargetEffect(2).setText("have that player lose 2 life"), true, StaticFilters.FILTER_CARD_A, TargetController.OPPONENT, SetTargetPointer.PLAYER ).withInterveningIf(condition); ability.addEffect(new GainLifeEffect(2).concatBy("If you do,")); diff --git a/Mage.Sets/src/mage/cards/b/BloodcrazedHoplite.java b/Mage.Sets/src/mage/cards/b/BloodcrazedHoplite.java index c896e90e4b0..efa1b0069e5 100644 --- a/Mage.Sets/src/mage/cards/b/BloodcrazedHoplite.java +++ b/Mage.Sets/src/mage/cards/b/BloodcrazedHoplite.java @@ -17,8 +17,11 @@ import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -37,7 +40,7 @@ public final class BloodcrazedHoplite extends CardImpl { .withRuleTextReplacement(true)); // Whenever a +1/+1 counter is put on Bloodcrazed Hoplite, remove a +1/+1 counter from target creature an opponent controls. Ability ability = new BloodcrazedHopliteTriggeredAbility(); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BloodgiftDemon.java b/Mage.Sets/src/mage/cards/b/BloodgiftDemon.java index 82d28154c8e..a98599644ed 100644 --- a/Mage.Sets/src/mage/cards/b/BloodgiftDemon.java +++ b/Mage.Sets/src/mage/cards/b/BloodgiftDemon.java @@ -1,40 +1,36 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.OnEventTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardTargetEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.events.GameEvent.EventType; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author North */ public final class BloodgiftDemon extends CardImpl { public BloodgiftDemon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); this.subtype.add(SubType.DEMON); this.power = new MageInt(5); this.toughness = new MageInt(4); this.addAbility(FlyingAbility.getInstance()); + // At the beginning of your upkeep, target player draws a card and loses 1 life. - Ability ability = new OnEventTriggeredAbility(EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", new DrawCardTargetEffect(1), false); - Effect effect = new LoseLifeTargetEffect(1); - effect.setText("and loses 1 life"); - ability.addEffect(effect); + Ability ability = new BeginningOfUpkeepTriggeredAbility(new DrawCardTargetEffect(1)); + ability.addEffect(new LoseLifeTargetEffect(1).setText("and loses 1 life")); ability.addTarget(new TargetPlayer()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BloodlineKeeper.java b/Mage.Sets/src/mage/cards/b/BloodlineKeeper.java index 32dd7d98314..8cc8653d882 100644 --- a/Mage.Sets/src/mage/cards/b/BloodlineKeeper.java +++ b/Mage.Sets/src/mage/cards/b/BloodlineKeeper.java @@ -1,18 +1,17 @@ package mage.cards.b; -import java.util.UUID; - import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.TransformAbility; @@ -21,16 +20,22 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.game.permanent.token.VampireToken; +import java.util.UUID; + /** * @author Loki */ public final class BloodlineKeeper extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.VAMPIRE, "you control five or more Vampires"); + private static final FilterPermanent filter + = new FilterControlledPermanent(SubType.VAMPIRE, "you control five or more Vampires"); + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 4); + private static final Hint hint = new ValueHint("Vampires you control", new PermanentsOnBattlefieldCount(filter)); public BloodlineKeeper(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); @@ -42,15 +47,15 @@ public final class BloodlineKeeper extends CardImpl { this.secondSideCardClazz = mage.cards.l.LordOfLineage.class; this.addAbility(FlyingAbility.getInstance()); + // {T}: Create a 2/2 black Vampire creature token with flying. this.addAbility(new SimpleActivatedAbility(new CreateTokenEffect(new VampireToken()), new TapSourceCost())); + // {B}: Transform Bloodline Keeper. Activate this ability only if you control five or more Vampires. this.addAbility(new TransformAbility()); - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new TransformSourceEffect(), - new ManaCostsImpl<>("{B}"), - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 4)); - this.addAbility(ability.addHint(new ValueHint("Vampires you control", new PermanentsOnBattlefieldCount(filter)))); + this.addAbility(new ActivateIfConditionActivatedAbility( + new TransformSourceEffect(), new ManaCostsImpl<>("{B}"), condition + ).addHint(hint)); } private BloodlineKeeper(final BloodlineKeeper card) { diff --git a/Mage.Sets/src/mage/cards/b/BloodlinePretender.java b/Mage.Sets/src/mage/cards/b/BloodlinePretender.java index fde7782d705..67318b95b96 100644 --- a/Mage.Sets/src/mage/cards/b/BloodlinePretender.java +++ b/Mage.Sets/src/mage/cards/b/BloodlinePretender.java @@ -2,7 +2,7 @@ package mage.cards.b; import mage.MageInt; import mage.abilities.common.AsEntersBattlefieldAbility; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.ChooseCreatureTypeEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.ChangelingAbility; @@ -13,9 +13,9 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.ChosenSubtypePredicate; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.ChosenSubtypePredicate; import java.util.UUID; @@ -25,7 +25,7 @@ import java.util.UUID; public final class BloodlinePretender extends CardImpl { private static final FilterPermanent filter - = new FilterCreaturePermanent("another creature of the chosen type"); + = new FilterControlledCreaturePermanent("another creature you control of the chosen type"); static { filter.add(AnotherPredicate.instance); @@ -46,7 +46,7 @@ public final class BloodlinePretender extends CardImpl { this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.BoostCreature))); // Whenever another creature of the chosen type you control enters, put a +1/+1 counter on Bloodline Pretender. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + this.addAbility(new EntersBattlefieldAllTriggeredAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter )); } diff --git a/Mage.Sets/src/mage/cards/b/BloodshotTrainee.java b/Mage.Sets/src/mage/cards/b/BloodshotTrainee.java index a46fbb0e55e..06e20de7583 100644 --- a/Mage.Sets/src/mage/cards/b/BloodshotTrainee.java +++ b/Mage.Sets/src/mage/cards/b/BloodshotTrainee.java @@ -10,7 +10,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; @@ -31,8 +30,7 @@ public final class BloodshotTrainee extends CardImpl { this.toughness = new MageInt(3); Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new DamageTargetEffect(4), - new TapSourceCost(), BloodshotTraineeCondition.instance + new DamageTargetEffect(4), new TapSourceCost(), BloodshotTraineeCondition.instance ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/b/BloodsoakedChampion.java b/Mage.Sets/src/mage/cards/b/BloodsoakedChampion.java index fc6dd14922e..5b1c751f4b0 100644 --- a/Mage.Sets/src/mage/cards/b/BloodsoakedChampion.java +++ b/Mage.Sets/src/mage/cards/b/BloodsoakedChampion.java @@ -1,11 +1,10 @@ package mage.cards.b; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.CantBlockAbility; import mage.abilities.condition.common.RaidCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; import mage.abilities.hint.common.RaidHint; import mage.cards.CardImpl; @@ -34,15 +33,10 @@ public final class BloodsoakedChampion extends CardImpl { this.addAbility(new CantBlockAbility()); // Raid — {1}{B}: Return Bloodstained Brave from your graveyard to the battlefield. Activate this ability only if you attacked this turn. - Ability ability = new ConditionalActivatedAbility( - Zone.GRAVEYARD, - new ReturnSourceFromGraveyardToBattlefieldEffect(), - new ManaCostsImpl<>("{1}{B}"), - RaidCondition.instance, - "Raid — {1}{B}: Return {this} from your graveyard to the battlefield. Activate only if you attacked this turn."); - ability.setAbilityWord(AbilityWord.RAID); - ability.addHint(RaidHint.instance); - this.addAbility(ability, new PlayerAttackedWatcher()); + this.addAbility(new ActivateIfConditionActivatedAbility( + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(), + new ManaCostsImpl<>("{1}{B}"), RaidCondition.instance + ).setAbilityWord(AbilityWord.RAID).addHint(RaidHint.instance), new PlayerAttackedWatcher()); } private BloodsoakedChampion(final BloodsoakedChampion card) { diff --git a/Mage.Sets/src/mage/cards/b/BloodthirstyOgre.java b/Mage.Sets/src/mage/cards/b/BloodthirstyOgre.java index 7edbf9546fa..7700ca2cb92 100644 --- a/Mage.Sets/src/mage/cards/b/BloodthirstyOgre.java +++ b/Mage.Sets/src/mage/cards/b/BloodthirstyOgre.java @@ -1,10 +1,10 @@ package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.dynamicvalue.DynamicValue; @@ -17,37 +17,40 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterControlledPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX */ public final class BloodthirstyOgre extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.DEMON, "you control a Demon"); private static final DynamicValue xValue = new SignInversionDynamicValue(new CountersSourceCount(CounterType.DEVOTION)); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.DEMON, "you control a Demon") + ); + public BloodthirstyOgre(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.OGRE, SubType.WARRIOR, SubType.SHAMAN); this.power = new MageInt(3); this.toughness = new MageInt(1); // {T}: Put a devotion counter on Bloodthirsty Ogre - this.addAbility(new SimpleActivatedAbility(new AddCountersSourceEffect(CounterType.DEVOTION.createInstance()),new TapSourceCost())); + this.addAbility(new SimpleActivatedAbility(new AddCountersSourceEffect(CounterType.DEVOTION.createInstance()), new TapSourceCost())); // {T}: Target creature gets -X/-X until end of turn, where X is the number of devotion counters on Bloodthirsty Ogre. Activate this ability only if you control a Demon. - - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, + Ability ability = new ActivateIfConditionActivatedAbility( new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn) - .setText("target creature gets -X/-X until end of turn, where X is the number of devotion counters on {this}"), - new TapSourceCost(), - new PermanentsOnTheBattlefieldCondition(filter)); + .setText("target creature gets -X/-X until end of turn, " + + "where X is the number of devotion counters on {this}"), + new TapSourceCost(), condition + ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BloodthornTaunter.java b/Mage.Sets/src/mage/cards/b/BloodthornTaunter.java index 72f4f37bf0f..2ca642a082d 100644 --- a/Mage.Sets/src/mage/cards/b/BloodthornTaunter.java +++ b/Mage.Sets/src/mage/cards/b/BloodthornTaunter.java @@ -12,6 +12,7 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class BloodthornTaunter extends CardImpl { SimpleActivatedAbility ability = new SimpleActivatedAbility( new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BlueDragon.java b/Mage.Sets/src/mage/cards/b/BlueDragon.java index 146ade129ea..80c5a184120 100644 --- a/Mage.Sets/src/mage/cards/b/BlueDragon.java +++ b/Mage.Sets/src/mage/cards/b/BlueDragon.java @@ -14,7 +14,7 @@ import mage.filter.predicate.other.AnotherTargetPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetOpponentsCreaturePermanent; import java.util.HashMap; @@ -23,7 +23,6 @@ import java.util.Map; import java.util.UUID; /** - * * @author weirddan455 */ public final class BlueDragon extends CardImpl { @@ -48,19 +47,9 @@ public final class BlueDragon extends CardImpl { // Lightning Breath — When Blue Dragon enters the battlefield, until your next turn, target creature an opponent controls gets -3/-0, up to one other target creature gets -2/-0, and up to one other target creature gets -1/-0. Ability ability = new EntersBattlefieldTriggeredAbility(new BlueDragonEffect()); - - Target target = new TargetOpponentsCreaturePermanent(); - target.setTargetTag(1); - ability.addTarget(target.withChooseHint("-3/-0")); - - target = new TargetCreaturePermanent(0, 1, filter2, false); - target.setTargetTag(2); - ability.addTarget(target.withChooseHint("-2/-0")); - - target = new TargetCreaturePermanent(0, 1, filter3, false); - target.setTargetTag(3); - ability.addTarget(target.withChooseHint("-1/-0")); - + ability.addTarget(new TargetOpponentsCreaturePermanent().setTargetTag(1).withChooseHint("-3/-0")); + ability.addTarget(new TargetPermanent(0, 1, filter2).setTargetTag(2).withChooseHint("-2/-0")); + ability.addTarget(new TargetPermanent(0, 1, filter3).setTargetTag(3).withChooseHint("-1/-0")); this.addAbility(ability.withFlavorWord("Lightning Breath")); } diff --git a/Mage.Sets/src/mage/cards/b/Blustersquall.java b/Mage.Sets/src/mage/cards/b/Blustersquall.java index 36edbe06932..0bfe1d44ba7 100644 --- a/Mage.Sets/src/mage/cards/b/Blustersquall.java +++ b/Mage.Sets/src/mage/cards/b/Blustersquall.java @@ -13,10 +13,13 @@ import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author LevelX2 */ @@ -26,7 +29,7 @@ public final class Blustersquall extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); // Tap target creature you don't control. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.getSpellAbility().addEffect(new TapTargetEffect()); // Overload {3}{U} (You may cast this spell for its overload cost. If you do, change its text by replacing all instances of "target" with "each.") diff --git a/Mage.Sets/src/mage/cards/b/BondersEnclave.java b/Mage.Sets/src/mage/cards/b/BondersEnclave.java index dee8f3a5d1f..e6a23309340 100644 --- a/Mage.Sets/src/mage/cards/b/BondersEnclave.java +++ b/Mage.Sets/src/mage/cards/b/BondersEnclave.java @@ -10,7 +10,6 @@ import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import java.util.UUID; @@ -27,8 +26,7 @@ public final class BondersEnclave extends CardImpl { // {3}, {T}: Draw a card. Activate this ability only if you control a creature with power 4 or greater. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), - new GenericManaCost(3), FerociousCondition.instance + new DrawCardSourceControllerEffect(1), new GenericManaCost(3), FerociousCondition.instance ); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/b/BoneShredder.java b/Mage.Sets/src/mage/cards/b/BoneShredder.java index ddd06ccdaaa..e752b07ffa0 100644 --- a/Mage.Sets/src/mage/cards/b/BoneShredder.java +++ b/Mage.Sets/src/mage/cards/b/BoneShredder.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -43,7 +44,7 @@ public final class BoneShredder extends CardImpl { //When Bone Shredder enters the battlefield, destroy target nonartifact, nonblack creature. Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(false)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BoobyTrap.java b/Mage.Sets/src/mage/cards/b/BoobyTrap.java index f8fd5f92907..e26b8ebf1af 100644 --- a/Mage.Sets/src/mage/cards/b/BoobyTrap.java +++ b/Mage.Sets/src/mage/cards/b/BoobyTrap.java @@ -91,7 +91,7 @@ class BoobyTrapTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "The chosen player reveals each card they draw.\n" + + return "The chosen player reveals each card they draw.
" + "When the chosen player draws the named card, sacrifice {this}. If you do, {this} deals 10 damage to that player."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/b/BoosterTutor.java b/Mage.Sets/src/mage/cards/b/BoosterTutor.java index 99c9ca6c21b..de4d70bdc37 100644 --- a/Mage.Sets/src/mage/cards/b/BoosterTutor.java +++ b/Mage.Sets/src/mage/cards/b/BoosterTutor.java @@ -91,7 +91,7 @@ class BoosterTutorEffect extends OneShotEffect { game.loadCards(cardsToLoad, controller.getId()); CardsImpl cards = new CardsImpl(); cards.addAllCards(boosterPack); - if (controller.choose(Outcome.Benefit, cards, targetCard, source, game)) { + if (controller.choose(Outcome.PutCardInPlay, cards, targetCard, source, game)) { Card card = game.getCard(targetCard.getFirstTarget()); if (card != null) { controller.moveCards(card, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/b/BorealOutrider.java b/Mage.Sets/src/mage/cards/b/BorealOutrider.java index 94b9fd62674..d220f910a7d 100644 --- a/Mage.Sets/src/mage/cards/b/BorealOutrider.java +++ b/Mage.Sets/src/mage/cards/b/BorealOutrider.java @@ -61,7 +61,7 @@ enum BorealOutriderCondition implements Condition { @Override public String toString() { - return "{S} of any of that spell's color was spent to cast it"; + return "{S} of any of that spell's colors was spent to cast it"; } } @@ -69,6 +69,7 @@ class BorealOutriderEffect extends ReplacementEffectImpl { BorealOutriderEffect() { super(Duration.EndOfStep, Outcome.BoostCreature); + staticText = "that creature enters with an additional +1/+1 counter on it"; } private BorealOutriderEffect(BorealOutriderEffect effect) { diff --git a/Mage.Sets/src/mage/cards/b/BorosFuryShield.java b/Mage.Sets/src/mage/cards/b/BorosFuryShield.java index 80bc35cb960..2e90adce7d9 100644 --- a/Mage.Sets/src/mage/cards/b/BorosFuryShield.java +++ b/Mage.Sets/src/mage/cards/b/BorosFuryShield.java @@ -15,6 +15,7 @@ import mage.filter.common.FilterAttackingOrBlockingCreature; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class BorosFuryShield extends CardImpl { // Prevent all combat damage that would be dealt by target attacking or blocking creature this turn. this.getSpellAbility().addEffect(new PreventDamageByTargetEffect(Duration.EndOfTurn, true)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // If {R} was spent to cast Boros Fury-Shield, it deals damage to that creature's controller equal to the creature's power. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( diff --git a/Mage.Sets/src/mage/cards/b/BorrowedHostility.java b/Mage.Sets/src/mage/cards/b/BorrowedHostility.java index 780b8319a26..03cb05fcedb 100644 --- a/Mage.Sets/src/mage/cards/b/BorrowedHostility.java +++ b/Mage.Sets/src/mage/cards/b/BorrowedHostility.java @@ -12,6 +12,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -38,13 +39,13 @@ public final class BorrowedHostility extends CardImpl { Effect effect = new BoostTargetEffect(3, 0, Duration.EndOfTurn); effect.setText("Target creature gets +3/+0 until end of turn"); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterBoost).withChooseHint("gets +3/+0 until end of turn")); + this.getSpellAbility().addTarget(new TargetPermanent(filterBoost).withChooseHint("gets +3/+0 until end of turn")); // Target creature gains first strike until end of turn. effect = new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn); effect.setText("Target creature gains first strike until end of turn"); Mode mode = new Mode(effect); - mode.addTarget(new TargetCreaturePermanent(filterFirstStrike).withChooseHint("gains first strike until end of turn")); + mode.addTarget(new TargetPermanent(filterFirstStrike).withChooseHint("gains first strike until end of turn")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/b/BorrowedMalevolence.java b/Mage.Sets/src/mage/cards/b/BorrowedMalevolence.java index f427b1c6db0..4b1d3d46e1d 100644 --- a/Mage.Sets/src/mage/cards/b/BorrowedMalevolence.java +++ b/Mage.Sets/src/mage/cards/b/BorrowedMalevolence.java @@ -10,6 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -36,13 +37,13 @@ public final class BorrowedMalevolence extends CardImpl { Effect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn); effect.setText("Target creature gets +1/+1 until end of turn"); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterCreaturePlus).withChooseHint("gets +1/+1 until end of turn")); + this.getSpellAbility().addTarget(new TargetPermanent(filterCreaturePlus).withChooseHint("gets +1/+1 until end of turn")); // Target creature gets -1/-1 until end of turn. effect = new BoostTargetEffect(-1, -1, Duration.EndOfTurn); effect.setText("Target creature gets -1/-1 until end of turn"); Mode mode = new Mode(effect); - mode.addTarget(new TargetCreaturePermanent(filterCreatureMinus).withChooseHint("gets -1/-1 until end of turn")); + mode.addTarget(new TargetPermanent(filterCreatureMinus).withChooseHint("gets -1/-1 until end of turn")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/b/BountyHunter.java b/Mage.Sets/src/mage/cards/b/BountyHunter.java index 365dc646545..09d3c48adec 100644 --- a/Mage.Sets/src/mage/cards/b/BountyHunter.java +++ b/Mage.Sets/src/mage/cards/b/BountyHunter.java @@ -14,10 +14,13 @@ import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author LoneFox @@ -38,11 +41,11 @@ public final class BountyHunter extends CardImpl { // {tap}: Put a bounty counter on target nonblack creature. Ability ability = new SimpleActivatedAbility(new AddCountersTargetEffect(CounterType.BOUNTY.createInstance()), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + ability.addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.addAbility(ability); // {tap}: Destroy target creature with a bounty counter on it. ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BowOfNylea.java b/Mage.Sets/src/mage/cards/b/BowOfNylea.java index 2cccbf04f28..967859d2bb2 100644 --- a/Mage.Sets/src/mage/cards/b/BowOfNylea.java +++ b/Mage.Sets/src/mage/cards/b/BowOfNylea.java @@ -20,6 +20,7 @@ import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCreaturePermanent; @@ -49,7 +50,7 @@ public final class BowOfNylea extends CardImpl { ability.addCost(new TapSourceCost()); // or Bow of Nylea deals 2 damage to target creature with flying; Mode mode = new Mode(new DamageTargetEffect(2)); - mode.addTarget(new TargetCreaturePermanent(filterFlying)); + mode.addTarget(new TargetPermanent(filterFlying)); ability.addMode(mode); // or you gain 3 life; mode = new Mode(new GainLifeEffect(3)); diff --git a/Mage.Sets/src/mage/cards/b/BoxingRing.java b/Mage.Sets/src/mage/cards/b/BoxingRing.java index 9c9fbb84a4a..cab3c136b8e 100644 --- a/Mage.Sets/src/mage/cards/b/BoxingRing.java +++ b/Mage.Sets/src/mage/cards/b/BoxingRing.java @@ -6,12 +6,15 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.WatcherScope; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; @@ -53,9 +56,8 @@ public final class BoxingRing extends CardImpl { this.addAbility(ability); // {T}: Create a Treasure token. Activate only if you control a creature that fought this turn. - this.addAbility(new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new CreateTokenEffect(new TreasureToken()), - new TapSourceCost(), BoxingRingCondition.instance + this.addAbility(new ActivateIfConditionActivatedAbility( + new CreateTokenEffect(new TreasureToken()), new TapSourceCost(), BoxingRingCondition.instance ), new BoxingRingWatcher()); } diff --git a/Mage.Sets/src/mage/cards/b/BraceForImpact.java b/Mage.Sets/src/mage/cards/b/BraceForImpact.java index f98d54ec04a..68e94370dd2 100644 --- a/Mage.Sets/src/mage/cards/b/BraceForImpact.java +++ b/Mage.Sets/src/mage/cards/b/BraceForImpact.java @@ -15,6 +15,7 @@ import mage.game.events.GameEvent; import mage.game.events.PreventDamageEvent; import mage.game.events.PreventedDamageEvent; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -35,7 +36,7 @@ public final class BraceForImpact extends CardImpl { // Prevent all damage that would be dealt to target multicolored creature this turn. For each 1 damage prevented this way, put a +1/+1 counter on that creature. this.getSpellAbility().addEffect(new BraceForImpactPreventDamageTargetEffect(Duration.EndOfTurn)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private BraceForImpact(final BraceForImpact card) { diff --git a/Mage.Sets/src/mage/cards/b/Brainspoil.java b/Mage.Sets/src/mage/cards/b/Brainspoil.java index b0185041d08..5d016a67639 100644 --- a/Mage.Sets/src/mage/cards/b/Brainspoil.java +++ b/Mage.Sets/src/mage/cards/b/Brainspoil.java @@ -10,6 +10,7 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.EnchantedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class Brainspoil extends CardImpl { // Destroy target creature that isn't enchanted. It can't be regenerated. this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Transmute {1}{B}{B} this.addAbility(new TransmuteAbility("{1}{B}{B}")); diff --git a/Mage.Sets/src/mage/cards/b/BrainstealerDragon.java b/Mage.Sets/src/mage/cards/b/BrainstealerDragon.java index 51191b395c7..0fc11fb4d03 100644 --- a/Mage.Sets/src/mage/cards/b/BrainstealerDragon.java +++ b/Mage.Sets/src/mage/cards/b/BrainstealerDragon.java @@ -2,10 +2,10 @@ package mage.cards.b; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.*; import mage.constants.*; import mage.filter.FilterPermanent; @@ -23,8 +23,7 @@ import java.util.UUID; */ public final class BrainstealerDragon extends CardImpl { - private static final FilterPermanent filter - = new FilterNonlandPermanent("a nonland permanent an opponent owns"); + private static final FilterPermanent filter = new FilterNonlandPermanent(); static { filter.add(TargetController.OPPONENT.getOwnerPredicate()); @@ -42,15 +41,12 @@ public final class BrainstealerDragon extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // At the beginning of your end step, exile the top card of each opponent's library. You may play those cards for as long as they remain exiled. If you cast a spell this way, you may spend mana as though it were mana of any color to cast it. - this.addAbility(new BeginningOfEndStepTriggeredAbility( - new BrainstealerDragonExileEffect() - )); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new BrainstealerDragonExileEffect())); // Whenever a nonland permanent an opponent owns you control enters, they lose life equal to its mana value. this.addAbility(new EntersBattlefieldControlledTriggeredAbility( - Zone.BATTLEFIELD, new BrainstealerDragonLifeEffect(), filter, - false, SetTargetPointer.PERMANENT - )); + Zone.BATTLEFIELD, new BrainstealerDragonLifeEffect(), filter, false, SetTargetPointer.PERMANENT + ).setTriggerPhrase("Whenever a nonland permanent an opponent owns enters the battlefield under your control, ")); } private BrainstealerDragon(final BrainstealerDragon card) { diff --git a/Mage.Sets/src/mage/cards/b/BramblefortFink.java b/Mage.Sets/src/mage/cards/b/BramblefortFink.java index dfb393b5f22..29d9f47e9ee 100644 --- a/Mage.Sets/src/mage/cards/b/BramblefortFink.java +++ b/Mage.Sets/src/mage/cards/b/BramblefortFink.java @@ -8,8 +8,9 @@ import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterPermanent; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.common.FilterControlledPlaneswalkerPermanent; import java.util.UUID; @@ -19,9 +20,9 @@ import java.util.UUID; */ public final class BramblefortFink extends CardImpl { - private static final FilterPermanent filter - = new FilterControlledPlaneswalkerPermanent(SubType.OKO, "you control an Oko planeswalker"); - private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPlaneswalkerPermanent(SubType.OKO, "you control an Oko planeswalker") + ); public BramblefortFink(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); @@ -32,10 +33,10 @@ public final class BramblefortFink extends CardImpl { // {8}: Bramblefort Fink has base power and toughness 10/10 until end of turn. Activate this ability only if you control an Oko planeswalker. this.addAbility(new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new SetBasePowerToughnessSourceEffect(10, 10, Duration.EndOfTurn), - new GenericManaCost(8), - condition)); + new SetBasePowerToughnessSourceEffect( + 10, 10, Duration.EndOfTurn + ), new GenericManaCost(8), condition + )); } private BramblefortFink(final BramblefortFink card) { diff --git a/Mage.Sets/src/mage/cards/b/BranchingBolt.java b/Mage.Sets/src/mage/cards/b/BranchingBolt.java index b5fca894864..f9da1d99e24 100644 --- a/Mage.Sets/src/mage/cards/b/BranchingBolt.java +++ b/Mage.Sets/src/mage/cards/b/BranchingBolt.java @@ -14,6 +14,7 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -39,10 +40,10 @@ public final class BranchingBolt extends CardImpl { this.getSpellAbility().getModes().setMaxModes(2); // Branching Bolt deals 3 damage to target creature with flying; this.getSpellAbility().addEffect(new DamageTargetEffect(3)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterFlying).withChooseHint("deals 3 damage, without flying")); + this.getSpellAbility().addTarget(new TargetPermanent(filterFlying).withChooseHint("deals 3 damage, without flying")); // or Branching Bolt deals 3 damage to target creature without flying. Mode mode = new Mode(new DamageTargetEffect(3)); - mode.addTarget(new TargetCreaturePermanent(filterNotFlying).withChooseHint("deals 3 damage, without flying")); + mode.addTarget(new TargetPermanent(filterNotFlying).withChooseHint("deals 3 damage, without flying")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/b/BrassTalonChimera.java b/Mage.Sets/src/mage/cards/b/BrassTalonChimera.java index 232469aaf02..42ef018d9cf 100644 --- a/Mage.Sets/src/mage/cards/b/BrassTalonChimera.java +++ b/Mage.Sets/src/mage/cards/b/BrassTalonChimera.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -44,7 +45,7 @@ public final class BrassTalonChimera extends CardImpl { Ability ability = new SimpleActivatedAbility(new AddCountersTargetEffect(CounterType.P2P2.createInstance()), new SacrificeSourceCost()); ability.addEffect(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield) .setText("It gains first strike. (This effect lasts indefinitely.)")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BreachingHippocamp.java b/Mage.Sets/src/mage/cards/b/BreachingHippocamp.java index 69ec028f5f4..4cf6bc6a89e 100644 --- a/Mage.Sets/src/mage/cards/b/BreachingHippocamp.java +++ b/Mage.Sets/src/mage/cards/b/BreachingHippocamp.java @@ -1,6 +1,5 @@ package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -11,16 +10,17 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class BreachingHippocamp extends CardImpl { public BreachingHippocamp(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); this.subtype.add(SubType.HORSE, SubType.FISH); this.power = new MageInt(3); @@ -28,9 +28,10 @@ public final class BreachingHippocamp extends CardImpl { // Flash this.addAbility(FlashAbility.getInstance()); + // When Breaching Hippocamp enters the battlefield, untap another target creature you control. Ability ability = new EntersBattlefieldTriggeredAbility(new UntapTargetEffect(), false); - ability.addTarget(new TargetControlledCreaturePermanent(1,1, StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL, false)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BreakOpen.java b/Mage.Sets/src/mage/cards/b/BreakOpen.java index ae00e8d7762..32b1d9317aa 100644 --- a/Mage.Sets/src/mage/cards/b/BreakOpen.java +++ b/Mage.Sets/src/mage/cards/b/BreakOpen.java @@ -9,6 +9,7 @@ import mage.constants.CardType; import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.card.FaceDownPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class BreakOpen extends CardImpl { // Turn target face-down creature an opponent controls face up. this.getSpellAbility().addEffect(new TurnFaceUpTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private BreakOpen(final BreakOpen card) { diff --git a/Mage.Sets/src/mage/cards/b/BreakThroughTheLine.java b/Mage.Sets/src/mage/cards/b/BreakThroughTheLine.java index 197a4e6b965..a9d1dd390fa 100644 --- a/Mage.Sets/src/mage/cards/b/BreakThroughTheLine.java +++ b/Mage.Sets/src/mage/cards/b/BreakThroughTheLine.java @@ -17,6 +17,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class BreakThroughTheLine extends CardImpl { Effect effect = new CantBeBlockedTargetEffect(Duration.EndOfTurn); effect.setText("and can't be blocked this turn"); ability.addEffect(effect); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BreakingOfTheFellowship.java b/Mage.Sets/src/mage/cards/b/BreakingOfTheFellowship.java index 2a4438cf23c..6b1449b7d2e 100644 --- a/Mage.Sets/src/mage/cards/b/BreakingOfTheFellowship.java +++ b/Mage.Sets/src/mage/cards/b/BreakingOfTheFellowship.java @@ -16,6 +16,7 @@ import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -30,8 +31,8 @@ public final class BreakingOfTheFellowship extends CardImpl { // Target creature an opponent controls deals damage equal to its power to another target creature that player controls. this.getSpellAbility().addEffect(new BreakingOfTheFellowshipEffect()); - this.getSpellAbility().addTarget(new BreakingOfTheFellowshipFirstTarget(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("another target creature that player controls"))); + this.getSpellAbility().addTarget(new BreakingOfTheFellowshipFirstTarget()); + this.getSpellAbility().addTarget(new TargetPermanent(new FilterCreaturePermanent("another target creature that player controls"))); // The Ring tempts you. this.getSpellAbility().addEffect(new TheRingTemptsYouEffect()); @@ -78,10 +79,10 @@ class BreakingOfTheFellowshipEffect extends OneShotEffect { } -class BreakingOfTheFellowshipFirstTarget extends TargetCreaturePermanent { +class BreakingOfTheFellowshipFirstTarget extends TargetPermanent { - public BreakingOfTheFellowshipFirstTarget(FilterCreaturePermanent filter) { - super(1, 1, filter, false); + public BreakingOfTheFellowshipFirstTarget() { + super(1, 1, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, false); } private BreakingOfTheFellowshipFirstTarget(final BreakingOfTheFellowshipFirstTarget target) { diff --git a/Mage.Sets/src/mage/cards/b/BreathOfFury.java b/Mage.Sets/src/mage/cards/b/BreathOfFury.java index f1f676514f3..01a40680699 100644 --- a/Mage.Sets/src/mage/cards/b/BreathOfFury.java +++ b/Mage.Sets/src/mage/cards/b/BreathOfFury.java @@ -1,7 +1,6 @@ package mage.cards.b; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; @@ -23,6 +22,8 @@ import mage.target.Target; import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** * @author duncant */ @@ -119,7 +120,7 @@ class BreathOfFuryEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature you control that could be enchanted by " + enchantment.getName()); filter.add(new CanBeEnchantedByPredicate(enchantment)); - Target target = new TargetControlledCreaturePermanent(filter); + Target target = new TargetPermanent(filter); target.withNotTarget(true); // It's important to check that the creature was successfully sacrificed here. Effects that prevent sacrifice will also prevent Breath of Fury's effect from working. // Commanders going to the command zone and Rest in Peace style replacement effects don't make Permanent.sacrifice return false. diff --git a/Mage.Sets/src/mage/cards/b/BridgeFromBelow.java b/Mage.Sets/src/mage/cards/b/BridgeFromBelow.java index 0be4df74c26..6fc26f76090 100644 --- a/Mage.Sets/src/mage/cards/b/BridgeFromBelow.java +++ b/Mage.Sets/src/mage/cards/b/BridgeFromBelow.java @@ -1,8 +1,7 @@ package mage.cards.b; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.condition.common.SourceInGraveyardCondition; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.ExileSourceEffect; import mage.cards.CardImpl; @@ -10,24 +9,20 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TargetController; import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TokenPredicate; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.ZoneChangeEvent; -import mage.game.permanent.Permanent; import mage.game.permanent.token.ZombieToken; import java.util.UUID; /** - * * @author Plopman */ public final class BridgeFromBelow extends CardImpl { - private static final FilterCreaturePermanent filter1 = new FilterCreaturePermanent("Whenever a nontoken creature is put into your graveyard from the battlefield, "); - private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("When a creature is put into an opponent's graveyard from the battlefield, "); + private static final FilterPermanent filter1 = new FilterCreaturePermanent(); + private static final FilterPermanent filter2 = new FilterCreaturePermanent(); static { filter1.add(TargetController.YOU.getOwnerPredicate()); @@ -39,11 +34,18 @@ public final class BridgeFromBelow extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}{B}{B}"); // Whenever a nontoken creature is put into your graveyard from the battlefield, if Bridge from Below is in your graveyard, create a 2/2 black Zombie creature token. - this.addAbility(new BridgeFromBelowAbility(new CreateTokenEffect(new ZombieToken()), filter1)); + this.addAbility(new DiesCreatureTriggeredAbility( + Zone.GRAVEYARD, new CreateTokenEffect(new ZombieToken()), + false, filter1, false + ).setTriggerPhrase("Whenever a nontoken creature is put into your graveyard from the battlefield, ") + .withInterveningIf(SourceInGraveyardCondition.instance)); // When a creature is put into an opponent's graveyard from the battlefield, if Bridge from Below is in your graveyard, exile Bridge from Below. - this.addAbility(new BridgeFromBelowAbility(new ExileSourceEffect(), filter2)); - + this.addAbility(new DiesCreatureTriggeredAbility( + Zone.GRAVEYARD, new ExileSourceEffect().setText("exile this card"), + false, filter2, false + ).setTriggerPhrase("When a creature is put into an opponent's graveyard from the battlefield, ") + .withInterveningIf(SourceInGraveyardCondition.instance)); } private BridgeFromBelow(final BridgeFromBelow card) { @@ -55,41 +57,3 @@ public final class BridgeFromBelow extends CardImpl { return new BridgeFromBelow(this); } } - -class BridgeFromBelowAbility extends TriggeredAbilityImpl { - - private final FilterCreaturePermanent filter; - - BridgeFromBelowAbility(Effect effect, FilterCreaturePermanent filter) { - super(Zone.GRAVEYARD, effect, false); - this.filter = filter; - this.withInterveningIf(SourceInGraveyardCondition.instance); - setTriggerPhrase(filter.getMessage()); - setLeavesTheBattlefieldTrigger(true); // it's not required for Bridge from Below, but better to keep same code style and verify pass - } - - private BridgeFromBelowAbility(final BridgeFromBelowAbility ability) { - super(ability); - this.filter = ability.filter; - } - - @Override - public BridgeFromBelowAbility copy() { - return new BridgeFromBelowAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ZONE_CHANGE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); - if (permanent == null || !((ZoneChangeEvent) event).isDiesEvent()) { - return false; - } - return filter.match(permanent, controllerId, this, game); - } - -} diff --git a/Mage.Sets/src/mage/cards/b/BringLow.java b/Mage.Sets/src/mage/cards/b/BringLow.java index 70c9b810e44..e700d5f6f34 100644 --- a/Mage.Sets/src/mage/cards/b/BringLow.java +++ b/Mage.Sets/src/mage/cards/b/BringLow.java @@ -1,7 +1,6 @@ package mage.cards.b; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.decorator.ConditionalOneShotEffect; @@ -14,6 +13,8 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * * @author LevelX2 @@ -29,7 +30,7 @@ public final class BringLow extends CardImpl { new DamageTargetEffect(5), new DamageTargetEffect(3), new TargetHasCounterCondition(CounterType.P1P1), - "{this} deals 3 damage to target creature. If that creature has a +1/+1 counter on it, Bring Low deals 5 damage to it instead")); + "{this} deals 3 damage to target creature. If that creature has a +1/+1 counter on it, {this} deals 5 damage to it instead")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/b/BringToTrial.java b/Mage.Sets/src/mage/cards/b/BringToTrial.java index c1bbac58820..a1d5b8a3d46 100644 --- a/Mage.Sets/src/mage/cards/b/BringToTrial.java +++ b/Mage.Sets/src/mage/cards/b/BringToTrial.java @@ -7,6 +7,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -28,7 +29,7 @@ public final class BringToTrial extends CardImpl { // Exile target creature with power 4 or greater. this.getSpellAbility().addEffect(new ExileTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private BringToTrial(final BringToTrial card) { diff --git a/Mage.Sets/src/mage/cards/b/BrinkOfMadness.java b/Mage.Sets/src/mage/cards/b/BrinkOfMadness.java index a0181157d5a..7e3653f13a8 100644 --- a/Mage.Sets/src/mage/cards/b/BrinkOfMadness.java +++ b/Mage.Sets/src/mage/cards/b/BrinkOfMadness.java @@ -1,14 +1,13 @@ package mage.cards.b; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.condition.common.CardsInHandCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.Ability; +import mage.abilities.condition.common.HellbentCondition; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.discard.DiscardHandTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; import mage.target.common.TargetOpponent; import java.util.UUID; @@ -22,12 +21,10 @@ public final class BrinkOfMadness extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); // At the beginning of your upkeep, if you have no cards in hand, sacrifice Brink of Madness and target opponent discards their hand. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceEffect()); - ability.addEffect(new DiscardHandTargetEffect()); + Ability ability = new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceEffect()).withInterveningIf(HellbentCondition.instance); + ability.addEffect(new DiscardHandTargetEffect().concatBy("and")); ability.addTarget(new TargetOpponent()); - CardsInHandCondition condition = new CardsInHandCondition(ComparisonType.EQUAL_TO, 0); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, condition, "At the beginning of your upkeep, if you have no cards in hand, sacrifice {this} and target opponent discards their hand.")); - + this.addAbility(ability); } private BrinkOfMadness(final BrinkOfMadness card) { diff --git a/Mage.Sets/src/mage/cards/b/BrokenDam.java b/Mage.Sets/src/mage/cards/b/BrokenDam.java index 46f0f144bff..f55a0bb78cc 100644 --- a/Mage.Sets/src/mage/cards/b/BrokenDam.java +++ b/Mage.Sets/src/mage/cards/b/BrokenDam.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.keyword.HorsemanshipAbility; import mage.cards.CardImpl; @@ -10,26 +8,27 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LoneFox */ public final class BrokenDam extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures without horsemanship"); static { filter.add(Predicates.not(new AbilityPredicate(HorsemanshipAbility.class))); } - public BrokenDam(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{U}"); + public BrokenDam(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}"); // Tap one or two target creatures without horsemanship. this.getSpellAbility().addEffect(new TapTargetEffect("tap one or two target creatures without horsemanship")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(1, 2, filter, false)); + this.getSpellAbility().addTarget(new TargetPermanent(1, 2, filter)); } private BrokenDam(final BrokenDam card) { diff --git a/Mage.Sets/src/mage/cards/b/BrokenVisage.java b/Mage.Sets/src/mage/cards/b/BrokenVisage.java index cee7109e816..923988b0ae5 100644 --- a/Mage.Sets/src/mage/cards/b/BrokenVisage.java +++ b/Mage.Sets/src/mage/cards/b/BrokenVisage.java @@ -18,6 +18,7 @@ import mage.filter.predicate.permanent.AttackingPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.BrokenVisageSpiritToken; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -38,7 +39,7 @@ public final class BrokenVisage extends CardImpl { // Destroy target nonartifact attacking creature. It can't be regenerated. Create a black Spirit creature token. Its power is equal to that creature's power and its toughness is equal to that creature's toughness. Sacrifice the token at the beginning of the next end step. this.getSpellAbility().addEffect(new BrokenVisageEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private BrokenVisage(final BrokenVisage card) { diff --git a/Mage.Sets/src/mage/cards/b/BrotherhoodRegalia.java b/Mage.Sets/src/mage/cards/b/BrotherhoodRegalia.java index 59b49b5e15c..e7dd7f1df12 100644 --- a/Mage.Sets/src/mage/cards/b/BrotherhoodRegalia.java +++ b/Mage.Sets/src/mage/cards/b/BrotherhoodRegalia.java @@ -12,7 +12,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -23,6 +23,7 @@ public final class BrotherhoodRegalia extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("legendary creature"); + static { filter.add(SuperType.LEGENDARY.getPredicate()); } @@ -44,7 +45,7 @@ public final class BrotherhoodRegalia extends CardImpl { this.addAbility(ability); // Equip legendary creature {1} - this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(1), new TargetControlledCreaturePermanent(filter), false)); + this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(1), new TargetPermanent(filter), false)); // Equip {3} this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(3), true)); diff --git a/Mage.Sets/src/mage/cards/b/BrotherhoodScribe.java b/Mage.Sets/src/mage/cards/b/BrotherhoodScribe.java index af932033555..eebfc363f3c 100644 --- a/Mage.Sets/src/mage/cards/b/BrotherhoodScribe.java +++ b/Mage.Sets/src/mage/cards/b/BrotherhoodScribe.java @@ -7,7 +7,7 @@ import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.condition.common.MetalcraftCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.counter.GetEnergyCountersControllerEffect; import mage.abilities.hint.common.MetalcraftHint; @@ -32,7 +32,7 @@ public final class BrotherhoodScribe extends CardImpl { this.toughness = new MageInt(3); // Metalcraft -- {T}: You get {E}. Activate only if you control three or more artifacts. - this.addAbility(new ConditionalActivatedAbility( + this.addAbility(new ActivateIfConditionActivatedAbility( new GetEnergyCountersControllerEffect(1), new TapSourceCost(), MetalcraftCondition.instance) diff --git a/Mage.Sets/src/mage/cards/b/BrotherhoodSpy.java b/Mage.Sets/src/mage/cards/b/BrotherhoodSpy.java index e3a2af67a09..e5251a1d417 100644 --- a/Mage.Sets/src/mage/cards/b/BrotherhoodSpy.java +++ b/Mage.Sets/src/mage/cards/b/BrotherhoodSpy.java @@ -2,17 +2,19 @@ package mage.cards.b; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; -import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; @@ -23,14 +25,15 @@ import java.util.UUID; */ public final class BrotherhoodSpy extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent(SubType.ASSASSIN); + private static final FilterPermanent filter + = new FilterControlledPermanent(SubType.ASSASSIN, "you control a legendary Assassin"); static { filter.add(SuperType.LEGENDARY.getPredicate()); } private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); - private static final Hint hint = new ConditionHint(condition, "You control a legendary Assassin"); + private static final Hint hint = new ConditionHint(condition); public BrotherhoodSpy(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); @@ -41,13 +44,11 @@ public final class BrotherhoodSpy extends CardImpl { this.toughness = new MageInt(3); // At the beginning of combat on your turn, if you control a legendary Assassin, Brotherhood Spy gets +1/+0 until end of turn and can't be blocked this turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - new BoostTargetEffect(1, 0) - ), condition, "At the beginning of combat on your turn, if you control a legendary Assassin, " + - "{this} gets +1/+0 until end of turn and can't be blocked this turn." - ); - ability.addEffect(new CantBeBlockedSourceEffect(Duration.EndOfTurn)); + Ability ability = new BeginningOfCombatTriggeredAbility( + new BoostSourceEffect(1, 0, Duration.EndOfTurn) + ).withInterveningIf(condition); + ability.addEffect(new CantBeBlockedSourceEffect(Duration.EndOfTurn) + .setText("and can't be blocked this turn")); this.addAbility(ability.addHint(hint)); } diff --git a/Mage.Sets/src/mage/cards/b/BruseTarlBoorishHerder.java b/Mage.Sets/src/mage/cards/b/BruseTarlBoorishHerder.java index 838c8c189ce..747fec5217c 100644 --- a/Mage.Sets/src/mage/cards/b/BruseTarlBoorishHerder.java +++ b/Mage.Sets/src/mage/cards/b/BruseTarlBoorishHerder.java @@ -1,11 +1,8 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.LifelinkAbility; @@ -16,11 +13,11 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author spjspj */ public final class BruseTarlBoorishHerder extends CardImpl { @@ -34,14 +31,13 @@ public final class BruseTarlBoorishHerder extends CardImpl { this.toughness = new MageInt(3); // Whenever Bruse Tarl, Boorish Herder enters the battlefield or attacks, target creature you control gains double strike and lifelink until end of turn. - Effect effect = new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn); - effect.setText("target creature you control gains double strike"); - Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(effect); - effect = new GainAbilityTargetEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn); - effect.setText("and lifelink until end of turn"); - ability.addEffect(effect); - ability.addTarget(new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("target creature you control"))); - + Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new GainAbilityTargetEffect( + DoubleStrikeAbility.getInstance(), Duration.EndOfTurn + ).setText("target creature you control gains double strike")); + ability.addEffect(new GainAbilityTargetEffect( + LifelinkAbility.getInstance(), Duration.EndOfTurn + ).setText("and lifelink until end of turn")); + ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); // Partner diff --git a/Mage.Sets/src/mage/cards/b/BullRushBruiser.java b/Mage.Sets/src/mage/cards/b/BullRushBruiser.java index d69fb1ad63d..b4749fa28e9 100644 --- a/Mage.Sets/src/mage/cards/b/BullRushBruiser.java +++ b/Mage.Sets/src/mage/cards/b/BullRushBruiser.java @@ -1,33 +1,35 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FirstStrikeAbility; -import mage.constants.Duration; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.common.FilterTeamPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class BullRushBruiser extends CardImpl { - private static final FilterTeamPermanent filter = new FilterTeamPermanent(SubType.WARRIOR, "another Warrior"); + private static final FilterTeamPermanent filter + = new FilterTeamPermanent(SubType.WARRIOR, "your team controls another Warrior"); static { filter.add(AnotherPredicate.instance); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + public BullRushBruiser(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); @@ -37,12 +39,9 @@ public final class BullRushBruiser extends CardImpl { this.toughness = new MageInt(3); // Whenever Bull-Rush Bruiser attacks, if your team controls another Warrior, Bull-Rush Bruiser gains first strike until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn), false), - new PermanentsOnTheBattlefieldCondition(filter), - "Whenever {this} attacks, if your team controls another Warrior, " - + "{this} gains first strike until end of turn." - )); + this.addAbility(new AttacksTriggeredAbility(new GainAbilitySourceEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn + )).withInterveningIf(condition)); } private BullRushBruiser(final BullRushBruiser card) { diff --git a/Mage.Sets/src/mage/cards/b/Bulwark.java b/Mage.Sets/src/mage/cards/b/Bulwark.java index 1d72f95d868..e2fac8bbb86 100644 --- a/Mage.Sets/src/mage/cards/b/Bulwark.java +++ b/Mage.Sets/src/mage/cards/b/Bulwark.java @@ -1,8 +1,8 @@ package mage.cards.b; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -43,7 +43,7 @@ class BulwarkDamageEffect extends OneShotEffect { BulwarkDamageEffect() { super(Outcome.Damage); - staticText = "Bulwark deals X damage to target opponent, where X is the number of cards in your hand minus the number of cards in that player's hand"; + staticText = "{this} deals X damage to target opponent, where X is the number of cards in your hand minus the number of cards in that player's hand"; } private BulwarkDamageEffect(final BulwarkDamageEffect effect) { diff --git a/Mage.Sets/src/mage/cards/b/BurningEyeZubera.java b/Mage.Sets/src/mage/cards/b/BurningEyeZubera.java index bf660252995..be50407423d 100644 --- a/Mage.Sets/src/mage/cards/b/BurningEyeZubera.java +++ b/Mage.Sets/src/mage/cards/b/BurningEyeZubera.java @@ -1,38 +1,36 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetAnyTarget; +import java.util.Optional; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class BurningEyeZubera extends CardImpl { public BurningEyeZubera(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); this.subtype.add(SubType.ZUBERA, SubType.SPIRIT); this.power = new MageInt(3); this.toughness = new MageInt(3); // When Burning-Eye Zubera dies, if 4 or more damage was dealt to it this turn, Burning-Eye Zubera deals 3 damage to any target. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new DiesSourceTriggeredAbility(new DamageTargetEffect(3)),new SourceGotFourDamage(), - "When {this} dies, if 4 or more damage was dealt to it this turn, Burning-Eye Zubera deals 3 damage to any target"); + Ability ability = new DiesSourceTriggeredAbility(new DamageTargetEffect(3)) + .withInterveningIf(BurningEyeZuberaCondition.instance); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } @@ -47,13 +45,19 @@ public final class BurningEyeZubera extends CardImpl { } } -class SourceGotFourDamage implements Condition { +enum BurningEyeZuberaCondition implements Condition { + instance; + @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent == null) { - permanent = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD); + return Optional + .ofNullable(source.getSourcePermanentOrLKI(game)) + .map(Permanent::getDamage) + .orElse(0) >= 4; } - return permanent.getDamage() > 3; + + @Override + public String toString() { + return "4 or more damage was dealt to it this turn"; } } diff --git a/Mage.Sets/src/mage/cards/b/BurningPalmEfreet.java b/Mage.Sets/src/mage/cards/b/BurningPalmEfreet.java index e0e1bd4963a..99f881cc6ac 100644 --- a/Mage.Sets/src/mage/cards/b/BurningPalmEfreet.java +++ b/Mage.Sets/src/mage/cards/b/BurningPalmEfreet.java @@ -16,6 +16,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -42,7 +43,7 @@ public final class BurningPalmEfreet extends CardImpl { ability.addEffect(new LoseAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn) .setText("and that creature loses flying until end of turn") ); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/ButchDeLoriaTunnelSnake.java b/Mage.Sets/src/mage/cards/b/ButchDeLoriaTunnelSnake.java index 8d6545ff0fa..9c660714aba 100644 --- a/Mage.Sets/src/mage/cards/b/ButchDeLoriaTunnelSnake.java +++ b/Mage.Sets/src/mage/cards/b/ButchDeLoriaTunnelSnake.java @@ -25,10 +25,13 @@ import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * @author Susucr */ @@ -67,7 +70,7 @@ public final class ButchDeLoriaTunnelSnake extends CardImpl { new AddCountersTargetEffect(CounterType.MENACE.createInstance()), new ManaCostsImpl<>("{1}{B}") ); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); ability.addEffect(new BecomesCreatureTypeTargetEffect(Duration.EndOfGame, SubType.ROGUE, false) .setText("It becomes a Rogue in addition to its other types")); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/b/BuzzingWhackADoodle.java b/Mage.Sets/src/mage/cards/b/BuzzingWhackADoodle.java index 73fc5257431..07360cdcf3d 100644 --- a/Mage.Sets/src/mage/cards/b/BuzzingWhackADoodle.java +++ b/Mage.Sets/src/mage/cards/b/BuzzingWhackADoodle.java @@ -1,14 +1,11 @@ - package mage.cards.b; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.IntCompareCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GainLifeEffect; @@ -18,15 +15,16 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.Outcome; -import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.Target; import mage.target.TargetPlayer; import mage.target.common.TargetOpponent; +import java.util.Set; +import java.util.UUID; + /** - * * @author spjspj */ public final class BuzzingWhackADoodle extends CardImpl { @@ -38,16 +36,22 @@ public final class BuzzingWhackADoodle extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new BuzzingWhackADoodleEffect(), false)); // *Whack - T: Target player loses 2 life. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new LoseLifeTargetEffect(2), new TapSourceCost(), new WhackCondition()); + Ability ability = new ActivateIfConditionActivatedAbility( + new LoseLifeTargetEffect(2), new TapSourceCost(), new WhackCondition() + ); ability.addTarget(new TargetPlayer()); this.addAbility(ability); // *Doodle - T: You gain 3 life. - Ability ability2 = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(3), new TapSourceCost(), new DoodleCondition()); + Ability ability2 = new ActivateIfConditionActivatedAbility( + new GainLifeEffect(3), new TapSourceCost(), new DoodleCondition() + ); this.addAbility(ability2); // *Buzz - 2, T: Draw a card. - Ability ability3 = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{2}"), new BuzzCondition()); + Ability ability3 = new ActivateIfConditionActivatedAbility( + new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{2}"), new BuzzCondition() + ); ability3.addCost(new TapSourceCost()); this.addAbility(ability3); } @@ -144,7 +148,7 @@ class WhackCondition extends IntCompareCondition { @Override public String toString() { - return "if both players picked 'Whack'"; + return "both players picked 'Whack'"; } } @@ -165,7 +169,7 @@ class DoodleCondition extends IntCompareCondition { @Override public String toString() { - return "if both players picked 'Doodle'"; + return "both players picked 'Doodle'"; } } @@ -186,6 +190,6 @@ class BuzzCondition extends IntCompareCondition { @Override public String toString() { - return "if both players picked differently"; + return "both players picked differently"; } } diff --git a/Mage.Sets/src/mage/cards/b/BygoneColossus.java b/Mage.Sets/src/mage/cards/b/BygoneColossus.java new file mode 100644 index 00000000000..1c6ed0ba743 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BygoneColossus.java @@ -0,0 +1,37 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.keyword.WarpAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BygoneColossus extends CardImpl { + + public BygoneColossus(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{9}"); + + this.subtype.add(SubType.ROBOT); + this.subtype.add(SubType.GIANT); + this.power = new MageInt(9); + this.toughness = new MageInt(9); + + // Warp {3} + this.addAbility(new WarpAbility(this, "{3}")); + } + + private BygoneColossus(final BygoneColossus card) { + super(card); + } + + @Override + public BygoneColossus copy() { + return new BygoneColossus(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BygoneMarvels.java b/Mage.Sets/src/mage/cards/b/BygoneMarvels.java index 9b2429fa71b..2367fc7e168 100644 --- a/Mage.Sets/src/mage/cards/b/BygoneMarvels.java +++ b/Mage.Sets/src/mage/cards/b/BygoneMarvels.java @@ -1,7 +1,6 @@ package mage.cards.b; import mage.abilities.condition.common.DescendCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CastSourceTriggeredAbility; import mage.abilities.effects.common.CopySourceSpellEffect; import mage.abilities.effects.common.ExileSpellEffect; @@ -27,11 +26,11 @@ public final class BygoneMarvels extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}{G}"); // Descend 8 -- When you cast this spell, if there are eight or more permanent cards in your graveyard, copy this spell twice. You may choose new targets for the copies. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new CastSourceTriggeredAbility(new CopySourceSpellEffect(2)), - DescendCondition.EIGHT, "When you cast this spell, if there are eight or more " + - "permanent cards in your graveyard, copy this spell twice. You may choose new targets for the copies." - ).setAbilityWord(AbilityWord.DESCEND_8).addHint(DescendCondition.getHint())); + this.addAbility(new CastSourceTriggeredAbility(new CopySourceSpellEffect(2) + .setText("copy this spell twice. You may choose new targets for the copies")) + .withInterveningIf(DescendCondition.EIGHT) + .setAbilityWord(AbilityWord.DESCEND_8) + .addHint(DescendCondition.getHint())); // Return target permanent card from your graveyard to your hand. Exile Bygone Marvels. this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/c/CabalInquisitor.java b/Mage.Sets/src/mage/cards/c/CabalInquisitor.java index e6129522ac4..b6cb7292f82 100644 --- a/Mage.Sets/src/mage/cards/c/CabalInquisitor.java +++ b/Mage.Sets/src/mage/cards/c/CabalInquisitor.java @@ -6,7 +6,7 @@ import mage.abilities.condition.common.ThresholdCondition; import mage.abilities.costs.common.ExileFromGraveCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -34,7 +34,7 @@ public final class CabalInquisitor extends CardImpl { this.toughness = new MageInt(1); // Threshold - {1}{B}, {T}, Exile two cards from your graveyard: Target player discards a card. Activate this ability only any time you could cast a sorcery, and only if seven or more cards are in your graveyard. - Ability ability = new ConditionalActivatedAbility( + Ability ability = new ActivateIfConditionActivatedAbility( new DiscardTargetEffect(1), new ManaCostsImpl<>("{1}{B}"), ThresholdCondition.instance ).setTiming(TimingRule.SORCERY); ability.addTarget(new TargetPlayer()); diff --git a/Mage.Sets/src/mage/cards/c/CabalPit.java b/Mage.Sets/src/mage/cards/c/CabalPit.java index 3c322614a2d..8d9407713c4 100644 --- a/Mage.Sets/src/mage/cards/c/CabalPit.java +++ b/Mage.Sets/src/mage/cards/c/CabalPit.java @@ -5,7 +5,7 @@ import mage.abilities.condition.common.ThresholdCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.mana.BlackManaAbility; @@ -32,7 +32,7 @@ public final class CabalPit extends CardImpl { this.addAbility(manaAbility); // Threshold - {B}, {T}, Sacrifice Cabal Pit: Target creature gets -2/-2 until end of turn. Activate this ability only if seven or more cards are in your graveyard. - Ability thresholdAbility = new ConditionalActivatedAbility( + Ability thresholdAbility = new ActivateIfConditionActivatedAbility( new BoostTargetEffect(-2, -2, Duration.EndOfTurn), new ManaCostsImpl<>("{B}"), ThresholdCondition.instance ); diff --git a/Mage.Sets/src/mage/cards/c/CabalTorturer.java b/Mage.Sets/src/mage/cards/c/CabalTorturer.java index b7116721839..19d118a3e7e 100644 --- a/Mage.Sets/src/mage/cards/c/CabalTorturer.java +++ b/Mage.Sets/src/mage/cards/c/CabalTorturer.java @@ -6,7 +6,7 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.ThresholdCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -37,7 +37,7 @@ public final class CabalTorturer extends CardImpl { this.addAbility(ability); // Threshold - {3}{B}{B}, {tap}: Target creature gets -2/-2 until end of turn. Activate this ability only if seven or more cards are in your graveyard. - ability = new ConditionalActivatedAbility( + ability = new ActivateIfConditionActivatedAbility( new BoostTargetEffect(-2, -2, Duration.EndOfTurn), new ManaCostsImpl<>("{3}{B}{B}"), ThresholdCondition.instance ); diff --git a/Mage.Sets/src/mage/cards/c/CacophonyUnleashed.java b/Mage.Sets/src/mage/cards/c/CacophonyUnleashed.java index 5c37b77015f..33dd02d30ac 100644 --- a/Mage.Sets/src/mage/cards/c/CacophonyUnleashed.java +++ b/Mage.Sets/src/mage/cards/c/CacophonyUnleashed.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.keyword.DeathtouchAbility; @@ -37,24 +36,18 @@ public final class CacophonyUnleashed extends CardImpl { public CacophonyUnleashed(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{5}{B}{B}"); - // When Cacophony Unleashed enters the battlefield, if you cast it, destroy all nonenchantment creatures. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(filter)), - CastFromEverywhereSourceCondition.instance, - "When {this} enters, if you cast it, destroy all nonenchantment creatures." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(filter)) + .withInterveningIf(CastFromEverywhereSourceCondition.instance)); // Whenever Cacophony Unleashed or another enchantment you control enters, until end of turn, Cacophony Unleashed becomes a legendary 6/6 Nightmare God creature with menace and deathtouch. It's still an enchantment. - this.addAbility( - new EntersBattlefieldThisOrAnotherTriggeredAbility( + this.addAbility(new EntersBattlefieldThisOrAnotherTriggeredAbility( new BecomesCreatureSourceEffect(new CacophonyUnleashedToken(), CardType.ENCHANTMENT, Duration.EndOfTurn) - .setText("until end of turn, Cacophony Unleashed becomes a legendary 6/6 Nightmare God " - + "creature with menace and deathtouch. It's still an enchantment."), + .setText("until end of turn, {this} becomes a legendary 6/6 Nightmare God " + + "creature with menace and deathtouch. It's still an enchantment."), StaticFilters.FILTER_PERMANENT_ENCHANTMENT, false, true - ) - ); + )); } private CacophonyUnleashed(final CacophonyUnleashed card) { diff --git a/Mage.Sets/src/mage/cards/c/CagedZombie.java b/Mage.Sets/src/mage/cards/c/CagedZombie.java index 2625767f96d..573152e12d2 100644 --- a/Mage.Sets/src/mage/cards/c/CagedZombie.java +++ b/Mage.Sets/src/mage/cards/c/CagedZombie.java @@ -12,7 +12,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import java.util.UUID; @@ -30,8 +29,7 @@ public final class CagedZombie extends CardImpl { // {1}{B}, {T}: Each opponent loses 2 life. Activate this ability only if a creature died this turn. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new LoseLifeOpponentsEffect(2), - new ManaCostsImpl<>("{1}{B}"), MorbidCondition.instance + new LoseLifeOpponentsEffect(2), new ManaCostsImpl<>("{1}{B}"), MorbidCondition.instance ); ability.addCost(new TapSourceCost()); this.addAbility(ability.addHint(MorbidHint.instance)); diff --git a/Mage.Sets/src/mage/cards/c/CaitCageBrawler.java b/Mage.Sets/src/mage/cards/c/CaitCageBrawler.java index b92d83818f9..12aa315f45a 100644 --- a/Mage.Sets/src/mage/cards/c/CaitCageBrawler.java +++ b/Mage.Sets/src/mage/cards/c/CaitCageBrawler.java @@ -57,10 +57,10 @@ public final class CaitCageBrawler extends CardImpl { class CaitCageBrawlerEffect extends OneShotEffect { - public CaitCageBrawlerEffect() { + CaitCageBrawlerEffect() { super(Outcome.Benefit); this.staticText = "you and defending player each draw a card, then discard a card. Put two +1/+1 counters on " + - "{this} if you discarded the card with the highest mana value among those cards or tied for highest."; + "{this} if you discarded the card with the greatest mana value among those cards or tied for greatest"; } protected CaitCageBrawlerEffect(final CaitCageBrawlerEffect effect) { @@ -120,4 +120,4 @@ class CaitCageBrawlerEffect extends OneShotEffect { } return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/c/CaligoSkinWitch.java b/Mage.Sets/src/mage/cards/c/CaligoSkinWitch.java index 79205ecbc1a..d8735f5903c 100644 --- a/Mage.Sets/src/mage/cards/c/CaligoSkinWitch.java +++ b/Mage.Sets/src/mage/cards/c/CaligoSkinWitch.java @@ -1,11 +1,9 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; import mage.abilities.keyword.KickerAbility; @@ -15,8 +13,9 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; +import java.util.UUID; + /** - * * @author JRHerlehy */ public final class CaligoSkinWitch extends CardImpl { @@ -32,15 +31,9 @@ public final class CaligoSkinWitch extends CardImpl { this.addAbility(new KickerAbility("{3}{B}")); // When Caligo Skin-Witch enters the battlefield, if it was kicked, each opponent discards two cards. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DiscardEachPlayerEffect( - StaticValue.get(2), - false, - TargetController.OPPONENT - )), - KickedCondition.ONCE, - "When {this} enters, if it was kicked, each opponent discards two cards." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DiscardEachPlayerEffect( + StaticValue.get(2), false, TargetController.OPPONENT + )).withInterveningIf(KickedCondition.ONCE)); } private CaligoSkinWitch(final CaligoSkinWitch card) { diff --git a/Mage.Sets/src/mage/cards/c/CallOfTheFullMoon.java b/Mage.Sets/src/mage/cards/c/CallOfTheFullMoon.java index fa705881e8a..c675832399f 100644 --- a/Mage.Sets/src/mage/cards/c/CallOfTheFullMoon.java +++ b/Mage.Sets/src/mage/cards/c/CallOfTheFullMoon.java @@ -1,54 +1,49 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.TwoOrMoreSpellsWereCastLastTurnCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; -/** - * - * @author LoneFox +import java.util.UUID; +/** + * @author LoneFox */ public final class CallOfTheFullMoon extends CardImpl { public CallOfTheFullMoon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); this.subtype.add(SubType.AURA); // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Benefit)); - Ability ability = new EnchantAbility(auraTarget); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget)); + // Enchanted creature gets +3/+2 and has trample. - ability = new SimpleStaticAbility(new BoostEnchantedEffect(3, 2, Duration.WhileOnBattlefield)); - Effect effect = new GainAbilityAttachedEffect(TrampleAbility.getInstance(), AttachmentType.AURA); - effect.setText("and has trample."); - ability.addEffect(effect); + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(3, 2)); + ability.addEffect(new GainAbilityAttachedEffect( + TrampleAbility.getInstance(), AttachmentType.AURA + ).setText("and has trample")); this.addAbility(ability); // At the beginning of each upkeep, if a player cast two or more spells last turn, sacrifice Call of the Full Moon. - TriggeredAbility ability2 = new BeginningOfUpkeepTriggeredAbility(TargetController.ANY, new SacrificeSourceEffect(), false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability2, TwoOrMoreSpellsWereCastLastTurnCondition.instance, - "At the beginning of each upkeep, if a player cast two or more spells last turn, sacrifice {this}.")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.ANY, new SacrificeSourceEffect(), false + ).withInterveningIf(TwoOrMoreSpellsWereCastLastTurnCondition.instance)); } private CallOfTheFullMoon(final CallOfTheFullMoon card) { diff --git a/Mage.Sets/src/mage/cards/c/CallToServe.java b/Mage.Sets/src/mage/cards/c/CallToServe.java index 79343503e67..686b14ec6c4 100644 --- a/Mage.Sets/src/mage/cards/c/CallToServe.java +++ b/Mage.Sets/src/mage/cards/c/CallToServe.java @@ -17,6 +17,8 @@ import mage.filter.StaticFilters; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author Loki @@ -28,7 +30,7 @@ public final class CallToServe extends CardImpl { this.subtype.add(SubType.AURA); // Enchant nonblack creature - TargetPermanent auraTarget = new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK); + TargetPermanent auraTarget = new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); Ability ability = new EnchantAbility(auraTarget); diff --git a/Mage.Sets/src/mage/cards/c/CallToTheGrave.java b/Mage.Sets/src/mage/cards/c/CallToTheGrave.java index 4ccc7548b6b..42dbde627e9 100644 --- a/Mage.Sets/src/mage/cards/c/CallToTheGrave.java +++ b/Mage.Sets/src/mage/cards/c/CallToTheGrave.java @@ -1,14 +1,11 @@ - package mage.cards.c; -import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.common.OnEventTriggeredAbility; -import mage.abilities.condition.common.CreatureCountCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.effects.common.SacrificeEffect; import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -16,33 +13,36 @@ import mage.constants.SubType; import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; -import mage.game.events.GameEvent; import java.util.UUID; /** - * * @author nantuko */ public final class CallToTheGrave extends CardImpl { - private static final String ruleText = "At the beginning of the end step, if no creatures are on the battlefield, sacrifice {this}."; private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Zombie creature"); static { filter.add(Predicates.not(SubType.ZOMBIE.getPredicate())); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterCreaturePermanent("no creatures are on the battlefield"), false + ); + public CallToTheGrave(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{4}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{B}"); // At the beginning of each player's upkeep, that player sacrifices a non-Zombie creature. - Ability ability = new BeginningOfUpkeepTriggeredAbility(TargetController.EACH_PLAYER, new SacrificeEffect(filter, 1, "that player"), false); - this.addAbility(ability); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.EACH_PLAYER, new SacrificeEffect(filter, 1, "that player"), false + )); // 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 ConditionalInterveningIfTriggeredAbility(triggered, new CreatureCountCondition(0, TargetController.ANY), ruleText)); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.NEXT, new SacrificeSourceEffect(), false + ).withInterveningIf(condition)); } private CallToTheGrave(final CallToTheGrave card) { diff --git a/Mage.Sets/src/mage/cards/c/CallToTheKindred.java b/Mage.Sets/src/mage/cards/c/CallToTheKindred.java index 4b2ff37cf46..57419f3606a 100644 --- a/Mage.Sets/src/mage/cards/c/CallToTheKindred.java +++ b/Mage.Sets/src/mage/cards/c/CallToTheKindred.java @@ -1,10 +1,10 @@ package mage.cards.c; import mage.abilities.Ability; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.keyword.EnchantAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; @@ -13,7 +13,6 @@ import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.SharesCreatureTypePredicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetCard; @@ -41,7 +40,7 @@ public final class CallToTheKindred extends CardImpl { // At the beginning of your upkeep, you may look at the top five cards of your library. // If you do, you may put a creature card that shares a creature type with enchanted creature from among them onto the battlefield, // then you put the rest of those cards on the bottom of your library in any order. - this.addAbility(new OnEventTriggeredAbility(GameEvent.EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", new CallToTheKindredEffect(), true)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CallToTheKindredEffect(), true)); } private CallToTheKindred(final CallToTheKindred card) { diff --git a/Mage.Sets/src/mage/cards/c/CallousOppressor.java b/Mage.Sets/src/mage/cards/c/CallousOppressor.java index 4b762b2cca9..15f3237b97c 100644 --- a/Mage.Sets/src/mage/cards/c/CallousOppressor.java +++ b/Mage.Sets/src/mage/cards/c/CallousOppressor.java @@ -21,6 +21,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponent; import mage.util.CardUtil; @@ -50,7 +51,7 @@ public final class CallousOppressor extends CardImpl { SourceTappedCondition.TAPPED, "Gain control of target creature that isn't of the chosen type for as long as {this} remains tapped"); Ability ability = new SimpleActivatedAbility(effect, new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(new CallousOppressorFilter())); + ability.addTarget(new TargetPermanent(new CallousOppressorFilter())); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CallousSellSword.java b/Mage.Sets/src/mage/cards/c/CallousSellSword.java index a727344100e..43cffe99073 100644 --- a/Mage.Sets/src/mage/cards/c/CallousSellSword.java +++ b/Mage.Sets/src/mage/cards/c/CallousSellSword.java @@ -16,10 +16,11 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.common.FilterAnyTarget; +import mage.filter.common.FilterPermanentOrPlayer; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetAnyTarget; import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetPermanentOrPlayer; import java.util.UUID; @@ -28,7 +29,7 @@ import java.util.UUID; */ public final class CallousSellSword extends AdventureCard { - private static final FilterAnyTarget filterSecondTarget = new FilterAnyTarget("any other target"); + private static final FilterPermanentOrPlayer filterSecondTarget = new FilterAnyTarget("any other target"); private static final Hint hint = new ValueHint( "Creatures that died under your control this turn", CreaturesYouControlDiedCount.instance @@ -54,7 +55,7 @@ public final class CallousSellSword extends AdventureCard { // Target creature you control deals damage equal to its power to any other target. Then sacrifice it. this.getSpellCard().getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect()); this.getSpellCard().getSpellAbility().addTarget(new TargetControlledCreaturePermanent().setTargetTag(1)); - this.getSpellCard().getSpellAbility().addTarget(new TargetAnyTarget(1, 1, filterSecondTarget).setTargetTag(2)); + this.getSpellCard().getSpellAbility().addTarget(new TargetPermanentOrPlayer(filterSecondTarget).setTargetTag(2)); this.getSpellCard().getSpellAbility().addEffect(new CallousSellSwordSacrificeFirstTargetEffect().concatBy("Then")); this.finalizeAdventure(); diff --git a/Mage.Sets/src/mage/cards/c/Camouflage.java b/Mage.Sets/src/mage/cards/c/Camouflage.java index d192d4edc66..1e86a48d31e 100644 --- a/Mage.Sets/src/mage/cards/c/Camouflage.java +++ b/Mage.Sets/src/mage/cards/c/Camouflage.java @@ -1,12 +1,5 @@ package mage.cards.c; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; import mage.abilities.condition.common.MyTurnCondition; @@ -17,9 +10,9 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.PhaseStep; -import mage.filter.predicate.Predicates; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate; import mage.game.Game; import mage.game.combat.CombatGroup; @@ -28,11 +21,12 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.util.RandomUtil; +import java.util.*; + /** - * * @author L_J */ public final class Camouflage extends CardImpl { @@ -121,7 +115,7 @@ class CamouflageEffect extends ContinuousRuleModifyingEffectImpl { filter.add(Predicates.not(new PermanentReferenceInCollectionPredicate(spentBlockers, game))); } if (defender.chooseUse(Outcome.Neutral, "Make a new blocker pile? If not, all remaining piles stay empty. (remaining piles: " + (attackerCount - masterList.size()) + ')', source, game)) { - Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true); + Target target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); if (target.canChoose(defenderId, source, game)) { if (defender.chooseTarget(Outcome.Neutral, target, source, game)) { for (UUID creatureId : target.getTargets()) { @@ -171,7 +165,7 @@ class CamouflageEffect extends ContinuousRuleModifyingEffectImpl { } } } - + List> allPiles = masterMap.get(playerId); Set blockerIds = new HashSet<>(); for (List pile : allPiles) { diff --git a/Mage.Sets/src/mage/cards/c/CanalDredger.java b/Mage.Sets/src/mage/cards/c/CanalDredger.java index a17cda24833..e51ece4951a 100644 --- a/Mage.Sets/src/mage/cards/c/CanalDredger.java +++ b/Mage.Sets/src/mage/cards/c/CanalDredger.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -16,6 +15,8 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** * * @author L_J @@ -31,7 +32,7 @@ public final class CanalDredger extends CardImpl { // TODO: Draft specific abilities not implemented // Draft Canal Dredger face up. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft Canal Dredger face up - not implemented."))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft {this} face up - not implemented."))); // Each player passes the last card from each booster pack to a player who drafted a card named Canal Dredger. this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Each player passes the last card from each booster pack to a player who drafted a card named Canal Dredger - not implemented."))); diff --git a/Mage.Sets/src/mage/cards/c/CandlegroveWitch.java b/Mage.Sets/src/mage/cards/c/CandlegroveWitch.java index e7fef672fa0..4215ec692c8 100644 --- a/Mage.Sets/src/mage/cards/c/CandlegroveWitch.java +++ b/Mage.Sets/src/mage/cards/c/CandlegroveWitch.java @@ -1,15 +1,17 @@ package mage.cards.c; import mage.MageInt; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.common.CovenCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.hint.common.CovenHint; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import java.util.UUID; @@ -27,14 +29,9 @@ public final class CandlegroveWitch extends CardImpl { this.toughness = new MageInt(2); // Coven — At the beginning of combat on your turn, if you control three or more creatures with different powers, Candlegrove Witch gains flying until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - new GainAbilitySourceEffect( - FlyingAbility.getInstance(), Duration.EndOfTurn - ) - ), CovenCondition.instance, "At the beginning of combat on your turn, if you control three " + - "or more creatures with different powers, {this} gains flying until end of turn." - ).addHint(CovenHint.instance).setAbilityWord(AbilityWord.COVEN)); + this.addAbility(new BeginningOfCombatTriggeredAbility( + new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn) + ).withInterveningIf(CovenCondition.instance).addHint(CovenHint.instance).setAbilityWord(AbilityWord.COVEN)); } private CandlegroveWitch(final CandlegroveWitch card) { diff --git a/Mage.Sets/src/mage/cards/c/CandlelitCavalry.java b/Mage.Sets/src/mage/cards/c/CandlelitCavalry.java index bbcbaa73149..afffa3173cd 100644 --- a/Mage.Sets/src/mage/cards/c/CandlelitCavalry.java +++ b/Mage.Sets/src/mage/cards/c/CandlelitCavalry.java @@ -1,15 +1,17 @@ package mage.cards.c; import mage.MageInt; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.common.CovenCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.hint.common.CovenHint; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import java.util.UUID; @@ -27,14 +29,9 @@ public final class CandlelitCavalry extends CardImpl { this.toughness = new MageInt(5); // Coven — At the beginning of combat on your turn, if you control three or more creatures with different powers, Candlelit Cavalry gains trample until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - new GainAbilitySourceEffect( - TrampleAbility.getInstance(), Duration.EndOfTurn - ) - ), CovenCondition.instance, "At the beginning of combat on your turn, if you control " + - "three or more creatures with different powers, {this} gains trample until end of turn." - ).addHint(CovenHint.instance).setAbilityWord(AbilityWord.COVEN)); + this.addAbility(new BeginningOfCombatTriggeredAbility(new GainAbilitySourceEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn + )).withInterveningIf(CovenCondition.instance).addHint(CovenHint.instance).setAbilityWord(AbilityWord.COVEN)); } private CandlelitCavalry(final CandlelitCavalry card) { diff --git a/Mage.Sets/src/mage/cards/c/Candletrap.java b/Mage.Sets/src/mage/cards/c/Candletrap.java index 4c580dceb43..b08de188b95 100644 --- a/Mage.Sets/src/mage/cards/c/Candletrap.java +++ b/Mage.Sets/src/mage/cards/c/Candletrap.java @@ -1,28 +1,27 @@ package mage.cards.c; -import java.util.UUID; - +import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.CovenCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.ExileAttachedEffect; import mage.abilities.effects.common.PreventAllDamageByAttachedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.hint.common.CovenHint; import mage.abilities.keyword.DefenderAbility; -import mage.constants.*; -import mage.target.common.TargetCreaturePermanent; -import mage.abilities.Ability; -import mage.abilities.effects.common.AttachEffect; -import mage.target.TargetPermanent; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; /** - * * @author weirddan455 */ public final class Candletrap extends CardImpl { @@ -36,21 +35,22 @@ public final class Candletrap extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget)); // Enchanted creature has defender. this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect(DefenderAbility.getInstance(), AttachmentType.AURA))); // Prevent all combat damage that would be dealt by enchanted creature. - this.addAbility(new SimpleStaticAbility(new PreventAllDamageByAttachedEffect(Duration.WhileOnBattlefield, "enchanted creature", true))); + this.addAbility(new SimpleStaticAbility(new PreventAllDamageByAttachedEffect( + Duration.WhileOnBattlefield, "enchanted creature", true + ))); // Coven — {2}{W}, Sacrifice Candletrap: Exile enchanted creature. Activate only if you control three or more creatures with different powers. - ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new ExileAttachedEffect(), new ManaCostsImpl<>("{2}{W}"), CovenCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new ExileAttachedEffect(), new ManaCostsImpl<>("{2}{W}"), CovenCondition.instance + ); ability.addCost(new SacrificeSourceCost()); - ability.setAbilityWord(AbilityWord.COVEN); - ability.addHint(CovenHint.instance); - this.addAbility(ability); + this.addAbility(ability.setAbilityWord(AbilityWord.COVEN).addHint(CovenHint.instance)); } private Candletrap(final Candletrap card) { diff --git a/Mage.Sets/src/mage/cards/c/CankerousThirst.java b/Mage.Sets/src/mage/cards/c/CankerousThirst.java index dc1ecd5327c..9762cc3e68f 100644 --- a/Mage.Sets/src/mage/cards/c/CankerousThirst.java +++ b/Mage.Sets/src/mage/cards/c/CankerousThirst.java @@ -19,6 +19,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -34,8 +35,8 @@ public final class CankerousThirst extends CardImpl { // If {B} was spent to cast Cankerous Thirst, you may have target creature get -3/-3 until end of turn. If {G} was spent to cast Cankerous Thirst, you may have target creature get +3/+3 until end of turn. this.getSpellAbility().addEffect(new CankerousThirstEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature (1th effect -3/-3)"))); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature (2nd effect +3/+3)"))); + this.getSpellAbility().addTarget(new TargetPermanent(new FilterCreaturePermanent("creature (1th effect -3/-3)"))); + this.getSpellAbility().addTarget(new TargetPermanent(new FilterCreaturePermanent("creature (2nd effect +3/+3)"))); this.getSpellAbility().addEffect(new InfoEffect("(Do both if {B}{G} was spent.)")); } diff --git a/Mage.Sets/src/mage/cards/c/CantinaBand.java b/Mage.Sets/src/mage/cards/c/CantinaBand.java index 36d2de81d0a..71088199aa6 100644 --- a/Mage.Sets/src/mage/cards/c/CantinaBand.java +++ b/Mage.Sets/src/mage/cards/c/CantinaBand.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class CantinaBand extends CardImpl { // {T}, {1}: Tap target nonartifact creature. Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CaoCaoLordOfWei.java b/Mage.Sets/src/mage/cards/c/CaoCaoLordOfWei.java index 095a835be06..f199fe1523d 100644 --- a/Mage.Sets/src/mage/cards/c/CaoCaoLordOfWei.java +++ b/Mage.Sets/src/mage/cards/c/CaoCaoLordOfWei.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -13,17 +11,17 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class CaoCaoLordOfWei extends CardImpl { public CaoCaoLordOfWei(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); @@ -32,9 +30,11 @@ public final class CaoCaoLordOfWei extends CardImpl { this.toughness = new MageInt(3); // {tap}: Target opponent discards two cards. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new DiscardTargetEffect(2), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DiscardTargetEffect(2), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance + ); ability.addTarget(new TargetOpponent()); - this.addAbility(ability); + this.addAbility(ability); } private CaoCaoLordOfWei(final CaoCaoLordOfWei card) { diff --git a/Mage.Sets/src/mage/cards/c/CapriciousSorcerer.java b/Mage.Sets/src/mage/cards/c/CapriciousSorcerer.java index f2fed9e7586..3577a8dfbad 100644 --- a/Mage.Sets/src/mage/cards/c/CapriciousSorcerer.java +++ b/Mage.Sets/src/mage/cards/c/CapriciousSorcerer.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -12,25 +10,27 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author fireshoes */ public final class CapriciousSorcerer extends CardImpl { public CapriciousSorcerer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(1); this.toughness = new MageInt(1); // {tap}: Capricious Sorcerer deals 1 damage to any target. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new DamageTargetEffect(1), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DamageTargetEffect(1), new TapSourceCost(), + MyTurnBeforeAttackersDeclaredCondition.instance + ); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CaptivatingCrew.java b/Mage.Sets/src/mage/cards/c/CaptivatingCrew.java index ec304038f23..6c4450048d7 100644 --- a/Mage.Sets/src/mage/cards/c/CaptivatingCrew.java +++ b/Mage.Sets/src/mage/cards/c/CaptivatingCrew.java @@ -18,8 +18,11 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author TheElk801 @@ -42,7 +45,7 @@ public final class CaptivatingCrew extends CardImpl { effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); effect.setText("It gains haste until end of turn"); ability.addEffect(effect); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CapturedByTheConsulate.java b/Mage.Sets/src/mage/cards/c/CapturedByTheConsulate.java index 7e4ed9447fe..7754c03bd08 100644 --- a/Mage.Sets/src/mage/cards/c/CapturedByTheConsulate.java +++ b/Mage.Sets/src/mage/cards/c/CapturedByTheConsulate.java @@ -26,6 +26,8 @@ import mage.target.targetpointer.FixedTarget; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author LevelX2 */ @@ -36,7 +38,7 @@ public final class CapturedByTheConsulate extends CardImpl { this.subtype.add(SubType.AURA); // Enchant creature you don't control - TargetPermanent auraTarget = new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL); + TargetPermanent auraTarget = new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.UnboostCreature)); Ability ability = new EnchantAbility(auraTarget); diff --git a/Mage.Sets/src/mage/cards/c/CarnivalCarnage.java b/Mage.Sets/src/mage/cards/c/CarnivalCarnage.java index cc765727975..8ff9875068c 100644 --- a/Mage.Sets/src/mage/cards/c/CarnivalCarnage.java +++ b/Mage.Sets/src/mage/cards/c/CarnivalCarnage.java @@ -1,17 +1,12 @@ package mage.cards.c; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetControllerEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.cards.CardSetInfo; import mage.cards.SplitCard; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SpellAbilityType; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetCreatureOrPlaneswalker; import mage.target.common.TargetOpponent; @@ -27,7 +22,8 @@ public final class CarnivalCarnage extends SplitCard { // Carnival // Carnival deals 1 damage to target creature or planeswalker and 1 damage to that permanent's controller. - this.getLeftHalfCard().getSpellAbility().addEffect(new CarnivalEffect()); + this.getLeftHalfCard().getSpellAbility().addEffect(new DamageTargetEffect(1)); + this.getLeftHalfCard().getSpellAbility().addEffect(new DamageTargetControllerEffect(1).setText("and 1 damage to that permanent's controller")); this.getLeftHalfCard().getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); // Carnage @@ -48,35 +44,3 @@ public final class CarnivalCarnage extends SplitCard { return new CarnivalCarnage(this); } } - -class CarnivalEffect extends OneShotEffect { - - CarnivalEffect() { - super(Outcome.Benefit); - staticText = "{this} deals 1 damage to target creature or planeswalker " + - "and 1 damage to that permanent's controller"; - } - - private CarnivalEffect(final CarnivalEffect effect) { - super(effect); - } - - @Override - public CarnivalEffect copy() { - return new CarnivalEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent == null) { - return false; - } - permanent.damage(1, source.getSourceId(), source, game); - Player player = game.getPlayer(permanent.getControllerId()); - if (player != null) { - player.damage(1, source.getSourceId(), source, game); - } - return true; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/Carom.java b/Mage.Sets/src/mage/cards/c/Carom.java index 42724fb9131..9cebd978664 100644 --- a/Mage.Sets/src/mage/cards/c/Carom.java +++ b/Mage.Sets/src/mage/cards/c/Carom.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.RedirectionEffect; @@ -10,14 +8,15 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.other.AnotherTargetPredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Skyler Sell */ public final class Carom extends CardImpl { @@ -28,16 +27,8 @@ public final class Carom extends CardImpl { // The next 1 damage that would be dealt to target creature this turn is dealt to another target creature instead. // Draw a card. this.getSpellAbility().addEffect(new CaromEffect(Duration.EndOfTurn, 1)); - - TargetCreaturePermanent target = new TargetCreaturePermanent(); - target.setTargetTag(1); - this.getSpellAbility().addTarget(target); - - FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature (damage is redirected to)"); - filter.add(new AnotherTargetPredicate(2)); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter); - target2.setTargetTag(2); - this.getSpellAbility().addTarget(target2); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("to redirect from").setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2).withChooseHint("to redirect to").setTargetTag(2)); this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } diff --git a/Mage.Sets/src/mage/cards/c/CaseOfTheBurningMasks.java b/Mage.Sets/src/mage/cards/c/CaseOfTheBurningMasks.java index 7c6fad69706..2a25533c19b 100644 --- a/Mage.Sets/src/mage/cards/c/CaseOfTheBurningMasks.java +++ b/Mage.Sets/src/mage/cards/c/CaseOfTheBurningMasks.java @@ -7,7 +7,7 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SolvedSourceCondition; import mage.abilities.costs.common.SacrificeSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; import mage.abilities.hint.common.CaseSolvedHint; @@ -45,7 +45,7 @@ public final class CaseOfTheBurningMasks extends CardImpl { initialAbility.addTarget(new TargetOpponentsCreaturePermanent()); // To solve -- Three or more sources you controlled dealt damage this turn. // Solved -- Sacrifice this Case: Exile the top three cards of your library. Choose one of them. You may play that card this turn. - Ability solvedAbility = new ConditionalActivatedAbility( + Ability solvedAbility = new ActivateIfConditionActivatedAbility( new ExileTopXMayPlayUntilEffect(3, true, Duration.EndOfTurn), new SacrificeSourceCost().setText("sacrifice this Case"), SolvedSourceCondition.SOLVED ); diff --git a/Mage.Sets/src/mage/cards/c/CaseOfTheFilchedFalcon.java b/Mage.Sets/src/mage/cards/c/CaseOfTheFilchedFalcon.java index 2acca20cc61..e3785e4bc2b 100644 --- a/Mage.Sets/src/mage/cards/c/CaseOfTheFilchedFalcon.java +++ b/Mage.Sets/src/mage/cards/c/CaseOfTheFilchedFalcon.java @@ -11,7 +11,7 @@ import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.condition.common.SolvedSourceCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.effects.keyword.InvestigateEffect; @@ -50,7 +50,7 @@ public final class CaseOfTheFilchedFalcon extends CardImpl { Condition toSolveCondition = new PermanentsOnTheBattlefieldCondition( filter, ComparisonType.MORE_THAN, 2, true); // Solved -- {2}{U}, Sacrifice this Case: Put four +1/+1 counters on target noncreature artifact. It becomes a 0/0 Bird creature with flying in addition to its other types. - Ability solvedAbility = new ConditionalActivatedAbility( + Ability solvedAbility = new ActivateIfConditionActivatedAbility( new AddCountersTargetEffect(CounterType.P1P1.createInstance(4)), new ManaCostsImpl<>("{2}{U}"), SolvedSourceCondition.SOLVED); solvedAbility.addEffect(new BecomesCreatureTargetEffect(new CaseOfTheFilchedFalconToken(), diff --git a/Mage.Sets/src/mage/cards/c/CaseOfTheStashedSkeleton.java b/Mage.Sets/src/mage/cards/c/CaseOfTheStashedSkeleton.java index 0759772440d..3f9293be0de 100644 --- a/Mage.Sets/src/mage/cards/c/CaseOfTheStashedSkeleton.java +++ b/Mage.Sets/src/mage/cards/c/CaseOfTheStashedSkeleton.java @@ -10,7 +10,7 @@ import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.condition.common.SolvedSourceCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.hint.common.CaseSolvedHint; @@ -52,7 +52,7 @@ public final class CaseOfTheStashedSkeleton extends CardImpl { Condition toSolveCondition = new PermanentsOnTheBattlefieldCondition( filter, ComparisonType.EQUAL_TO, 0, true); // Solved -- {1}{B}, Sacrifice this Case: Search your library for a card, put it into your hand, then shuffle. Activate only as a sorcery. - Ability solvedAbility = new ConditionalActivatedAbility( + Ability solvedAbility = new ActivateIfConditionActivatedAbility( new SearchLibraryPutInHandEffect(new TargetCardInLibrary(), false) .setText("Search your library for a card, put it into your hand, then shuffle. Activate only as a sorcery."), new ManaCostsImpl<>("{1}{B}"), diff --git a/Mage.Sets/src/mage/cards/c/CaseOfTheUneatenFeast.java b/Mage.Sets/src/mage/cards/c/CaseOfTheUneatenFeast.java index 5475727d708..aa5ee9636e2 100644 --- a/Mage.Sets/src/mage/cards/c/CaseOfTheUneatenFeast.java +++ b/Mage.Sets/src/mage/cards/c/CaseOfTheUneatenFeast.java @@ -10,7 +10,7 @@ import mage.abilities.condition.Condition; import mage.abilities.condition.common.SolvedSourceCondition; import mage.abilities.condition.common.YouGainedLifeCondition; import mage.abilities.costs.common.SacrificeSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.hint.common.CaseSolvedHint; @@ -49,7 +49,7 @@ public final class CaseOfTheUneatenFeast extends CardImpl { new GainLifeEffect(1), StaticFilters.FILTER_PERMANENT_CREATURE); // To solve -- You've gained 5 or more life this turn. // Solved -- Sacrifice this Case: Creature cards in your graveyard gain "You may cast this card from your graveyard" until end of turn. - Ability solvedAbility = new ConditionalActivatedAbility( + Ability solvedAbility = new ActivateIfConditionActivatedAbility( new CaseOfTheUneatenFeastEffect(), new SacrificeSourceCost().setText("sacrifice this Case"), SolvedSourceCondition.SOLVED); diff --git a/Mage.Sets/src/mage/cards/c/CastDown.java b/Mage.Sets/src/mage/cards/c/CastDown.java index ce9bb242d86..a9b95cf29fd 100644 --- a/Mage.Sets/src/mage/cards/c/CastDown.java +++ b/Mage.Sets/src/mage/cards/c/CastDown.java @@ -7,6 +7,7 @@ import mage.constants.CardType; import mage.constants.SuperType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -23,7 +24,7 @@ public final class CastDown extends CardImpl { // Destroy target nonlegendary creature. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private CastDown(final CastDown card){ @@ -33,4 +34,4 @@ public final class CastDown extends CardImpl { public CastDown copy(){ return new CastDown(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/c/CatapultFodder.java b/Mage.Sets/src/mage/cards/c/CatapultFodder.java index 2853b20b656..97882939d50 100644 --- a/Mage.Sets/src/mage/cards/c/CatapultFodder.java +++ b/Mage.Sets/src/mage/cards/c/CatapultFodder.java @@ -1,26 +1,43 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; import mage.abilities.keyword.TransformAbility; -import mage.constants.SubType; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.ToughnessGreaterThanPowerPredicate; + +import java.util.UUID; /** - * * @author weirddan455 */ public final class CatapultFodder extends CardImpl { + private static final FilterPermanent filter = new FilterControlledCreaturePermanent( + "you control three or more creatures that each have toughness greater than their power" + ); + + static { + filter.add(ToughnessGreaterThanPowerPredicate.instance); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 2); + private static final Hint hint = new ValueHint( + "Creatures you control with toughness greater than their power", new PermanentsOnBattlefieldCount(filter) + ); + public CatapultFodder(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); @@ -31,11 +48,7 @@ public final class CatapultFodder extends CardImpl { // At the beginning of combat on your turn, if you control three or more creatures that each have toughness greater than their power, transform Catapult Fodder. this.addAbility(new TransformAbility()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility(new TransformSourceEffect()), - CatapultFodderCondition.instance, - "At the beginning of combat on your turn, if you control three or more creatures that each have toughness greater than their power, transform {this}" - )); + this.addAbility(new BeginningOfCombatTriggeredAbility(new TransformSourceEffect()).withInterveningIf(condition)); } private CatapultFodder(final CatapultFodder card) { @@ -47,26 +60,3 @@ public final class CatapultFodder extends CardImpl { return new CatapultFodder(this); } } - -enum CatapultFodderCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - int creatures = 0; - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) { - if (permanent.isCreature(game) && permanent.getToughness().getValue() > permanent.getPower().getValue()) { - creatures++; - if (creatures >= 3) { - return true; - } - } - } - return false; - } - - @Override - public String toString() { - return "you control three or more creatures that each have toughness greater than their power"; - } -} diff --git a/Mage.Sets/src/mage/cards/c/CatapultSquad.java b/Mage.Sets/src/mage/cards/c/CatapultSquad.java index ab28ba6efdd..b9cb309fed3 100644 --- a/Mage.Sets/src/mage/cards/c/CatapultSquad.java +++ b/Mage.Sets/src/mage/cards/c/CatapultSquad.java @@ -15,6 +15,7 @@ import mage.constants.Zone; import mage.filter.common.FilterAttackingOrBlockingCreature; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; @@ -40,7 +41,7 @@ public final class CatapultSquad extends CardImpl { // Tap two untapped Soldiers you control: Catapult Squad deals 2 damage to target attacking or blocking creature. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2), new TapTargetCost(new TargetControlledPermanent(2, 2, filter, false))); - ability.addTarget(new TargetCreaturePermanent(new FilterAttackingOrBlockingCreature())); + ability.addTarget(new TargetPermanent(new FilterAttackingOrBlockingCreature())); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CathedralAcolyte.java b/Mage.Sets/src/mage/cards/c/CathedralAcolyte.java index 47182f4df5d..21d77466332 100644 --- a/Mage.Sets/src/mage/cards/c/CathedralAcolyte.java +++ b/Mage.Sets/src/mage/cards/c/CathedralAcolyte.java @@ -27,7 +27,7 @@ import java.util.UUID; */ public final class CathedralAcolyte extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creature that entered the battlefield this turn"); + private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creature that entered this turn"); static { filter.add(CounterAnyPredicate.instance); diff --git a/Mage.Sets/src/mage/cards/c/CathedralMembrane.java b/Mage.Sets/src/mage/cards/c/CathedralMembrane.java index 923776d1012..9514da271f7 100644 --- a/Mage.Sets/src/mage/cards/c/CathedralMembrane.java +++ b/Mage.Sets/src/mage/cards/c/CathedralMembrane.java @@ -1,21 +1,22 @@ - package mage.cards.c; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; -import mage.abilities.common.ZoneChangeTriggeredAbility; +import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.DefenderAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.TurnPhase; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.watchers.Watcher; +import mage.watchers.common.BlockedAttackerWatcher; -import java.util.HashSet; -import java.util.Set; import java.util.UUID; /** @@ -35,8 +36,7 @@ public final class CathedralMembrane extends CardImpl { this.addAbility(DefenderAbility.getInstance()); // When Cathedral Membrane dies during combat, it deals 6 damage to each creature it blocked this combat. - this.addAbility(new CathedralMembraneAbility(), new CathedralMembraneWatcher()); - + this.addAbility(new CathedralMembraneAbility()); } private CathedralMembrane(final CathedralMembrane card) { @@ -49,10 +49,11 @@ public final class CathedralMembrane extends CardImpl { } } -class CathedralMembraneAbility extends ZoneChangeTriggeredAbility { +class CathedralMembraneAbility extends DiesSourceTriggeredAbility { CathedralMembraneAbility() { - super(Zone.BATTLEFIELD, Zone.GRAVEYARD, new CathedralMembraneEffect(), "When {this} dies during combat, ", false); + super(new CathedralMembraneEffect()); + setTriggerPhrase("When {this} dies during combat, "); } private CathedralMembraneAbility(CathedralMembraneAbility ability) { @@ -66,12 +67,7 @@ class CathedralMembraneAbility extends ZoneChangeTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (super.checkTrigger(event, game)) { - if (game.getTurnPhaseType() == TurnPhase.COMBAT) { - return true; - } - } - return false; + return game.getTurnPhaseType() == TurnPhase.COMBAT && super.checkTrigger(event, game); } } @@ -94,41 +90,13 @@ class CathedralMembraneEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - CathedralMembraneWatcher watcher = game.getState().getWatcher(CathedralMembraneWatcher.class, source.getSourceId()); - if (watcher != null) { - for (UUID uuid : watcher.getBlockedCreatures()) { - Permanent permanent = game.getPermanent(uuid); - if (permanent != null) { - permanent.damage(6, source.getSourceId(), source, game, false, true); - } + Permanent permanent = source.getSourcePermanentOrLKI(game); + BlockedAttackerWatcher watcher = game.getState().getWatcher(BlockedAttackerWatcher.class); + if (watcher != null && permanent != null) { + for (Permanent p : watcher.getBlockedCreatures(new MageObjectReference(permanent, game), game)) { + p.damage(6, source.getSourceId(), source, game, false, true); } } return true; } } - -class CathedralMembraneWatcher extends Watcher { - - private final Set blockedCreatures = new HashSet<>(); - - CathedralMembraneWatcher() { - super(WatcherScope.CARD); - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.BLOCKER_DECLARED && event.getSourceId().equals(sourceId)) { - blockedCreatures.add(event.getTargetId()); - } - } - - @Override - public void reset() { - super.reset(); - blockedCreatures.clear(); - } - - Set getBlockedCreatures() { - return blockedCreatures; - } -} diff --git a/Mage.Sets/src/mage/cards/c/CattiBrieOfMithralHall.java b/Mage.Sets/src/mage/cards/c/CattiBrieOfMithralHall.java index f0fe906e2ba..dc8c128822f 100644 --- a/Mage.Sets/src/mage/cards/c/CattiBrieOfMithralHall.java +++ b/Mage.Sets/src/mage/cards/c/CattiBrieOfMithralHall.java @@ -20,6 +20,7 @@ import mage.constants.*; import mage.counters.CounterType; import mage.filter.common.FilterAttackingOrBlockingCreature; import mage.game.Game; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -59,7 +60,7 @@ public final class CattiBrieOfMithralHall extends CardImpl { // {1}, Remove all +1/+1 counters from Catti-brie: It deals X damage to target attacking or blocking creature an opponent controls, where X is the number of counters removed this way. Ability damageAbility = new SimpleActivatedAbility( new DamageTargetEffect(CattiBrieRemovedCounterValue.instance).setText("it deals X damage to target attacking or blocking creature an opponent controls, where X is the number of counters removed this way"), new ManaCostsImpl<>("{1}")); - damageAbility.addTarget(new TargetCreaturePermanent(filter)); + damageAbility.addTarget(new TargetPermanent(filter)); damageAbility.addCost(new RemoveAllCountersSourceCost(CounterType.P1P1)); this.addAbility(damageAbility); diff --git a/Mage.Sets/src/mage/cards/c/CauldronOfSouls.java b/Mage.Sets/src/mage/cards/c/CauldronOfSouls.java index 49d6eac6183..7c7add9d41f 100644 --- a/Mage.Sets/src/mage/cards/c/CauldronOfSouls.java +++ b/Mage.Sets/src/mage/cards/c/CauldronOfSouls.java @@ -1,23 +1,19 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.PersistAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Zone; -import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class CauldronOfSouls extends CardImpl { @@ -26,12 +22,13 @@ public final class CauldronOfSouls extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); // {tap}: Choose any number of target creatures. Each of those creatures gains persist until end of turn. - Effect effect = new GainAbilityTargetEffect(new PersistAbility(), Duration.EndOfTurn); - effect.setText("choose any number of target creatures. Each of those creatures gains persist until end of turn"); - Ability ability = new SimpleActivatedAbility(effect, new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE, StaticFilters.FILTER_PERMANENT_CREATURE, false)); + Ability ability = new SimpleActivatedAbility( + new GainAbilityTargetEffect(new PersistAbility(), Duration.EndOfTurn) + .setText("choose any number of target creatures. Each of those creatures gains persist until end of turn"), + new TapSourceCost() + ); + ability.addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE)); this.addAbility(ability); - } private CauldronOfSouls(final CauldronOfSouls card) { diff --git a/Mage.Sets/src/mage/cards/c/CavernousMaw.java b/Mage.Sets/src/mage/cards/c/CavernousMaw.java index 32379092ed1..adb526ed19f 100644 --- a/Mage.Sets/src/mage/cards/c/CavernousMaw.java +++ b/Mage.Sets/src/mage/cards/c/CavernousMaw.java @@ -3,7 +3,7 @@ package mage.cards.c; import mage.abilities.Ability; import mage.abilities.condition.IntCompareCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.dynamicvalue.AdditiveDynamicValue; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; @@ -41,7 +41,7 @@ public final class CavernousMaw extends CardImpl { this.addAbility(new ColorlessManaAbility()); // {2}: Cavernous Maw becomes a 3/3 Elemental creature until end of turn. It's still a Cave land. Activate only if the number of other Caves you control plus the number of Cave cards in your graveyard is three or greater. - this.addAbility(new ConditionalActivatedAbility( + this.addAbility(new ActivateIfConditionActivatedAbility( new BecomesCreatureSourceEffect( new CreatureToken(3, 3, "3/3 Elemental creature") .withSubType(SubType.ELEMENTAL), diff --git a/Mage.Sets/src/mage/cards/c/CelestialEnforcer.java b/Mage.Sets/src/mage/cards/c/CelestialEnforcer.java index ef5772bcd21..03dc253156f 100644 --- a/Mage.Sets/src/mage/cards/c/CelestialEnforcer.java +++ b/Mage.Sets/src/mage/cards/c/CelestialEnforcer.java @@ -13,7 +13,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; @@ -45,7 +44,7 @@ public final class CelestialEnforcer extends CardImpl { // {1}{W}, {T}: Tap target creature. Activate this ability only if you control a creature with flying. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new TapTargetEffect(), new ManaCostsImpl<>("{1}{W}"), condition + new TapTargetEffect(), new ManaCostsImpl<>("{1}{W}"), condition ); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/c/CelestialRegulator.java b/Mage.Sets/src/mage/cards/c/CelestialRegulator.java index f499ded4111..305d2c93a43 100644 --- a/Mage.Sets/src/mage/cards/c/CelestialRegulator.java +++ b/Mage.Sets/src/mage/cards/c/CelestialRegulator.java @@ -17,8 +17,11 @@ import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.CounterAnyPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * * @author weirddan455 @@ -39,7 +42,7 @@ public final class CelestialRegulator extends CardImpl { // When Celestial Regulator enters the battlefield, choose target creature you don't control and tap it. // If you control a creature with a counter on it, the chosen creature doesn't untap during its controller's next untap step. Ability ability = new EntersBattlefieldTriggeredAbility(new CelestialRegulatorEffect()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CennsTactician.java b/Mage.Sets/src/mage/cards/c/CennsTactician.java index 2bc13f43866..5b9596af83c 100644 --- a/Mage.Sets/src/mage/cards/c/CennsTactician.java +++ b/Mage.Sets/src/mage/cards/c/CennsTactician.java @@ -16,6 +16,7 @@ import mage.constants.*; import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class CennsTactician extends CardImpl { // {W}, {tap}: Put a +1/+1 counter on target Soldier creature. Ability ability = new SimpleActivatedAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new ColoredManaCost(ColoredManaSymbol.W)); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filterSoldier)); + ability.addTarget(new TargetPermanent(filterSoldier)); this.addAbility(ability); // Each creature you control with a +1/+1 counter on it can block an additional creature each combat. diff --git a/Mage.Sets/src/mage/cards/c/CentaurArcher.java b/Mage.Sets/src/mage/cards/c/CentaurArcher.java index b848646cc85..5eda6670a21 100644 --- a/Mage.Sets/src/mage/cards/c/CentaurArcher.java +++ b/Mage.Sets/src/mage/cards/c/CentaurArcher.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class CentaurArcher extends CardImpl { // {tap}: Centaur Archer deals 1 damage to target creature with flying. Ability activatedAbility = new SimpleActivatedAbility(new DamageTargetEffect(1), new TapSourceCost()); - activatedAbility.addTarget(new TargetCreaturePermanent(filter)); + activatedAbility.addTarget(new TargetPermanent(filter)); this.addAbility(activatedAbility); } diff --git a/Mage.Sets/src/mage/cards/c/CentaurGarden.java b/Mage.Sets/src/mage/cards/c/CentaurGarden.java index 1bf1fa1b913..4b21c3b0742 100644 --- a/Mage.Sets/src/mage/cards/c/CentaurGarden.java +++ b/Mage.Sets/src/mage/cards/c/CentaurGarden.java @@ -5,7 +5,7 @@ import mage.abilities.condition.common.ThresholdCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.mana.GreenManaAbility; @@ -32,7 +32,7 @@ public final class CentaurGarden extends CardImpl { this.addAbility(manaAbility); // Threshold - {G}, {tap}, Sacrifice Centaur Garden: Target creature gets +3/+3 until end of turn. Activate this ability only if seven or more cards are in your graveyard. - Ability thresholdAbility = new ConditionalActivatedAbility( + Ability thresholdAbility = new ActivateIfConditionActivatedAbility( new BoostTargetEffect(3, 3, Duration.EndOfTurn), new ManaCostsImpl<>("{G}"), ThresholdCondition.instance ); diff --git a/Mage.Sets/src/mage/cards/c/CentaurPeacemaker.java b/Mage.Sets/src/mage/cards/c/CentaurPeacemaker.java index 45e10757f0b..d14039c1307 100644 --- a/Mage.Sets/src/mage/cards/c/CentaurPeacemaker.java +++ b/Mage.Sets/src/mage/cards/c/CentaurPeacemaker.java @@ -1,20 +1,16 @@ package mage.cards.c; -import java.util.Objects; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.constants.SubType; +import mage.abilities.effects.common.GainLifeAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.game.Game; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class CentaurPeacemaker extends CardImpl { @@ -28,9 +24,7 @@ public final class CentaurPeacemaker extends CardImpl { this.toughness = new MageInt(3); // When Centaur Mediator enters the battlefield, each player gains 4 life. - this.addAbility(new EntersBattlefieldTriggeredAbility( - new CentaurMediatorEffect() - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeAllEffect(4))); } private CentaurPeacemaker(final CentaurPeacemaker card) { @@ -42,32 +36,3 @@ public final class CentaurPeacemaker extends CardImpl { return new CentaurPeacemaker(this); } } - -class CentaurMediatorEffect extends OneShotEffect { - - CentaurMediatorEffect() { - super(Outcome.GainLife); - staticText = "each player gains 4 life."; - } - - private CentaurMediatorEffect(final CentaurMediatorEffect effect) { - super(effect); - } - - @Override - public CentaurMediatorEffect copy() { - return new CentaurMediatorEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - game.getState().getPlayersInRange( - source.getControllerId(), game) - .stream() - .map(game::getPlayer) - .filter(Objects::nonNull) - .forEachOrdered(player -> player.gainLife(4, game, source)); - return true; - } - -} diff --git a/Mage.Sets/src/mage/cards/c/CephalidColiseum.java b/Mage.Sets/src/mage/cards/c/CephalidColiseum.java index 7f8d92d1ecd..4710981fd81 100644 --- a/Mage.Sets/src/mage/cards/c/CephalidColiseum.java +++ b/Mage.Sets/src/mage/cards/c/CephalidColiseum.java @@ -5,7 +5,7 @@ import mage.abilities.condition.common.ThresholdCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.DrawDiscardTargetEffect; import mage.abilities.mana.BlueManaAbility; @@ -31,7 +31,7 @@ public final class CephalidColiseum extends CardImpl { this.addAbility(manaAbility); // Threshold - {U}, {tap}, Sacrifice Cephalid Coliseum: Target player draws three cards, then discards three cards. Activate this ability only if seven or more cards are in your graveyard. - Ability thresholdAbility = new ConditionalActivatedAbility( + Ability thresholdAbility = new ActivateIfConditionActivatedAbility( new DrawDiscardTargetEffect(3, 3), new ManaCostsImpl<>("{U}"), ThresholdCondition.instance ); diff --git a/Mage.Sets/src/mage/cards/c/CephalidRetainer.java b/Mage.Sets/src/mage/cards/c/CephalidRetainer.java index 03935c83147..04e5316d61b 100644 --- a/Mage.Sets/src/mage/cards/c/CephalidRetainer.java +++ b/Mage.Sets/src/mage/cards/c/CephalidRetainer.java @@ -16,6 +16,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class CephalidRetainer extends CardImpl { // {U}{U}: Tap target creature without flying. Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new ManaCostsImpl<>("{U}{U}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CerebralVortex.java b/Mage.Sets/src/mage/cards/c/CerebralVortex.java index 0b12819ff69..920382b2bd7 100644 --- a/Mage.Sets/src/mage/cards/c/CerebralVortex.java +++ b/Mage.Sets/src/mage/cards/c/CerebralVortex.java @@ -10,7 +10,6 @@ import mage.constants.Outcome; import mage.constants.WatcherScope; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.players.Player; import mage.target.TargetPlayer; import mage.watchers.Watcher; @@ -48,7 +47,7 @@ class CerebralVortexEffect extends OneShotEffect { CerebralVortexEffect() { super(Outcome.Damage); - this.staticText = ", then Cerebral Vortex deals damage to that player equal to the number of cards they've drawn this turn"; + this.staticText = ", then {this} deals damage to that player equal to the number of cards they've drawn this turn"; } private CerebralVortexEffect(final CerebralVortexEffect effect) { diff --git a/Mage.Sets/src/mage/cards/c/CetaSanctuary.java b/Mage.Sets/src/mage/cards/c/CetaSanctuary.java index d995234fe7f..a5f2d20753e 100644 --- a/Mage.Sets/src/mage/cards/c/CetaSanctuary.java +++ b/Mage.Sets/src/mage/cards/c/CetaSanctuary.java @@ -1,17 +1,16 @@ package mage.cards.c; -import java.util.UUID; import mage.ObjectColor; -import mage.abilities.Ability; -import mage.abilities.common.SanctuaryInterveningIfTriggeredAbility; +import mage.abilities.common.SanctuaryTriggeredAbility; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class CetaSanctuary extends CardImpl { @@ -20,12 +19,12 @@ public final class CetaSanctuary extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); // At the beginning of your upkeep, if you control a red or green permanent, draw a card, then discard a card. If you control a red permanent and a green permanent, instead draw two cards, then discard a card. - Ability ability = new SanctuaryInterveningIfTriggeredAbility( - new DrawDiscardControllerEffect(1, 1), new DrawDiscardControllerEffect(2, 1), ObjectColor.GREEN, ObjectColor.RED, - "At the beginning of your upkeep, if you control a red or green permanent, draw a card, then discard a card. " - + "If you control a red permanent and a green permanent, instead draw two cards, then discard a card." - ); - this.addAbility(ability); + this.addAbility(new SanctuaryTriggeredAbility( + new DrawDiscardControllerEffect(1, 1), + new DrawDiscardControllerEffect(2, 1), + ObjectColor.GREEN, ObjectColor.RED, "draw a card, then discard a card. " + + "If you control a red permanent and a green permanent, instead draw two cards, then discard a card." + )); } private CetaSanctuary(final CetaSanctuary card) { diff --git a/Mage.Sets/src/mage/cards/c/Cetavolver.java b/Mage.Sets/src/mage/cards/c/Cetavolver.java index a5da484d969..de202943a46 100644 --- a/Mage.Sets/src/mage/cards/c/Cetavolver.java +++ b/Mage.Sets/src/mage/cards/c/Cetavolver.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.common.KickedCostCondition; @@ -14,10 +13,12 @@ import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.counters.CounterType; +import java.util.UUID; + /** * * @author Loki @@ -39,7 +40,7 @@ public final class Cetavolver extends CardImpl { // If Cetavolver was kicked with its {1}{R} kicker, it enters with two +1/+1 counters on it and with first strike. EntersBattlefieldAbility ability1 = new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance(2),false), - new KickedCostCondition("{1}{R}"), "If Cetavolver was kicked with its {1}{R} kicker, it enters with two +1/+1 counters on it and with first strike.", + new KickedCostCondition("{1}{R}"), "If {this} was kicked with its {1}{R} kicker, it enters with two +1/+1 counters on it and with first strike.", "{this} enters with two +1/+1 counters on it and with first strike"); ((EntersBattlefieldEffect)ability1.getEffects().get(0)).addEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield)); this.addAbility(ability1); @@ -47,7 +48,7 @@ public final class Cetavolver extends CardImpl { // If Cetavolver was kicked with its {G} kicker, it enters with a +1/+1 counter on it and with trample. EntersBattlefieldAbility ability2 = new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance(1),false), new KickedCostCondition("{G}"), - "If Cetavolver was kicked with its {G} kicker, it enters with a +1/+1 counter on it and with trample.", + "If {this} was kicked with its {G} kicker, it enters with a +1/+1 counter on it and with trample.", "{this} enters with a +1/+1 counter on it and with trample"); ((EntersBattlefieldEffect)ability2.getEffects().get(0)).addEffect(new GainAbilitySourceEffect(TrampleAbility.getInstance(), Duration.WhileOnBattlefield)); this.addAbility(ability2); diff --git a/Mage.Sets/src/mage/cards/c/ChainedBrute.java b/Mage.Sets/src/mage/cards/c/ChainedBrute.java index dd39e3422ba..dc5aa46ba61 100644 --- a/Mage.Sets/src/mage/cards/c/ChainedBrute.java +++ b/Mage.Sets/src/mage/cards/c/ChainedBrute.java @@ -13,9 +13,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledPermanent; import java.util.UUID; @@ -36,8 +34,7 @@ public final class ChainedBrute extends CardImpl { // {1}, Sacrifice another creature: Untap Chained Brute. Activate this ability only during your turn. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new UntapSourceEffect(), - new GenericManaCost(1), MyTurnCondition.instance + new UntapSourceEffect(), new GenericManaCost(1), MyTurnCondition.instance ); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/c/Chainflinger.java b/Mage.Sets/src/mage/cards/c/Chainflinger.java index df3b4314f7f..5f11b2d40f3 100644 --- a/Mage.Sets/src/mage/cards/c/Chainflinger.java +++ b/Mage.Sets/src/mage/cards/c/Chainflinger.java @@ -6,7 +6,7 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.ThresholdCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -36,7 +36,7 @@ public final class Chainflinger extends CardImpl { this.addAbility(ability); // Threshold - {2}{R}, {tap}: Chainflinger deals 2 damage to any target. Activate this ability only if seven or more cards are in your graveyard. - Ability thresholdAbility = new ConditionalActivatedAbility( + Ability thresholdAbility = new ActivateIfConditionActivatedAbility( new DamageTargetEffect(2), new ManaCostsImpl<>("{2}{R}"), ThresholdCondition.instance ); thresholdAbility.addCost(new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/c/Chandler.java b/Mage.Sets/src/mage/cards/c/Chandler.java index 9a87640b874..8da8844cfe1 100644 --- a/Mage.Sets/src/mage/cards/c/Chandler.java +++ b/Mage.Sets/src/mage/cards/c/Chandler.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class Chandler extends CardImpl { // {R}{R}{R}, {tap}: Destroy target artifact creature. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{R}{R}{R}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/ChandrasIncinerator.java b/Mage.Sets/src/mage/cards/c/ChandrasIncinerator.java index 5fd71a51efb..9c439931724 100644 --- a/Mage.Sets/src/mage/cards/c/ChandrasIncinerator.java +++ b/Mage.Sets/src/mage/cards/c/ChandrasIncinerator.java @@ -3,21 +3,21 @@ package mage.cards.c; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.SpellAbility; -import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.SourceDealsNoncombatDamageToOpponentTriggeredAbility; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.FilterPermanent; import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; import mage.target.TargetPermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; import mage.util.CardUtil; import mage.watchers.Watcher; @@ -46,7 +46,10 @@ public final class ChandrasIncinerator extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Whenever a source you control deals noncombat damage to an opponent, Chandra's Incinerator deals that much damage to target creature or planeswalker that player controls. - this.addAbility(new ChandrasIncineratorTriggeredAbility()); + Ability ability = new SourceDealsNoncombatDamageToOpponentTriggeredAbility(new DamageTargetEffect(SavedDamageValue.MUCH), SetTargetPointer.PLAYER); + ability.addTarget(new TargetPermanent(new FilterCreatureOrPlaneswalkerPermanent("creature or planeswalker that player controls"))); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); + this.addAbility(ability); } private ChandrasIncinerator(final ChandrasIncinerator card) { @@ -123,47 +126,3 @@ class ChandrasIncineratorWatcher extends Watcher { return damageMap.getOrDefault(playerId, 0); } } - -class ChandrasIncineratorTriggeredAbility extends TriggeredAbilityImpl { - - ChandrasIncineratorTriggeredAbility() { - super(Zone.BATTLEFIELD, null); - } - - private ChandrasIncineratorTriggeredAbility(final ChandrasIncineratorTriggeredAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - DamagedPlayerEvent dEvent = (DamagedPlayerEvent) event; - if (dEvent.isCombatDamage() - || !game.getOpponents(event.getTargetId()).contains(getControllerId()) - || !game.getControllerId(event.getSourceId()).equals(getControllerId())) { - return false; - } - this.getEffects().clear(); - this.addEffect(new DamageTargetEffect(event.getAmount())); - FilterPermanent filter = new FilterCreatureOrPlaneswalkerPermanent("creature or planeswalker"); - filter.add(new ControllerIdPredicate(event.getTargetId())); - this.getTargets().clear(); - this.addTarget(new TargetPermanent(filter)); - return true; - } - - @Override - public ChandrasIncineratorTriggeredAbility copy() { - return new ChandrasIncineratorTriggeredAbility(this); - } - - @Override - public String getRule() { - return "Whenever a source you control deals noncombat damage to an opponent, " + - "{this} deals that much damage to target creature or planeswalker that player controls."; - } -} diff --git a/Mage.Sets/src/mage/cards/c/ChandrasPyreling.java b/Mage.Sets/src/mage/cards/c/ChandrasPyreling.java index 380ba8a5b91..8eaf21d8798 100644 --- a/Mage.Sets/src/mage/cards/c/ChandrasPyreling.java +++ b/Mage.Sets/src/mage/cards/c/ChandrasPyreling.java @@ -1,7 +1,8 @@ package mage.cards.c; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.common.SourceDealsNoncombatDamageToOpponentTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.DoubleStrikeAbility; @@ -10,13 +11,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import java.util.Objects; import java.util.UUID; /** @@ -33,7 +28,9 @@ public final class ChandrasPyreling extends CardImpl { this.toughness = new MageInt(3); // Whenever a source you control deals noncombat damage to an opponent, Chandra's Pyreling gets +1/+0 and gains double strike until end of turn. - this.addAbility(new ChandrasPyrelingAbility()); + Ability ability = new SourceDealsNoncombatDamageToOpponentTriggeredAbility(new BoostSourceEffect(1, 0, Duration.EndOfTurn).setText("this creature gets +1/+0")); + ability.addEffect(new GainAbilitySourceEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn).setText("and gains double strike until end of turn")); + this.addAbility(ability); } private ChandrasPyreling(final ChandrasPyreling card) { @@ -45,38 +42,3 @@ public final class ChandrasPyreling extends CardImpl { return new ChandrasPyreling(this); } } - -class ChandrasPyrelingAbility extends TriggeredAbilityImpl { - - ChandrasPyrelingAbility() { - super(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn)); - addEffect(new GainAbilitySourceEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn)); - } - - private ChandrasPyrelingAbility(final ChandrasPyrelingAbility ability) { - super(ability); - } - - @Override - public ChandrasPyrelingAbility copy() { - return new ChandrasPyrelingAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; - return !damageEvent.isCombatDamage() - && game.getOpponents(controllerId).contains(event.getTargetId()) - && Objects.equals(controllerId, game.getControllerId(event.getSourceId())); - } - - @Override - public String getRule() { - return "Whenever a source you control deals noncombat damage to an opponent, {this} gets +1/+0 and gains double strike until end of turn."; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/ChangeOfPlans.java b/Mage.Sets/src/mage/cards/c/ChangeOfPlans.java index 6288c217a69..0d0b27b6f5b 100644 --- a/Mage.Sets/src/mage/cards/c/ChangeOfPlans.java +++ b/Mage.Sets/src/mage/cards/c/ChangeOfPlans.java @@ -1,6 +1,5 @@ package mage.cards.c; -import mage.MageItem; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.keyword.ConniveSourceEffect; @@ -9,8 +8,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.filter.FilterPermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -83,13 +81,7 @@ class ChangeOfPlansEffect extends OneShotEffect { return true; } FilterPermanent filter = new FilterPermanent("creatures"); - filter.add(Predicates.or( - permanents - .stream() - .map(MageItem::getId) - .map(PermanentIdPredicate::new) - .collect(Collectors.toSet()) - )); + filter.add(new PermanentReferenceInCollectionPredicate(permanents, game)); TargetPermanent target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); player.choose(outcome, target.withChooseHint("to phase out"), source, game); for (UUID targetId : target.getTargets()) { diff --git a/Mage.Sets/src/mage/cards/c/ChemistersTrick.java b/Mage.Sets/src/mage/cards/c/ChemistersTrick.java index 7aeeb029592..0b350b5185a 100644 --- a/Mage.Sets/src/mage/cards/c/ChemistersTrick.java +++ b/Mage.Sets/src/mage/cards/c/ChemistersTrick.java @@ -15,11 +15,14 @@ import mage.constants.Outcome; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author LevelX2 @@ -30,7 +33,7 @@ public final class ChemistersTrick extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}{R}"); // Target creature you don't control gets -2/-0 until end of turn and attacks this turn if able. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.getSpellAbility().addEffect(new BoostTargetEffect(-2, 0, Duration.EndOfTurn)); this.getSpellAbility().addEffect(new AttacksIfAbleTargetEffect(Duration.EndOfTurn).setText("and attacks this turn if able")); diff --git a/Mage.Sets/src/mage/cards/c/CherishedHatchling.java b/Mage.Sets/src/mage/cards/c/CherishedHatchling.java index aa93168f1b2..c346568cdc8 100644 --- a/Mage.Sets/src/mage/cards/c/CherishedHatchling.java +++ b/Mage.Sets/src/mage/cards/c/CherishedHatchling.java @@ -20,11 +20,14 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.Spell; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * @author LevelX2 */ @@ -68,7 +71,7 @@ class CherishedHatchlingTriggeredAbility extends DelayedTriggeredAbility { private static Effect getEffectToAdd() { Ability abilityToAdd = new EntersBattlefieldTriggeredAbility(new FightTargetSourceEffect().setText("you may have it fight another target creature"), true); - abilityToAdd.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + abilityToAdd.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); return new GainAbilityTargetEffect(abilityToAdd, Duration.EndOfTurn, "it gains \"When this creature enters, you may have it fight another target creature.\"", true); } diff --git a/Mage.Sets/src/mage/cards/c/ChevillBaneOfMonsters.java b/Mage.Sets/src/mage/cards/c/ChevillBaneOfMonsters.java index 106c45379c1..3469c669238 100644 --- a/Mage.Sets/src/mage/cards/c/ChevillBaneOfMonsters.java +++ b/Mage.Sets/src/mage/cards/c/ChevillBaneOfMonsters.java @@ -2,15 +2,14 @@ package mage.cards.c; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -27,7 +26,7 @@ import java.util.UUID; public final class ChevillBaneOfMonsters extends CardImpl { private static final FilterPermanent filter - = new FilterPermanent(); + = new FilterPermanent("your opponents control no permanents with bounty counters on them"); private static final FilterPermanent filter2 = new FilterCreatureOrPlaneswalkerPermanent("creature or planeswalker an opponent controls"); private static final FilterPermanent filter3 @@ -59,13 +58,9 @@ public final class ChevillBaneOfMonsters extends CardImpl { this.addAbility(DeathtouchAbility.getInstance()); // At the beginning of your upkeep, if your opponents control no permanents with bounty counters on them, put a bounty counter on target creature or planeswalker an opponent controls. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - new AddCountersTargetEffect(CounterType.BOUNTY.createInstance()), false - ), condition, "At the beginning of your upkeep, " + - "if your opponents control no permanents with bounty counters on them, " + - "put a bounty counter on target creature or planeswalker an opponent controls." - ); + Ability ability = new BeginningOfUpkeepTriggeredAbility( + new AddCountersTargetEffect(CounterType.BOUNTY.createInstance()) + ).withInterveningIf(condition); ability.addTarget(new TargetPermanent(filter2)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/c/Chewbacca.java b/Mage.Sets/src/mage/cards/c/Chewbacca.java index 964513320ee..c740c9ea95b 100644 --- a/Mage.Sets/src/mage/cards/c/Chewbacca.java +++ b/Mage.Sets/src/mage/cards/c/Chewbacca.java @@ -1,6 +1,5 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksOrBlocksTriggeredAbility; @@ -9,20 +8,21 @@ import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.SuperType; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author Styxo */ public final class Chewbacca extends CardImpl { public Chewbacca(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}{G}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{G}{W}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.WOOKIEE); this.subtype.add(SubType.WARRIOR); @@ -34,7 +34,7 @@ public final class Chewbacca extends CardImpl { // Whenever Chewbacca attacks or blocks, another target creature you control gets +3/+3 until end of turn. Ability ability = new AttacksOrBlocksTriggeredAbility(new BoostTargetEffect(3, 3, Duration.EndOfTurn), false); - ability.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/ChewbaccaTheBeast.java b/Mage.Sets/src/mage/cards/c/ChewbaccaTheBeast.java index 905238824fc..2f3a8aeb15c 100644 --- a/Mage.Sets/src/mage/cards/c/ChewbaccaTheBeast.java +++ b/Mage.Sets/src/mage/cards/c/ChewbaccaTheBeast.java @@ -13,6 +13,7 @@ import mage.cards.CardSetInfo; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.permanent.AttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -43,7 +44,7 @@ public final class ChewbaccaTheBeast extends CardImpl { // Whenever Chewbacca, the Beast attacks, another target attacking creature you control gains indestructible until end of turn. Ability ability = new AttacksTriggeredAbility(new GainAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), false); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/ChiefChirpa.java b/Mage.Sets/src/mage/cards/c/ChiefChirpa.java index 2866aa9ba93..ac3d8d8d8f5 100644 --- a/Mage.Sets/src/mage/cards/c/ChiefChirpa.java +++ b/Mage.Sets/src/mage/cards/c/ChiefChirpa.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -19,13 +17,14 @@ import mage.constants.TargetController; import mage.counters.CounterType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.permanent.token.EwokToken; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author Styxo */ public final class ChiefChirpa extends CardImpl { @@ -42,7 +41,7 @@ public final class ChiefChirpa extends CardImpl { } public ChiefChirpa(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{R}{G}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{G}{W}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.EWOK); this.subtype.add(SubType.WARRIOR); @@ -54,7 +53,7 @@ public final class ChiefChirpa extends CardImpl { // Whenever a green creature you control dies, you may put a +1/+1 counter on another target Ewok creature you control. Ability ability = new DiesCreatureTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), true, diedFilter); - ability.addTarget(new TargetControlledCreaturePermanent(ewokFilter)); + ability.addTarget(new TargetPermanent(ewokFilter)); this.addAbility(ability); // When Chief Chirpa become monstrous, create three 1/1 green Ewok creature tokens. diff --git a/Mage.Sets/src/mage/cards/c/ChillToTheBone.java b/Mage.Sets/src/mage/cards/c/ChillToTheBone.java index a0ee9f882e8..576d903ecb3 100644 --- a/Mage.Sets/src/mage/cards/c/ChillToTheBone.java +++ b/Mage.Sets/src/mage/cards/c/ChillToTheBone.java @@ -9,6 +9,7 @@ import mage.constants.CardType; import mage.constants.SuperType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -28,7 +29,7 @@ public final class ChillToTheBone extends CardImpl { // Destroy target nonsnow creature. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private ChillToTheBone(final ChillToTheBone card) { diff --git a/Mage.Sets/src/mage/cards/c/ChokingVines.java b/Mage.Sets/src/mage/cards/c/ChokingVines.java index d07731b13f5..adf075894df 100644 --- a/Mage.Sets/src/mage/cards/c/ChokingVines.java +++ b/Mage.Sets/src/mage/cards/c/ChokingVines.java @@ -8,11 +8,14 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.PhaseStep; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.XTargetsCountAdjuster; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_ATTACKING_CREATURES; + /** * @author arcox */ @@ -30,7 +33,7 @@ public final class ChokingVines extends CardImpl { .setText("X target attacking creatures become blocked.")); this.getSpellAbility().addEffect(new DamageTargetEffect(1) .setText("{this} deals 1 damage to each of those creatures")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ATTACKING_CREATURES)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_ATTACKING_CREATURES)); this.getSpellAbility().setTargetAdjuster(new XTargetsCountAdjuster()); } diff --git a/Mage.Sets/src/mage/cards/c/ChromeReplicator.java b/Mage.Sets/src/mage/cards/c/ChromeReplicator.java index 20cd7226010..807308840d1 100644 --- a/Mage.Sets/src/mage/cards/c/ChromeReplicator.java +++ b/Mage.Sets/src/mage/cards/c/ChromeReplicator.java @@ -5,7 +5,6 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -37,12 +36,7 @@ public final class ChromeReplicator extends CardImpl { this.toughness = new MageInt(4); // When Chrome Replicator enters the battlefield, if you control two or more nonland, nontoken permanents with the same name as one another, create a 4/4 colorless Construct artifact creature token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new Construct4Token())), - ChromeReplicatorCondition.instance, "When {this} enters, " + - "if you control two or more nonland, nontoken permanents with the same name as one another, " + - "create a 4/4 colorless Construct artifact creature token." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new Construct4Token())).withInterveningIf(ChromeReplicatorCondition.instance)); } private ChromeReplicator(final ChromeReplicator card) { @@ -78,4 +72,9 @@ enum ChromeReplicatorCondition implements Condition { .filter(s -> !s.isEmpty()) .anyMatch(s -> nameMap.compute(s, CardUtil::setOrIncrementValue) >= 2); } + + @Override + public String toString() { + return "you control two or more nonland, nontoken permanents with the same name as one another"; + } } diff --git a/Mage.Sets/src/mage/cards/c/ChromeshellCrab.java b/Mage.Sets/src/mage/cards/c/ChromeshellCrab.java index 582981243d5..48b4574519e 100644 --- a/Mage.Sets/src/mage/cards/c/ChromeshellCrab.java +++ b/Mage.Sets/src/mage/cards/c/ChromeshellCrab.java @@ -15,9 +15,12 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Duration; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author fireshoes @@ -41,7 +44,7 @@ public final class ChromeshellCrab extends CardImpl { effect.setText("exchange control of target creature you control and target creature an opponent controls"); Ability ability = new TurnedFaceUpSourceTriggeredAbility(effect, false, true); ability.addTarget(new TargetControlledCreaturePermanent()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/Chronozoa.java b/Mage.Sets/src/mage/cards/c/Chronozoa.java index 97f3248396b..37e6fc3511e 100644 --- a/Mage.Sets/src/mage/cards/c/Chronozoa.java +++ b/Mage.Sets/src/mage/cards/c/Chronozoa.java @@ -1,12 +1,9 @@ - package mage.cards.c; import mage.MageInt; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.condition.common.LastTimeCounterRemovedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.CreateTokenCopySourceEffect; -import mage.abilities.effects.Effect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.VanishingAbility; import mage.cards.CardImpl; @@ -34,11 +31,10 @@ public final class Chronozoa extends CardImpl { this.addAbility(new VanishingAbility(3)); // When Chronozoa dies, if it had no time counters on it, create two tokens that are copies of it. - Effect effect = new CreateTokenCopySourceEffect(2); - effect.setText("create two tokens that are copies of it"); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new DiesSourceTriggeredAbility(effect, false), - LastTimeCounterRemovedCondition.instance, - "When {this} dies, if it had no time counters on it, create two tokens that are copies of it.")); + this.addAbility(new DiesSourceTriggeredAbility( + new CreateTokenCopySourceEffect(2) + .setText("create two tokens that are copies of it"), false + ).withInterveningIf(LastTimeCounterRemovedCondition.instance)); } private Chronozoa(final Chronozoa card) { diff --git a/Mage.Sets/src/mage/cards/c/ChurningReservoir.java b/Mage.Sets/src/mage/cards/c/ChurningReservoir.java index 1a0b02282db..196ec45d80f 100644 --- a/Mage.Sets/src/mage/cards/c/ChurningReservoir.java +++ b/Mage.Sets/src/mage/cards/c/ChurningReservoir.java @@ -2,17 +2,16 @@ package mage.cards.c; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.WatcherScope; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; @@ -59,7 +58,7 @@ public final class ChurningReservoir extends CardImpl { // {2}, {T}: Create a 1/1 red Phyrexian Goblin creature token. Activate only if an oil counter was removed from a permanent you controlled this turn or a permanent with an oil counter on it was put into a graveyard this turn. ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new CreateTokenEffect(new PhyrexianGoblinToken()), + new CreateTokenEffect(new PhyrexianGoblinToken()), new GenericManaCost(2), ChurningReservoirCondition.instance ); ability.addCost(new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/c/CinderCrawler.java b/Mage.Sets/src/mage/cards/c/CinderCrawler.java index 4862ecc686e..72646557b11 100644 --- a/Mage.Sets/src/mage/cards/c/CinderCrawler.java +++ b/Mage.Sets/src/mage/cards/c/CinderCrawler.java @@ -1,20 +1,19 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.condition.common.SourceBlockedCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class CinderCrawler extends CardImpl { @@ -27,11 +26,9 @@ public final class CinderCrawler extends CardImpl { this.toughness = new MageInt(2); // {R}: Cinder Crawler gets +1/+0 until end of turn. Activate this ability only if Cinder Crawler is blocked. - this.addAbility(new ConditionalActivatedAbility( - Zone.BATTLEFIELD, + this.addAbility(new ActivateIfConditionActivatedAbility( new BoostSourceEffect(1, 0, Duration.EndOfTurn), - new ManaCostsImpl<>("{R}"), - SourceBlockedCondition.instance + new ManaCostsImpl<>("{R}"), SourceBlockedCondition.instance )); } diff --git a/Mage.Sets/src/mage/cards/c/CinderhazeWretch.java b/Mage.Sets/src/mage/cards/c/CinderhazeWretch.java index a7cf0dbcf05..a41e6be57cb 100644 --- a/Mage.Sets/src/mage/cards/c/CinderhazeWretch.java +++ b/Mage.Sets/src/mage/cards/c/CinderhazeWretch.java @@ -14,7 +14,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.target.TargetPlayer; @@ -34,14 +33,16 @@ public final class CinderhazeWretch extends CardImpl { this.toughness = new MageInt(2); // {T}: Target player discards a card. Activate this ability only during your turn. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new DiscardTargetEffect(1), new TapSourceCost(), MyTurnCondition.instance); - ability.addHint(MyTurnHint.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DiscardTargetEffect(1), new TapSourceCost(), MyTurnCondition.instance + ); ability.addTarget(new TargetPlayer()); - this.addAbility(ability); + this.addAbility(ability.addHint(MyTurnHint.instance)); // Put a -1/-1 counter on Cinderhaze Wretch: Untap Cinderhaze Wretch. - this.addAbility(new SimpleActivatedAbility(new UntapSourceEffect(), new PutCountersSourceCost(CounterType.M1M1.createInstance(1)))); - + this.addAbility(new SimpleActivatedAbility( + new UntapSourceEffect(), new PutCountersSourceCost(CounterType.M1M1.createInstance(1)) + )); } private CinderhazeWretch(final CinderhazeWretch card) { diff --git a/Mage.Sets/src/mage/cards/c/CitadelOfPain.java b/Mage.Sets/src/mage/cards/c/CitadelOfPain.java index 5597a0f0d7f..a0e2826a3be 100644 --- a/Mage.Sets/src/mage/cards/c/CitadelOfPain.java +++ b/Mage.Sets/src/mage/cards/c/CitadelOfPain.java @@ -1,20 +1,17 @@ package mage.cards.c; import mage.abilities.Ability; -import mage.abilities.Mode; -import mage.abilities.TriggeredAbility; -import mage.abilities.common.OnEventTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.TargetController; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledLandPermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.players.Player; import java.util.UUID; @@ -28,10 +25,9 @@ public final class CitadelOfPain extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); // At the beginning of each player's end step, Citadel of Pain deals X damage to that player, where X is the number of untapped lands they control. - TriggeredAbility triggered = new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, - "beginning of the end step", true, - new CitadelOfPainEffect()); - this.addAbility(triggered); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.EACH_PLAYER, new CitadelOfPainEffect(), false + )); } private CitadelOfPain(final CitadelOfPain card) { @@ -64,16 +60,15 @@ class CitadelOfPainEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(game.getActivePlayerId()); - if (player != null) { - int damage = game.getBattlefield().countAll(filter, game.getActivePlayerId(), game); - player.damage(damage, source.getSourceId(), source, game); - return true; + if (player == null) { + return false; } - return false; + int damage = game.getBattlefield().count(filter, game.getActivePlayerId(), source, game); + return damage > 0 && player.damage(damage, source.getSourceId(), source, game) > 0; } @Override public CitadelOfPainEffect copy() { return new CitadelOfPainEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/c/CitadelSiege.java b/Mage.Sets/src/mage/cards/c/CitadelSiege.java index edbafe2556e..4399e931bc8 100644 --- a/Mage.Sets/src/mage/cards/c/CitadelSiege.java +++ b/Mage.Sets/src/mage/cards/c/CitadelSiege.java @@ -15,6 +15,7 @@ import mage.constants.ModeChoice; import mage.constants.TargetController; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; @@ -46,7 +47,7 @@ public final class CitadelSiege extends CardImpl { ability = new BeginningOfCombatTriggeredAbility( TargetController.OPPONENT, new TapTargetEffect("tap target creature that player controls"), false ); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(new SimpleStaticAbility(new GainAnchorWordAbilitySourceEffect(ability, ModeChoice.DRAGONS))); } diff --git a/Mage.Sets/src/mage/cards/c/CitanulWoodreaders.java b/Mage.Sets/src/mage/cards/c/CitanulWoodreaders.java index 3b3193f57b7..d9b27fbea9f 100644 --- a/Mage.Sets/src/mage/cards/c/CitanulWoodreaders.java +++ b/Mage.Sets/src/mage/cards/c/CitanulWoodreaders.java @@ -1,11 +1,8 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; @@ -13,8 +10,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class CitanulWoodreaders extends CardImpl { @@ -31,11 +29,8 @@ public final class CitanulWoodreaders extends CardImpl { this.addAbility(new KickerAbility("{2}{G}")); // When Citanul Woodreaders enters the battlefield, if it was kicked, draw two cards. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(2)), - KickedCondition.ONCE, - "When {this} enters, if it was kicked, draw two cards." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(2)) + .withInterveningIf(KickedCondition.ONCE)); } private CitanulWoodreaders(final CitanulWoodreaders card) { diff --git a/Mage.Sets/src/mage/cards/c/CityOfShadows.java b/Mage.Sets/src/mage/cards/c/CityOfShadows.java index f67dc011964..ae9a711c8ba 100644 --- a/Mage.Sets/src/mage/cards/c/CityOfShadows.java +++ b/Mage.Sets/src/mage/cards/c/CityOfShadows.java @@ -1,6 +1,5 @@ package mage.cards.c; -import java.util.UUID; import mage.Mana; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -12,13 +11,13 @@ import mage.abilities.mana.DynamicManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; /** - * * @author Luna Skyrise */ public final class CityOfShadows extends CardImpl { @@ -28,7 +27,7 @@ public final class CityOfShadows extends CardImpl { // {T}, Exile a creature you control: Put a storage counter on City of Shadows. Ability ability = new SimpleActivatedAbility(new AddCountersSourceEffect(CounterType.STORAGE.createInstance()), new TapSourceCost()); - ability.addCost(new ExileTargetCost(new TargetControlledCreaturePermanent(StaticFilters.FILTER_CONTROLLED_A_CREATURE))); + ability.addCost(new ExileTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_A_CREATURE))); this.addAbility(ability); // {T}: Add {C} for each storage counter on City of Shadows. diff --git a/Mage.Sets/src/mage/cards/c/ClaimJumper.java b/Mage.Sets/src/mage/cards/c/ClaimJumper.java index ffa895f0f65..568a2c47f67 100644 --- a/Mage.Sets/src/mage/cards/c/ClaimJumper.java +++ b/Mage.Sets/src/mage/cards/c/ClaimJumper.java @@ -3,8 +3,8 @@ package mage.cards.c; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.OpponentControlsMoreCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.abilities.keyword.VigilanceAbility; @@ -29,6 +29,8 @@ public final class ClaimJumper extends CardImpl { filter.add(SubType.PLAINS.getPredicate()); } + private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS); + public ClaimJumper(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); @@ -41,27 +43,13 @@ public final class ClaimJumper extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // When Claim Jumper enters the battlefield, if an opponent controls more lands than you, you may search your library for a Plains card and put it onto the battlefield tapped. Then if an opponent controls more lands than you, repeat this process once. If you search your library this way, shuffle. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility( - new SearchLibraryPutInPlayEffect( - new TargetCardInLibrary(0, 1, filter), true - ), - true - ), - new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS), - "When {this} enters, if an opponent controls more lands than you, " - + "you may search your library for a Plains card and put it onto the battlefield tapped. " - + "Then if an opponent controls more lands than you, repeat this process once. " - + "If you search your library this way, shuffle." - ); - ability.addEffect( - new ConditionalOneShotEffect( - new SearchLibraryPutInPlayEffect( - new TargetCardInLibrary(0, 1, filter), true, false, true - ), - new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS) - ) - ); + Ability ability = new EntersBattlefieldTriggeredAbility( + new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true), true + ).withInterveningIf(condition); + ability.addEffect(new ConditionalOneShotEffect( + new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true, false, true), + condition, "Then if an opponent controls more lands than you, repeat this process once. If you search your library this way, shuffle" + )); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/ClanDefiance.java b/Mage.Sets/src/mage/cards/c/ClanDefiance.java index 14e388c5e43..a3d04ea8ba7 100644 --- a/Mage.Sets/src/mage/cards/c/ClanDefiance.java +++ b/Mage.Sets/src/mage/cards/c/ClanDefiance.java @@ -10,6 +10,7 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetPlayerOrPlaneswalker; @@ -36,10 +37,10 @@ public final class ClanDefiance extends CardImpl { this.getSpellAbility().getModes().setMaxModes(3); // Clan Defiance deals X damage to target creature with flying; this.getSpellAbility().addEffect(new DamageTargetEffect(GetXValue.instance)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterFlying).withChooseHint("deals X damage, with flying")); + this.getSpellAbility().addTarget(new TargetPermanent(filterFlying).withChooseHint("deals X damage, with flying")); // Clan Defiance deals X damage to target creature without flying; Mode mode1 = new Mode(new DamageTargetEffect(GetXValue.instance)); - mode1.addTarget(new TargetCreaturePermanent(filterWithoutFlying).withChooseHint("deals X damage, without flying")); + mode1.addTarget(new TargetPermanent(filterWithoutFlying).withChooseHint("deals X damage, without flying")); this.getSpellAbility().addMode(mode1); // and/or Clan Defiance deals X damage to target player. Mode mode2 = new Mode(new DamageTargetEffect(GetXValue.instance)); diff --git a/Mage.Sets/src/mage/cards/c/ClashOfRealities.java b/Mage.Sets/src/mage/cards/c/ClashOfRealities.java index 6d8f13d6c8e..3f732d9af3a 100644 --- a/Mage.Sets/src/mage/cards/c/ClashOfRealities.java +++ b/Mage.Sets/src/mage/cards/c/ClashOfRealities.java @@ -16,6 +16,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,12 +39,12 @@ public final class ClashOfRealities extends CardImpl { // All Spirits have "When this permanent enters the battlefield, you may have it deal 3 damage to target non-Spirit creature." Ability ability1 = new ClashOfRealitiesTriggeredAbility(new DamageTargetEffect(3), "When this permanent enters, "); - ability1.addTarget(new TargetCreaturePermanent(filterNotSpirit)); + ability1.addTarget(new TargetPermanent(filterNotSpirit)); this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect(ability1, Duration.WhileOnBattlefield, filterSpirit, "All Spirits have \"When this permanent enters the battlefield, you may have it deal 3 damage to target non-Spirit creature.\""))); // Non-Spirit creatures have "When this creature enters the battlefield, you may have it deal 3 damage to target Spirit creature." Ability ability2 = new ClashOfRealitiesTriggeredAbility(new DamageTargetEffect(3), "When this creature enters, "); - ability2.addTarget(new TargetCreaturePermanent(filterSpirit)); + ability2.addTarget(new TargetPermanent(filterSpirit)); this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect(ability2, Duration.WhileOnBattlefield, filterNotSpirit, "Non-Spirit creatures have \"When this creature enters the battlefield, you may have it deal 3 damage to target Spirit creature.\""))); } diff --git a/Mage.Sets/src/mage/cards/c/ClashOfTitans.java b/Mage.Sets/src/mage/cards/c/ClashOfTitans.java index c9405028f82..561f6abc70d 100644 --- a/Mage.Sets/src/mage/cards/c/ClashOfTitans.java +++ b/Mage.Sets/src/mage/cards/c/ClashOfTitans.java @@ -6,10 +6,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2; + /** * @author TheElk801 */ @@ -24,7 +27,7 @@ public final class ClashOfTitans extends CardImpl { target.setTargetTag(1); this.getSpellAbility().addTarget(target); - target = new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2); + target = new TargetPermanent(FILTER_ANOTHER_CREATURE_TARGET_2); target.setTargetTag(2); this.getSpellAbility().addTarget(target); } diff --git a/Mage.Sets/src/mage/cards/c/ClearAPath.java b/Mage.Sets/src/mage/cards/c/ClearAPath.java index db45f3a0420..fda21aea8eb 100644 --- a/Mage.Sets/src/mage/cards/c/ClearAPath.java +++ b/Mage.Sets/src/mage/cards/c/ClearAPath.java @@ -11,6 +11,7 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -32,7 +33,7 @@ public final class ClearAPath extends CardImpl { // Destroy target creature with defender. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); this.getSpellAbility().addTarget(target); } diff --git a/Mage.Sets/src/mage/cards/c/ClearShot.java b/Mage.Sets/src/mage/cards/c/ClearShot.java index 3cd13c1c01a..d3ee7cadc1f 100644 --- a/Mage.Sets/src/mage/cards/c/ClearShot.java +++ b/Mage.Sets/src/mage/cards/c/ClearShot.java @@ -8,11 +8,14 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author LevelX2 */ @@ -28,7 +31,7 @@ public final class ClearShot extends CardImpl { // It deals damage equal to its power to target creature you don't control. this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect("It")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); // second target + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); // second target } diff --git a/Mage.Sets/src/mage/cards/c/CleavingSkyrider.java b/Mage.Sets/src/mage/cards/c/CleavingSkyrider.java index 9dd232ba792..5ae8dcd5ad5 100644 --- a/Mage.Sets/src/mage/cards/c/CleavingSkyrider.java +++ b/Mage.Sets/src/mage/cards/c/CleavingSkyrider.java @@ -1,28 +1,30 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.AttackingCreatureCount; import mage.abilities.effects.common.DamageTargetEffect; -import mage.constants.SubType; import mage.abilities.keyword.FlashAbility; -import mage.abilities.keyword.KickerAbility; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class CleavingSkyrider extends CardImpl { + private static final DynamicValue xValue = new AttackingCreatureCount("the number of attacking creatures"); + public CleavingSkyrider(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); @@ -41,11 +43,9 @@ public final class CleavingSkyrider extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Cleaving Skyrider enters the battlefield, if it was kicked, it deals X damage to any target, where X is the number of attacking creatures. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(new AttackingCreatureCount())), - KickedCondition.ONCE, - "When {this} enters, if it was kicked, it deals X damage to any target, where X is the number of attacking creatures." - ); + Ability ability = new EntersBattlefieldTriggeredAbility( + new DamageTargetEffect(xValue, "it").setText("it deals X damage to any target, where X is the number of attacking creatures") + ).withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/ClockworkAvian.java b/Mage.Sets/src/mage/cards/c/ClockworkAvian.java index 77f3d5787aa..0baa24bc0f3 100644 --- a/Mage.Sets/src/mage/cards/c/ClockworkAvian.java +++ b/Mage.Sets/src/mage/cards/c/ClockworkAvian.java @@ -8,15 +8,16 @@ import mage.abilities.condition.common.AttackedOrBlockedThisCombatSourceConditio import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; @@ -47,17 +48,13 @@ public final class ClockworkAvian extends CardImpl { )); // At end of combat, if Clockwork Avian attacked or blocked this combat, remove a +1/+0 counter from it. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EndOfCombatTriggeredAbility( - new RemoveCounterSourceEffect(CounterType.P1P0.createInstance()), false - ), AttackedOrBlockedThisCombatSourceCondition.instance, "At end of combat, " + - "if {this} attacked or blocked this combat, remove a +1/+0 counter from it." - ), new AttackedOrBlockedThisCombatWatcher()); + this.addAbility(new EndOfCombatTriggeredAbility( + new RemoveCounterSourceEffect(CounterType.P1P0.createInstance()).setText("remove a +1/+0 counter from it"), false + ).withInterveningIf(AttackedOrBlockedThisCombatSourceCondition.instance), new AttackedOrBlockedThisCombatWatcher()); // {X}, {tap}: Put up to X +1/+0 counters on Clockwork Avian. This ability can't cause the total number of +1/+0 counters on Clockwork Avian to be greater than four. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new ClockworkAvianEffect(), - new ManaCostsImpl<>("{X}"), new IsStepCondition(PhaseStep.UPKEEP) + Ability ability = new ActivateIfConditionActivatedAbility( + new ClockworkAvianEffect(), new ManaCostsImpl<>("{X}"), IsStepCondition.getMyUpkeep() ); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/c/ClockworkBeast.java b/Mage.Sets/src/mage/cards/c/ClockworkBeast.java index 499f38d6457..aaef5b5002b 100644 --- a/Mage.Sets/src/mage/cards/c/ClockworkBeast.java +++ b/Mage.Sets/src/mage/cards/c/ClockworkBeast.java @@ -9,14 +9,15 @@ import mage.abilities.condition.common.AttackedOrBlockedThisCombatSourceConditio import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; @@ -44,17 +45,13 @@ public final class ClockworkBeast extends CardImpl { )); // At end of combat, if Clockwork Beast attacked or blocked this combat, remove a +1/+0 counter from it. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EndOfCombatTriggeredAbility( - new RemoveCounterSourceEffect(CounterType.P1P0.createInstance()), false - ), AttackedOrBlockedThisCombatSourceCondition.instance, "At end of combat, " + - "if {this} attacked or blocked this combat, remove a +1/+0 counter from it." - ), new AttackedOrBlockedThisCombatWatcher()); + this.addAbility(new EndOfCombatTriggeredAbility( + new RemoveCounterSourceEffect(CounterType.P1P0.createInstance()).setText("remove a +1/+0 counter from it"), false + ).withInterveningIf(AttackedOrBlockedThisCombatSourceCondition.instance), new AttackedOrBlockedThisCombatWatcher()); // {X}, {tap}: Put up to X +1/+0 counters on Clockwork Beast. This ability can't cause the total number of +1/+0 counters on Clockwork Beast to be greater than seven. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new ClockworkBeastEffect(), - new ManaCostsImpl<>("{X}"), new IsStepCondition(PhaseStep.UPKEEP) + Ability ability = new ActivateIfConditionActivatedAbility( + new ClockworkBeastEffect(), new ManaCostsImpl<>("{X}"), IsStepCondition.getMyUpkeep() ); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/c/ClockworkGnomes.java b/Mage.Sets/src/mage/cards/c/ClockworkGnomes.java index 810b2d41523..8587ac39d4d 100644 --- a/Mage.Sets/src/mage/cards/c/ClockworkGnomes.java +++ b/Mage.Sets/src/mage/cards/c/ClockworkGnomes.java @@ -14,6 +14,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class ClockworkGnomes extends CardImpl { // {3}, {tap}: Regenerate target artifact creature. Ability ability = new SimpleActivatedAbility(new RegenerateTargetEffect(), new ManaCostsImpl<>("{3}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/ClockworkServant.java b/Mage.Sets/src/mage/cards/c/ClockworkServant.java index 4893641718d..6ee4007302a 100644 --- a/Mage.Sets/src/mage/cards/c/ClockworkServant.java +++ b/Mage.Sets/src/mage/cards/c/ClockworkServant.java @@ -3,10 +3,10 @@ package mage.cards.c; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.AdamantCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; @@ -25,11 +25,8 @@ public final class ClockworkServant extends CardImpl { this.toughness = new MageInt(3); // Adamant - When Clockwork Servant enters the battlefield, if at least three mana of the same color was spent to cast it, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)), - AdamantCondition.ANY, "
Adamant — When {this} enters, " + - "if at least three mana of the same color was spent to cast it, draw a card." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .withInterveningIf(AdamantCondition.ANY).setAbilityWord(AbilityWord.ADAMANT)); } private ClockworkServant(final ClockworkServant card) { diff --git a/Mage.Sets/src/mage/cards/c/ClockworkSteed.java b/Mage.Sets/src/mage/cards/c/ClockworkSteed.java index d658e619f68..45aa3ebb66f 100644 --- a/Mage.Sets/src/mage/cards/c/ClockworkSteed.java +++ b/Mage.Sets/src/mage/cards/c/ClockworkSteed.java @@ -9,15 +9,17 @@ import mage.abilities.condition.common.AttackedOrBlockedThisCombatSourceConditio import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; @@ -52,17 +54,13 @@ public final class ClockworkSteed extends CardImpl { this.addAbility(new SimpleEvasionAbility(new CantBeBlockedByCreaturesSourceEffect(filter, Duration.WhileOnBattlefield))); // At end of combat, if Clockwork Steed attacked or blocked this combat, remove a +1/+0 counter from it. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EndOfCombatTriggeredAbility( - new RemoveCounterSourceEffect(CounterType.P1P0.createInstance()), false - ), AttackedOrBlockedThisCombatSourceCondition.instance, "At end of combat, " + - "if {this} attacked or blocked this combat, remove a +1/+0 counter from it." - ), new AttackedOrBlockedThisCombatWatcher()); + this.addAbility(new EndOfCombatTriggeredAbility( + new RemoveCounterSourceEffect(CounterType.P1P0.createInstance()).setText("remove a +1/+0 counter from it"), false + ).withInterveningIf(AttackedOrBlockedThisCombatSourceCondition.instance), new AttackedOrBlockedThisCombatWatcher()); // {X}, {tap}: Put up to X +1/+0 counters on Clockwork Steed. This ability can't cause the total number of +1/+0 counters on Clockwork Steed to be greater than four. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new ClockworkSteedEffect(), - new ManaCostsImpl<>("{X}"), new IsStepCondition(PhaseStep.UPKEEP) + Ability ability = new ActivateIfConditionActivatedAbility( + new ClockworkSteedEffect(), new ManaCostsImpl<>("{X}"), IsStepCondition.getMyUpkeep() ); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/c/ClockworkSwarm.java b/Mage.Sets/src/mage/cards/c/ClockworkSwarm.java index 002b971d144..25f9e70081f 100644 --- a/Mage.Sets/src/mage/cards/c/ClockworkSwarm.java +++ b/Mage.Sets/src/mage/cards/c/ClockworkSwarm.java @@ -9,15 +9,17 @@ import mage.abilities.condition.common.AttackedOrBlockedThisCombatSourceConditio import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; @@ -56,17 +58,13 @@ public final class ClockworkSwarm extends CardImpl { this.addAbility(new SimpleEvasionAbility(new CantBeBlockedByCreaturesSourceEffect(filter, Duration.WhileOnBattlefield))); // At end of combat, if Clockwork Swarm attacked or blocked this combat, remove a +1/+0 counter from it. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EndOfCombatTriggeredAbility( - new RemoveCounterSourceEffect(CounterType.P1P0.createInstance()), false - ), AttackedOrBlockedThisCombatSourceCondition.instance, "At end of combat, " + - "if {this} attacked or blocked this combat, remove a +1/+0 counter from it." - ), new AttackedOrBlockedThisCombatWatcher()); + this.addAbility(new EndOfCombatTriggeredAbility( + new RemoveCounterSourceEffect(CounterType.P1P0.createInstance()).setText("remove a +1/+0 counter from it"), false + ).withInterveningIf(AttackedOrBlockedThisCombatSourceCondition.instance), new AttackedOrBlockedThisCombatWatcher()); // {X}, {tap}: Put up to X +1/+0 counters on Clockwork Swarm. This ability can't cause the total number of +1/+0 counters on Clockwork Swarm to be greater than four. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new ClockworkSwarmEffect(), - new ManaCostsImpl<>("{X}"), new IsStepCondition(PhaseStep.UPKEEP) + Ability ability = new ActivateIfConditionActivatedAbility( + new ClockworkSwarmEffect(), new ManaCostsImpl<>("{X}"), IsStepCondition.getMyUpkeep() ); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/c/ClosingStatement.java b/Mage.Sets/src/mage/cards/c/ClosingStatement.java index 12444cbfcb2..aabb7a99b3a 100644 --- a/Mage.Sets/src/mage/cards/c/ClosingStatement.java +++ b/Mage.Sets/src/mage/cards/c/ClosingStatement.java @@ -16,13 +16,12 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreatureOrPlaneswalker; import java.util.UUID; /** - * * @author htrajan */ public final class ClosingStatement extends CardImpl { @@ -44,11 +43,9 @@ public final class ClosingStatement extends CardImpl { this.addAbility(ability); // Destroy target creature or planeswalker you don't control. Put a +1/+1 counter on up to one target creature you control. - this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker(1, 1, filter, false) - .setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanent(filter).setTargetTag(1)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, 1) - .setTargetTag(2)); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, 1).setTargetTag(2)); this.getSpellAbility().addEffect(new ClosingStatementEffect()); } @@ -85,9 +82,9 @@ class ClosingStatementEffect extends OneShotEffect { return false; } Target target = source.getTargets().stream() - .filter(t -> t.getTargetTag() == 2) - .findFirst() - .orElseThrow(() -> new IllegalStateException("Expected to find target with tag 2 but none exists")); + .filter(t -> t.getTargetTag() == 2) + .findFirst() + .orElseThrow(() -> new IllegalStateException("Expected to find target with tag 2 but none exists")); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { return permanent.addCounters(CounterType.P1P1.createInstance(), source.getControllerId(), source, game); diff --git a/Mage.Sets/src/mage/cards/c/CloudsLimitBreak.java b/Mage.Sets/src/mage/cards/c/CloudsLimitBreak.java index 25b96002dce..91b5eea84fd 100644 --- a/Mage.Sets/src/mage/cards/c/CloudsLimitBreak.java +++ b/Mage.Sets/src/mage/cards/c/CloudsLimitBreak.java @@ -16,7 +16,6 @@ import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; import java.util.Objects; import java.util.UUID; @@ -67,9 +66,9 @@ public final class CloudsLimitBreak extends CardImpl { } } -class CloudsLimitBreakTarget extends TargetCreaturePermanent { +class CloudsLimitBreakTarget extends TargetPermanent { - private static final FilterCreaturePermanent filter + private static final FilterPermanent filter = new FilterCreaturePermanent("tapped creatures with different controllers"); CloudsLimitBreakTarget() { diff --git a/Mage.Sets/src/mage/cards/c/CoalStoker.java b/Mage.Sets/src/mage/cards/c/CoalStoker.java index c8aadcb84fb..fdf9c173e7b 100644 --- a/Mage.Sets/src/mage/cards/c/CoalStoker.java +++ b/Mage.Sets/src/mage/cards/c/CoalStoker.java @@ -1,12 +1,9 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.Mana; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromHandSourcePermanentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.mana.BasicManaEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -14,24 +11,22 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.watchers.common.CastFromHandWatcher; +import java.util.UUID; + /** - * * @author ilcartographer */ public final class CoalStoker extends CardImpl { public CoalStoker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(3); this.toughness = new MageInt(3); // When Coal Stoker enters the battlefield, if you cast it from your hand, add {R}{R}{R}. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new BasicManaEffect(Mana.RedMana(3)), false), - CastFromHandSourcePermanentCondition.instance, - "When {this} enters, if you cast it from your hand, add {R}{R}{R}."), - new CastFromHandWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility(new BasicManaEffect(Mana.RedMana(3))) + .withInterveningIf(CastFromHandSourcePermanentCondition.instance), new CastFromHandWatcher()); } private CoalStoker(final CoalStoker card) { diff --git a/Mage.Sets/src/mage/cards/c/CoalitionRelic.java b/Mage.Sets/src/mage/cards/c/CoalitionRelic.java index 4ae44f6e614..69538a7d364 100644 --- a/Mage.Sets/src/mage/cards/c/CoalitionRelic.java +++ b/Mage.Sets/src/mage/cards/c/CoalitionRelic.java @@ -3,18 +3,17 @@ package mage.cards.c; import mage.Mana; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.mana.AnyColorManaAbility; +import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.choices.ChoiceColor; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; @@ -52,7 +51,7 @@ class CoalitionRelicEffect extends OneShotEffect { CoalitionRelicEffect() { super(Outcome.PutManaInPool); - this.staticText = "remove all charge counters from Coalition Relic. Add one mana of any color for each charge counter removed this way"; + this.staticText = "remove all charge counters from {this}. Add one mana of any color for each charge counter removed this way"; } private CoalitionRelicEffect(final CoalitionRelicEffect effect) { diff --git a/Mage.Sets/src/mage/cards/c/CoastalDrake.java b/Mage.Sets/src/mage/cards/c/CoastalDrake.java index 2e37b3766fc..d679c6aa728 100644 --- a/Mage.Sets/src/mage/cards/c/CoastalDrake.java +++ b/Mage.Sets/src/mage/cards/c/CoastalDrake.java @@ -15,8 +15,11 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.constants.SubType.KAVU; + /** * * @author Loki @@ -35,7 +38,7 @@ public final class CoastalDrake extends CardImpl { // {1}{U}, {T} : Return target Kavu to its owner's hand. Ability ability = new SimpleActivatedAbility(new ReturnToHandTargetEffect(), new ManaCostsImpl<>("{1}{U}")); - ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent(SubType.KAVU, "Kavu"))); + ability.addTarget(new TargetPermanent(new FilterCreaturePermanent(KAVU, "Kavu"))); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CoastalWizard.java b/Mage.Sets/src/mage/cards/c/CoastalWizard.java index b476e1b3b5d..5a718460040 100644 --- a/Mage.Sets/src/mage/cards/c/CoastalWizard.java +++ b/Mage.Sets/src/mage/cards/c/CoastalWizard.java @@ -1,51 +1,40 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.MyTurnBeforeAttackersDeclaredCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.ReturnToHandSourceEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author fireshoes */ public final class CoastalWizard extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); - static { - filter.add(AnotherPredicate.instance); - } public CoastalWizard(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(1); this.toughness = new MageInt(1); // {tap}: Return Coastal Wizard and another target creature to their owners' hands. Activate this ability only during your turn, before attackers are declared. - Effect effect = new ReturnToHandSourceEffect(true); - effect.setText("Return Coastal Wizard"); - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - effect, new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); - effect = new ReturnToHandTargetEffect(); - effect.setText("and another target creature to their owners' hands"); - ability.addTarget(new TargetCreaturePermanent(filter)); - ability.addEffect(effect); + Ability ability = new ActivateIfConditionActivatedAbility( + new ReturnToHandSourceEffect(true).setText("return {this}"), + new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance + ); + ability.addEffect(new ReturnToHandTargetEffect().setText("and another target creature to their owners' hands")); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CoatiScavenger.java b/Mage.Sets/src/mage/cards/c/CoatiScavenger.java index 3f1c243b9d1..caf38252d54 100644 --- a/Mage.Sets/src/mage/cards/c/CoatiScavenger.java +++ b/Mage.Sets/src/mage/cards/c/CoatiScavenger.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DescendCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -29,11 +28,8 @@ public final class CoatiScavenger extends CardImpl { this.toughness = new MageInt(2); // Descend 4 -- When Coati Scavenger enters the battlefield, if there are four or more permanent cards in your graveyard, return target permanent card from your graveyard to your hand. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()), - DescendCondition.FOUR, "When {this} enters, if there are four or more " + - "permanent cards in your graveyard, return target permanent card from your graveyard to your hand." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()) + .withInterveningIf(DescendCondition.FOUR); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_PERMANENT)); this.addAbility(ability.setAbilityWord(AbilityWord.DESCEND_4).addHint(DescendCondition.getHint())); } diff --git a/Mage.Sets/src/mage/cards/c/CodespellCleric.java b/Mage.Sets/src/mage/cards/c/CodespellCleric.java index 8718d4b0ee6..0f92de10eef 100644 --- a/Mage.Sets/src/mage/cards/c/CodespellCleric.java +++ b/Mage.Sets/src/mage/cards/c/CodespellCleric.java @@ -5,7 +5,6 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; @@ -39,11 +38,8 @@ public final class CodespellCleric extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // When Codespell Cleric enters the battlefield, if it was the second spell you cast this turn, put a +1/+1 counter on target creature. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())), - CodespellClericCondition.instance, "When {this} enters, " + - "if it was the second spell you cast this turn, put a +1/+1 counter on target creature." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())) + .withInterveningIf(CodespellClericCondition.instance); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability, new CodespellClericWatcher()); } @@ -66,6 +62,11 @@ enum CodespellClericCondition implements Condition { CodespellClericWatcher watcher = game.getState().getWatcher(CodespellClericWatcher.class); return watcher != null && watcher.checkSpell(source, game); } + + @Override + public String toString() { + return "it was the second spell you cast this turn"; + } } class CodespellClericWatcher extends Watcher { diff --git a/Mage.Sets/src/mage/cards/c/CoffinPuppets.java b/Mage.Sets/src/mage/cards/c/CoffinPuppets.java index 7ca089511df..4e8fa10b7e7 100644 --- a/Mage.Sets/src/mage/cards/c/CoffinPuppets.java +++ b/Mage.Sets/src/mage/cards/c/CoffinPuppets.java @@ -1,4 +1,3 @@ - package mage.cards.c; import mage.MageInt; @@ -12,12 +11,10 @@ import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffec import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.PhaseStep; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterControlledLandPermanent; import mage.filter.common.FilterControlledPermanent; -import mage.target.common.TargetControlledPermanent; import java.util.UUID; @@ -38,7 +35,7 @@ public final class CoffinPuppets extends CardImpl { private static final Condition condition = new CompoundCondition( "during your upkeep and only if you control a Swamp", new PermanentsOnTheBattlefieldCondition(filter), - new IsStepCondition(PhaseStep.UPKEEP) + IsStepCondition.getMyUpkeep() ); public CoffinPuppets(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/CogworkLibrarian.java b/Mage.Sets/src/mage/cards/c/CogworkLibrarian.java index 0460290b3a9..c3ad17b06bf 100644 --- a/Mage.Sets/src/mage/cards/c/CogworkLibrarian.java +++ b/Mage.Sets/src/mage/cards/c/CogworkLibrarian.java @@ -1,15 +1,16 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.InfoEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.InfoEffect; + +import java.util.UUID; /** * @@ -27,12 +28,12 @@ public final class CogworkLibrarian extends CardImpl { // TODO: Draft specific abilities not implemented // Draft Cogwork Librarian face up. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft Cogwork Librarian face up - not implemented."))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft {this} face up - not implemented."))); // As you draft a card, you may draft an additional card from that booster pack. If you do, put Cogwork Librarian into that booster pack. this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("As you draft a card, " + "you may draft an additional card from that booster pack. If you do, " - + "put Cogwork Librarian into that booster pack - not implemented."))); + + "put {this} into that booster pack - not implemented."))); } private CogworkLibrarian(final CogworkLibrarian card) { diff --git a/Mage.Sets/src/mage/cards/c/CogworkSpy.java b/Mage.Sets/src/mage/cards/c/CogworkSpy.java index f8ee109d1db..bb02a3c810c 100644 --- a/Mage.Sets/src/mage/cards/c/CogworkSpy.java +++ b/Mage.Sets/src/mage/cards/c/CogworkSpy.java @@ -28,7 +28,7 @@ public final class CogworkSpy extends CardImpl { // TODO: Draft specific abilities not implemented // Reveal Cogwork Spy as you draft it. You may look at the next card drafted from this booster pack. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Reveal Cogwork Spy as you draft it. " + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Reveal {this} as you draft it. " + "You may look at the next card drafted from this booster pack - not implemented."))); // Flying diff --git a/Mage.Sets/src/mage/cards/c/CoilingStalker.java b/Mage.Sets/src/mage/cards/c/CoilingStalker.java index 4990d4c8845..701ad3b8e89 100644 --- a/Mage.Sets/src/mage/cards/c/CoilingStalker.java +++ b/Mage.Sets/src/mage/cards/c/CoilingStalker.java @@ -1,24 +1,24 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.constants.SubType; import mage.abilities.keyword.NinjutsuAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author weirddan455 */ public final class CoilingStalker extends CardImpl { @@ -43,7 +43,7 @@ public final class CoilingStalker extends CardImpl { // Whenever Coiling Stalker deals combat damage to a player, put a +1/+1 counter on target creature you control that doesn't have a +1/+1 counter on it. Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false); - ability.addTarget(new TargetControlledCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/ColfenorTheLastYew.java b/Mage.Sets/src/mage/cards/c/ColfenorTheLastYew.java index 7c4f5018f3e..93109b0530b 100644 --- a/Mage.Sets/src/mage/cards/c/ColfenorTheLastYew.java +++ b/Mage.Sets/src/mage/cards/c/ColfenorTheLastYew.java @@ -2,13 +2,17 @@ package mage.cards.c; import mage.MageInt; import mage.MageObjectReference; +import mage.abilities.Ability; import mage.abilities.common.DiesThisOrAnotherTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.ReachAbility; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; @@ -16,10 +20,10 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.MageObjectReferencePredicate; import mage.filter.predicate.mageobject.ToughnessPredicate; import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; +import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.GenericTargetAdjuster; import java.util.UUID; @@ -44,7 +48,10 @@ public final class ColfenorTheLastYew extends CardImpl { this.addAbility(ReachAbility.getInstance()); // Whenever Colfenor, the Last Yew or another creature you control dies, return up to one other target creature card with lesser toughness from your graveyard to your hand. - this.addAbility(new ColfenorTheLastYewTriggeredAbility()); + Ability ability = new DiesThisOrAnotherTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), false, StaticFilters.FILTER_CONTROLLED_CREATURE); + ability.addTarget(new TargetCardInYourGraveyard(0, 1, new FilterCreatureCard("other target creature card with lesser toughness"))); + ability.setTargetAdjuster(new ColfenorTheLastYewTargetAdjuster()); + this.addAbility(ability); } private ColfenorTheLastYew(final ColfenorTheLastYew card) { @@ -56,43 +63,15 @@ public final class ColfenorTheLastYew extends CardImpl { return new ColfenorTheLastYew(this); } } - -class ColfenorTheLastYewTriggeredAbility extends DiesThisOrAnotherTriggeredAbility { - - ColfenorTheLastYewTriggeredAbility() { - super(new ReturnFromGraveyardToHandTargetEffect(), false, StaticFilters.FILTER_CONTROLLED_CREATURE); - } - - private ColfenorTheLastYewTriggeredAbility(final ColfenorTheLastYewTriggeredAbility ability) { - super(ability); - } - +class ColfenorTheLastYewTargetAdjuster extends GenericTargetAdjuster { @Override - public DiesThisOrAnotherTriggeredAbility copy() { - return new ColfenorTheLastYewTriggeredAbility(this); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (!super.checkTrigger(event, game)) { - return false; - } - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - Permanent permanent = zEvent.getTarget(); - if (permanent == null) { - return false; - } + public void adjustTargets(Ability ability, Game game) { + Permanent permanent = (Permanent)ability.getEffects().get(0).getValue("creatureDied"); + ability.getTargets().clear(); + Target newTarget = blueprintTarget.copy(); FilterCard filterCard = new FilterCreatureCard("creature card with toughness less than " + permanent.getToughness().getValue()); filterCard.add(new ToughnessPredicate(ComparisonType.FEWER_THAN, permanent.getToughness().getValue())); filterCard.add(Predicates.not(new MageObjectReferencePredicate(new MageObjectReference(permanent, game)))); - this.getTargets().clear(); - this.addTarget(new TargetCardInYourGraveyard(0, 1, filterCard)); - return true; - } - - @Override - public String getRule() { - return "Whenever {this} or another creature you control dies, return up to one other target creature card " + - "with lesser toughness from your graveyard to your hand."; + ability.addTarget(newTarget); } } diff --git a/Mage.Sets/src/mage/cards/c/CollarTheCulprit.java b/Mage.Sets/src/mage/cards/c/CollarTheCulprit.java index a5a1e96eea0..ca360a0db11 100644 --- a/Mage.Sets/src/mage/cards/c/CollarTheCulprit.java +++ b/Mage.Sets/src/mage/cards/c/CollarTheCulprit.java @@ -9,6 +9,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ToughnessPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -28,7 +29,7 @@ public final class CollarTheCulprit extends CardImpl { // Destroy target creature with toughness 4 or greater. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private CollarTheCulprit(final CollarTheCulprit card) { @@ -39,4 +40,4 @@ public final class CollarTheCulprit extends CardImpl { public CollarTheCulprit copy() { return new CollarTheCulprit(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/c/CollectedConjuring.java b/Mage.Sets/src/mage/cards/c/CollectedConjuring.java index b838db5ce86..c38757e772b 100644 --- a/Mage.Sets/src/mage/cards/c/CollectedConjuring.java +++ b/Mage.Sets/src/mage/cards/c/CollectedConjuring.java @@ -76,6 +76,8 @@ class CollectedConjuringEffect extends OneShotEffect { } Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 6)); controller.moveCards(cards, Zone.EXILED, source, game); + game.processAction(); + cards.retainZone(Zone.EXILED, game); CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, filter, 2); controller.putCardsOnBottomOfLibrary(cards, game, source, false); return true; diff --git a/Mage.Sets/src/mage/cards/c/CollectiveDefiance.java b/Mage.Sets/src/mage/cards/c/CollectiveDefiance.java index b38e425645d..e9b252575d2 100644 --- a/Mage.Sets/src/mage/cards/c/CollectiveDefiance.java +++ b/Mage.Sets/src/mage/cards/c/CollectiveDefiance.java @@ -15,6 +15,7 @@ import mage.filter.FilterPlayer; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponentOrPlaneswalker; @@ -47,7 +48,7 @@ public final class CollectiveDefiance extends CardImpl { Effect effect = new DamageTargetEffect(4); effect.setText("{this} deals 4 damage to target creature"); Mode mode = new Mode(effect); - mode.addTarget(new TargetCreaturePermanent(filterCreature).withChooseHint("deals 4 damage to")); + mode.addTarget(new TargetPermanent(filterCreature).withChooseHint("deals 4 damage to")); this.getSpellAbility().addMode(mode); // Collective Defiance deals 3 damage to target opponent or planeswalker. diff --git a/Mage.Sets/src/mage/cards/c/CollectiveEffort.java b/Mage.Sets/src/mage/cards/c/CollectiveEffort.java index ccff1b45ca4..9ba56cd19d1 100644 --- a/Mage.Sets/src/mage/cards/c/CollectiveEffort.java +++ b/Mage.Sets/src/mage/cards/c/CollectiveEffort.java @@ -20,8 +20,8 @@ import mage.filter.predicate.mageobject.PowerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.TargetPlayer; -import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetEnchantmentPermanent; @@ -43,7 +43,7 @@ public final class CollectiveEffort extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{W}{W}"); // Escalate — Tap an untapped creature you control. - this.addAbility(new EscalateAbility(new TapTargetCost(new TargetControlledCreaturePermanent(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE)))); + this.addAbility(new EscalateAbility(new TapTargetCost(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE))); // Choose one or more — this.getSpellAbility().getModes().setMinModes(1); @@ -51,7 +51,7 @@ public final class CollectiveEffort extends CardImpl { // Destroy target creature with power 4 or greater.; this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterDestroyCreature).withChooseHint("destroy")); + this.getSpellAbility().addTarget(new TargetPermanent(filterDestroyCreature).withChooseHint("destroy")); // Destroy target enchantment.; Effect effect = new DestroyTargetEffect(); diff --git a/Mage.Sets/src/mage/cards/c/ColossalMajesty.java b/Mage.Sets/src/mage/cards/c/ColossalMajesty.java index 3b9395291dd..61c2aa0ee8b 100644 --- a/Mage.Sets/src/mage/cards/c/ColossalMajesty.java +++ b/Mage.Sets/src/mage/cards/c/ColossalMajesty.java @@ -1,10 +1,9 @@ package mage.cards.c; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.common.FerociousCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.hint.common.FerociousHint; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -20,15 +19,8 @@ public final class ColossalMajesty extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); // At the beginning of your upkeep, if you control a creature with power 4 or greater, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - new DrawCardSourceControllerEffect(1), false - ), - FerociousCondition.instance, - "At the beginning of your upkeep, " - + "if you control a creature with power 4 or greater, " - + "draw a card." - ).addHint(FerociousHint.instance)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .withInterveningIf(FerociousCondition.instance).addHint(FerociousHint.instance)); } private ColossalMajesty(final ColossalMajesty card) { diff --git a/Mage.Sets/src/mage/cards/c/ColossusOfSardia.java b/Mage.Sets/src/mage/cards/c/ColossusOfSardia.java index 52a44993f62..e413df1c79c 100644 --- a/Mage.Sets/src/mage/cards/c/ColossusOfSardia.java +++ b/Mage.Sets/src/mage/cards/c/ColossusOfSardia.java @@ -1,12 +1,10 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.IsStepCondition; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect; import mage.abilities.effects.common.UntapSourceEffect; import mage.abilities.keyword.TrampleAbility; @@ -14,17 +12,16 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.PhaseStep; -import mage.constants.Zone; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class ColossusOfSardia extends CardImpl { public ColossusOfSardia(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{9}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{9}"); this.subtype.add(SubType.GOLEM); this.power = new MageInt(9); @@ -37,8 +34,9 @@ public final class ColossusOfSardia extends CardImpl { this.addAbility(new SimpleStaticAbility(new DontUntapInControllersUntapStepSourceEffect())); // {9}: Untap Colossus of Sardia. Activate this ability only during your upkeep. - this.addAbility(new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new UntapSourceEffect(), new ManaCostsImpl<>("{9}"), new IsStepCondition(PhaseStep.UPKEEP), null)); + this.addAbility(new ActivateIfConditionActivatedAbility( + new UntapSourceEffect(), new GenericManaCost(9), IsStepCondition.getMyUpkeep() + )); } private ColossusOfSardia(final ColossusOfSardia card) { diff --git a/Mage.Sets/src/mage/cards/c/ComboAttack.java b/Mage.Sets/src/mage/cards/c/ComboAttack.java index 2b17b496161..8acc59d0cf4 100644 --- a/Mage.Sets/src/mage/cards/c/ComboAttack.java +++ b/Mage.Sets/src/mage/cards/c/ComboAttack.java @@ -1,30 +1,34 @@ package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.filter.FilterPermanent; import mage.filter.common.FilterTeamCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class ComboAttack extends CardImpl { + private static final FilterPermanent filter = new FilterTeamCreaturePermanent("creatures your team controls"); + public ComboAttack(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); // Two target creatures your team controls each deal damage equal to their power to target creature. this.getSpellAbility().addEffect(new ComboAttackEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(2, 2, new FilterTeamCreaturePermanent(), false)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(1)); + this.getSpellAbility().addTarget(new TargetPermanent(2, filter)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } private ComboAttack(final ComboAttack card) { diff --git a/Mage.Sets/src/mage/cards/c/Combust.java b/Mage.Sets/src/mage/cards/c/Combust.java index b625cd51b69..7e0703f4087 100644 --- a/Mage.Sets/src/mage/cards/c/Combust.java +++ b/Mage.Sets/src/mage/cards/c/Combust.java @@ -15,6 +15,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -36,7 +37,7 @@ public final class Combust extends CardImpl { // Combust deals 5 damage to target white or blue creature. The damage can't be prevented. this.getSpellAbility().addEffect(new DamageTargetEffect(5, false)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Combust can't be countered. Ability ability = new SimpleStaticAbility(Zone.STACK, new CantBeCounteredSourceEffect()); @@ -53,4 +54,4 @@ public final class Combust extends CardImpl { return new Combust(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/c/CometStellarPup.java b/Mage.Sets/src/mage/cards/c/CometStellarPup.java index 9231561d959..70943e564f3 100644 --- a/Mage.Sets/src/mage/cards/c/CometStellarPup.java +++ b/Mage.Sets/src/mage/cards/c/CometStellarPup.java @@ -78,7 +78,7 @@ class CometStellarPupAbility extends OneShotEffect { + "1 or 2 — [+2], then create two 1/1 green Squirrel creature tokens. They gain haste until end of turn.
" + "3 — [-1], then return a card with mana value 2 or less from your graveyard to your hand.
" + "4 or 5 — {this} deals damage equal to the number of loyalty counters on him to a creature or player, then [-2].
" - + "6 — [+1], and you may activate Comet, Stellar Pup's loyalty ability two more times this turn."; + + "6 — [+1], and you may activate {this}'s loyalty ability two more times this turn."; } private CometStellarPupAbility(final CometStellarPupAbility effect) { diff --git a/Mage.Sets/src/mage/cards/c/CommandBridge.java b/Mage.Sets/src/mage/cards/c/CommandBridge.java new file mode 100644 index 00000000000..86a2d545de8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CommandBridge.java @@ -0,0 +1,51 @@ +package mage.cards.c; + +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; +import mage.abilities.mana.AnyColorManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.TappedPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CommandBridge extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledPermanent("an untapped permanent you control"); + + static { + filter.add(TappedPredicate.UNTAPPED); + } + + public CommandBridge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // This land enters tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // When this land enters, sacrifice it unless you tap an untapped permanent you control. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SacrificeSourceUnlessPaysEffect(new TapTargetCost(filter)) + )); + + // {T}: Add one mana of any color. + this.addAbility(new AnyColorManaAbility()); + } + + private CommandBridge(final CommandBridge card) { + super(card); + } + + @Override + public CommandBridge copy() { + return new CommandBridge(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CompanionOfTheTrials.java b/Mage.Sets/src/mage/cards/c/CompanionOfTheTrials.java index fdd89ef531f..41d068b8245 100644 --- a/Mage.Sets/src/mage/cards/c/CompanionOfTheTrials.java +++ b/Mage.Sets/src/mage/cards/c/CompanionOfTheTrials.java @@ -1,9 +1,9 @@ - package mage.cards.c; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.UntapTargetEffect; @@ -12,22 +12,19 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterPlaneswalkerPermanent; +import mage.filter.common.FilterControlledPlaneswalkerPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** - * * @author fireshoes */ public final class CompanionOfTheTrials extends CardImpl { - private static final FilterPlaneswalkerPermanent filter = new FilterPlaneswalkerPermanent("you control a Gideon planeswalker"); - static { - filter.add(SubType.GIDEON.getPredicate()); - } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPlaneswalkerPermanent(SubType.GIDEON, "you control a Gideon planeswalker") + ); public CompanionOfTheTrials(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); @@ -41,10 +38,9 @@ public final class CompanionOfTheTrials extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // {1}{W}: Untap target creature. Activate this ability only if you control a Gideon planeswalker. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new UntapTargetEffect(), - new ManaCostsImpl<>("{1}{W}"), - new PermanentsOnTheBattlefieldCondition(filter)); + Ability ability = new ActivateIfConditionActivatedAbility( + new UntapTargetEffect(), new ManaCostsImpl<>("{1}{W}"), condition + ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CompleteDisregard.java b/Mage.Sets/src/mage/cards/c/CompleteDisregard.java index f6569b7c01c..fa48129824d 100644 --- a/Mage.Sets/src/mage/cards/c/CompleteDisregard.java +++ b/Mage.Sets/src/mage/cards/c/CompleteDisregard.java @@ -10,6 +10,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -32,7 +33,7 @@ public final class CompleteDisregard extends CardImpl { // Exile target creature with power 3 or less. this.getSpellAbility().addEffect(new ExileTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private CompleteDisregard(final CompleteDisregard card) { diff --git a/Mage.Sets/src/mage/cards/c/ComplexAutomaton.java b/Mage.Sets/src/mage/cards/c/ComplexAutomaton.java index 39fb2aa589f..62db8ffaa9f 100644 --- a/Mage.Sets/src/mage/cards/c/ComplexAutomaton.java +++ b/Mage.Sets/src/mage/cards/c/ComplexAutomaton.java @@ -1,20 +1,16 @@ - package mage.cards.c; import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.ReturnToHandSourceEffect; -import mage.abilities.hint.ValueHint; +import mage.abilities.hint.common.PermanentsYouControlHint; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; import java.util.UUID; @@ -25,7 +21,7 @@ import java.util.UUID; public final class ComplexAutomaton extends CardImpl { private static final Condition condition = new PermanentsOnTheBattlefieldCondition( - StaticFilters.FILTER_CONTROLLED_PERMANENT, ComparisonType.MORE_THAN, 6 + new FilterControlledPermanent("you control seven or more permanents"), ComparisonType.MORE_THAN, 6 ); public ComplexAutomaton(UUID ownerId, CardSetInfo setInfo) { @@ -36,12 +32,8 @@ public final class ComplexAutomaton extends CardImpl { this.toughness = new MageInt(4); // At the beginning of your upkeep, if you control seven or more permanents, return Complex Automaton to its owner's hand. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - new ReturnToHandSourceEffect(true), false - ), condition, "At the beginning of your upkeep, " + - "if you control seven or more permanents, return {this} to its owner's hand." - ).addHint(new ValueHint("Permanents you control", new PermanentsOnBattlefieldCount(new FilterControlledPermanent())))); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new ReturnToHandSourceEffect(true)) + .withInterveningIf(condition).addHint(PermanentsYouControlHint.instance)); } private ComplexAutomaton(final ComplexAutomaton card) { diff --git a/Mage.Sets/src/mage/cards/c/ConformerShuriken.java b/Mage.Sets/src/mage/cards/c/ConformerShuriken.java index 7a551915287..ad4eaea674c 100644 --- a/Mage.Sets/src/mage/cards/c/ConformerShuriken.java +++ b/Mage.Sets/src/mage/cards/c/ConformerShuriken.java @@ -86,7 +86,7 @@ class ConformerShurikenEffect extends OneShotEffect { .map(game::getPermanent) .map(MageObject::getPower) .map(MageInt::getValue) - .map(x -> permanent.getPower().getValue() - x) + .map(targetsPower -> targetsPower - permanent.getPower().getValue()) .filter(x -> x > 0 && permanent.addCounters(CounterType.P1P1.createInstance(x), source, game)) .isPresent(); } diff --git a/Mage.Sets/src/mage/cards/c/ConfoundingConundrum.java b/Mage.Sets/src/mage/cards/c/ConfoundingConundrum.java index dea670eae21..eeb9dbb09a8 100644 --- a/Mage.Sets/src/mage/cards/c/ConfoundingConundrum.java +++ b/Mage.Sets/src/mage/cards/c/ConfoundingConundrum.java @@ -4,8 +4,6 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; @@ -31,7 +29,7 @@ import java.util.UUID; */ public final class ConfoundingConundrum extends CardImpl { - private static final FilterPermanent filter = new FilterLandPermanent(); + private static final FilterPermanent filter = new FilterLandPermanent("a land an opponent controls"); static { filter.add(TargetController.OPPONENT.getControllerPredicate()); @@ -44,13 +42,10 @@ public final class ConfoundingConundrum extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1))); // Whenever a land enters the battlefield under an opponent's control, if that player had another land enter the battlefield under their control this turn, they return a land they control to its owner's hand. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldAllTriggeredAbility( - Zone.BATTLEFIELD, new ConfoundingConundrumEffect(), filter, - false, SetTargetPointer.PLAYER - ), ConfoundingConundrumCondition.instance, "Whenever a land enters the battlefield under " + - "an opponent's control, if that player had another land enter the battlefield " + - "under their control this turn, they return a land they control to its owner's hand." - ), new ConfoundingConundrumWatcher()); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + Zone.BATTLEFIELD, new ConfoundingConundrumEffect(), + filter, false, SetTargetPointer.PLAYER + ).withInterveningIf(ConfoundingConundrumCondition.instance), new ConfoundingConundrumWatcher()); } private ConfoundingConundrum(final ConfoundingConundrum card) { @@ -69,17 +64,16 @@ enum ConfoundingConundrumCondition implements Condition { @Override public boolean apply(Game game, Ability source) { ConfoundingConundrumWatcher watcher = game.getState().getWatcher(ConfoundingConundrumWatcher.class); - if (watcher == null) { - return false; - } - Player player = null; - for (Effect effect : source.getEffects()) { - if (player != null) { - break; - } - player = game.getPlayer(effect.getTargetPointer().getFirst(game, source)); - } - return player != null && watcher.checkPlayer(player.getId()); + return watcher != null + && CardUtil + .getEffectValueFromAbility(source, "permanentEnteringControllerId", UUID.class) + .filter(watcher::checkPlayer) + .isPresent(); + } + + @Override + public String toString() { + return "that player had another land enter the battlefield under their control this turn"; } } @@ -87,6 +81,7 @@ class ConfoundingConundrumEffect extends OneShotEffect { ConfoundingConundrumEffect() { super(Outcome.Benefit); + staticText = "they return a land they control to its owner's hand"; } private ConfoundingConundrumEffect(final ConfoundingConundrumEffect effect) { diff --git a/Mage.Sets/src/mage/cards/c/ConniveConcoct.java b/Mage.Sets/src/mage/cards/c/ConniveConcoct.java index c28f608578e..9e4ce30d66c 100644 --- a/Mage.Sets/src/mage/cards/c/ConniveConcoct.java +++ b/Mage.Sets/src/mage/cards/c/ConniveConcoct.java @@ -20,6 +20,7 @@ import mage.filter.predicate.mageobject.PowerPredicate; import mage.game.Game; import mage.players.Player; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -46,7 +47,7 @@ public final class ConniveConcoct extends SplitCard { new GainControlTargetEffect(Duration.Custom) ); this.getLeftHalfCard().getSpellAbility().addTarget( - new TargetCreaturePermanent(filter) + new TargetPermanent(filter) ); // Concoct diff --git a/Mage.Sets/src/mage/cards/c/ConqueringManticore.java b/Mage.Sets/src/mage/cards/c/ConqueringManticore.java index 439e6048dcb..e1819ed50ef 100644 --- a/Mage.Sets/src/mage/cards/c/ConqueringManticore.java +++ b/Mage.Sets/src/mage/cards/c/ConqueringManticore.java @@ -16,8 +16,11 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Duration; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author North @@ -36,7 +39,7 @@ public final class ConqueringManticore extends CardImpl { Ability ability = new EntersBattlefieldTriggeredAbility(new GainControlTargetEffect(Duration.EndOfTurn), false); ability.addEffect(new UntapTargetEffect().setText("Untap that creature")); ability.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn).setText("It gains haste until end of turn.")); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/Conscription.java b/Mage.Sets/src/mage/cards/c/Conscription.java index a54564c5d5c..656068c2d62 100644 --- a/Mage.Sets/src/mage/cards/c/Conscription.java +++ b/Mage.Sets/src/mage/cards/c/Conscription.java @@ -12,6 +12,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -34,7 +35,7 @@ public final class Conscription extends CardImpl { this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfGame)); this.getSpellAbility().addEffect(new BecomesCreatureTypeTargetEffect(Duration.EndOfGame, SubType.TROOPER, false) .setText("It becomes a Trooper in addition to its other types")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private Conscription(final Conscription card) { diff --git a/Mage.Sets/src/mage/cards/c/ConsulsLieutenant.java b/Mage.Sets/src/mage/cards/c/ConsulsLieutenant.java index 4a1c5be70f7..5035bafc11d 100644 --- a/Mage.Sets/src/mage/cards/c/ConsulsLieutenant.java +++ b/Mage.Sets/src/mage/cards/c/ConsulsLieutenant.java @@ -1,11 +1,9 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.RenownedSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.RenownAbility; @@ -14,23 +12,17 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.TargetController; -import mage.filter.common.FilterAttackingCreature; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class ConsulsLieutenant extends CardImpl { - private static final FilterAttackingCreature filter = new FilterAttackingCreature("attacking creatures you control"); - - static { - filter.add(TargetController.YOU.getControllerPredicate()); - } - public ConsulsLieutenant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); this.power = new MageInt(2); @@ -38,13 +30,14 @@ public final class ConsulsLieutenant extends CardImpl { // First strike this.addAbility(FirstStrikeAbility.getInstance()); + // Renown 1 this.addAbility(new RenownAbility(1)); + // Whenever Consul's Lieutenant attacks, if it's renowned, other attacking creatures you control get +1/+1 until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new AttacksTriggeredAbility( - new BoostControlledEffect(1, 1, Duration.EndOfTurn, filter, true), false), - RenownedSourceCondition.instance, - "Whenever Consul's Lieutenant attacks, if it's renowned, other attacking creatures you control get +1/+1 until end of turn.")); + this.addAbility(new AttacksTriggeredAbility(new BoostControlledEffect( + 1, 1, Duration.EndOfTurn, StaticFilters.FILTER_ATTACKING_CREATURES, true + )).withInterveningIf(RenownedSourceCondition.ITS)); } private ConsulsLieutenant(final ConsulsLieutenant card) { diff --git a/Mage.Sets/src/mage/cards/c/ConsulsShieldguard.java b/Mage.Sets/src/mage/cards/c/ConsulsShieldguard.java index 2efb58dae72..dfbe4a9d47d 100644 --- a/Mage.Sets/src/mage/cards/c/ConsulsShieldguard.java +++ b/Mage.Sets/src/mage/cards/c/ConsulsShieldguard.java @@ -16,6 +16,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterAttackingCreature; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -43,7 +44,7 @@ public final class ConsulsShieldguard extends CardImpl { // Whenever Consul's Shieldguard attacks, you may pay {E}. If you do, another target attacking creature gains indestructible until end of turn. Ability ability = new AttacksTriggeredAbility(new DoIfCostPaid(new GainAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), new PayEnergyCost(1))); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/ConsumeStrength.java b/Mage.Sets/src/mage/cards/c/ConsumeStrength.java index 4c2ad90b846..1cb173ebf76 100644 --- a/Mage.Sets/src/mage/cards/c/ConsumeStrength.java +++ b/Mage.Sets/src/mage/cards/c/ConsumeStrength.java @@ -1,23 +1,17 @@ - package mage.cards.c; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.other.AnotherTargetPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; -import mage.target.targetpointer.FixedTarget; +import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class ConsumeStrength extends CardImpl { @@ -26,18 +20,11 @@ public final class ConsumeStrength extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}{G}"); // Target creature gets +2/+2 until end of turn. Another target creature gets -2/-2 until end of turn. - this.getSpellAbility().addEffect(new ConsumeStrengthEffect()); - - FilterCreaturePermanent filter1 = new FilterCreaturePermanent("creature to get +2/+2"); - TargetCreaturePermanent target1 = new TargetCreaturePermanent(filter1); - target1.setTargetTag(1); - this.getSpellAbility().addTarget(target1); - - FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another creature to get -2/-2"); - filter2.add(new AnotherTargetPredicate(2)); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter2); - target2.setTargetTag(2); - this.getSpellAbility().addTarget(target2); + this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2)); + this.getSpellAbility().addEffect(new BoostTargetEffect(-2, -2) + .setText("another target creature gets -2/-2 until end of turn").setTargetPointer(new SecondTargetPointer())); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("+2/+2").setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2).withChooseHint("-2/-2").setTargetTag(2)); } private ConsumeStrength(final ConsumeStrength card) { @@ -49,37 +36,3 @@ public final class ConsumeStrength extends CardImpl { return new ConsumeStrength(this); } } - -class ConsumeStrengthEffect extends OneShotEffect { - - ConsumeStrengthEffect() { - super(Outcome.BoostCreature); - this.staticText = "Target creature gets +2/+2 until end of turn. Another target creature gets -2/-2 until end of turn"; - } - - private ConsumeStrengthEffect(final ConsumeStrengthEffect effect) { - super(effect); - } - - @Override - public ConsumeStrengthEffect copy() { - return new ConsumeStrengthEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent != null) { - ContinuousEffect effect = new BoostTargetEffect(2, 2, Duration.EndOfTurn); - effect.setTargetPointer(new FixedTarget(permanent, game)); - game.addEffect(effect, source); - } - permanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - if (permanent != null) { - ContinuousEffect effect = new BoostTargetEffect(-2, -2, Duration.EndOfTurn); - effect.setTargetPointer(new FixedTarget(permanent, game)); - game.addEffect(effect, source); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/c/ConsumingSinkhole.java b/Mage.Sets/src/mage/cards/c/ConsumingSinkhole.java index 5b1c94faafc..c91f9e2ebf6 100644 --- a/Mage.Sets/src/mage/cards/c/ConsumingSinkhole.java +++ b/Mage.Sets/src/mage/cards/c/ConsumingSinkhole.java @@ -11,6 +11,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetPlayerOrPlaneswalker; @@ -36,7 +37,7 @@ public final class ConsumingSinkhole extends CardImpl { Effect effect = new ExileTargetEffect(); effect.setText("Exile target land creature"); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Consuming Sinkhole deals 4 damage to target player. Mode mode = new Mode(new DamageTargetEffect(4)); diff --git a/Mage.Sets/src/mage/cards/c/ContaminantGrafter.java b/Mage.Sets/src/mage/cards/c/ContaminantGrafter.java index fa54288ffef..11bac1ff6ad 100644 --- a/Mage.Sets/src/mage/cards/c/ContaminantGrafter.java +++ b/Mage.Sets/src/mage/cards/c/ContaminantGrafter.java @@ -5,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.BatchTriggeredAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.condition.common.CorruptedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect; import mage.abilities.effects.common.counter.ProliferateEffect; @@ -49,15 +48,10 @@ public final class ContaminantGrafter extends CardImpl { // Corrupted — At the beginning of your end step, if an opponent has three or more poison // counters, draw a card, then you may put a land card from your hand onto the battlefield. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility(new DrawCardSourceControllerEffect(1)), - CorruptedCondition.instance, "At the beginning of your end step, if an opponent has three or more poison " + - "counters, draw a card, then you may put a land card from your hand onto the battlefield" - ); - ability.addEffect(new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_LAND_A).concatBy("then")); - ability.setAbilityWord(AbilityWord.CORRUPTED); - ability.addHint(CorruptedCondition.getHint()); - this.addAbility(ability); + Ability ability = new BeginningOfEndStepTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .withInterveningIf(CorruptedCondition.instance); + ability.addEffect(new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_LAND_A).concatBy(", then")); + this.addAbility(ability.setAbilityWord(AbilityWord.CORRUPTED).addHint(CorruptedCondition.getHint())); } private ContaminantGrafter(final ContaminantGrafter card) { diff --git a/Mage.Sets/src/mage/cards/c/ContestOfClaws.java b/Mage.Sets/src/mage/cards/c/ContestOfClaws.java index 71ddea06b8c..530b4a9847e 100644 --- a/Mage.Sets/src/mage/cards/c/ContestOfClaws.java +++ b/Mage.Sets/src/mage/cards/c/ContestOfClaws.java @@ -14,9 +14,12 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2; + /** * * @author jimga150 @@ -32,7 +35,7 @@ public final class ContestOfClaws extends CardImpl { Target target = new TargetControlledCreaturePermanent().setTargetTag(1); this.getSpellAbility().addTarget(target); - Target target2 = new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2).setTargetTag(2); + Target target2 = new TargetPermanent(FILTER_ANOTHER_CREATURE_TARGET_2).setTargetTag(2); this.getSpellAbility().addTarget(target2); } diff --git a/Mage.Sets/src/mage/cards/c/ContestedCliffs.java b/Mage.Sets/src/mage/cards/c/ContestedCliffs.java index eece6e5d555..32d59b7b26f 100644 --- a/Mage.Sets/src/mage/cards/c/ContestedCliffs.java +++ b/Mage.Sets/src/mage/cards/c/ContestedCliffs.java @@ -18,8 +18,11 @@ import mage.constants.Zone; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -42,9 +45,9 @@ public final class ContestedCliffs extends CardImpl { Effect effect = new FightTargetsEffect(); Ability ability = new SimpleActivatedAbility(effect, new ManaCostsImpl<>("{R}{G}")); ability.addCost(new TapSourceCost()); - Target target1 = new TargetCreaturePermanent(filter1); + Target target1 = new TargetPermanent(filter1); ability.addTarget(target1); - Target target2 = new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE); + Target target2 = new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE); ability.addTarget(target2); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/ControlledInstincts.java b/Mage.Sets/src/mage/cards/c/ControlledInstincts.java index cd8e447f483..80801916ad4 100644 --- a/Mage.Sets/src/mage/cards/c/ControlledInstincts.java +++ b/Mage.Sets/src/mage/cards/c/ControlledInstincts.java @@ -39,7 +39,7 @@ public final class ControlledInstincts extends CardImpl { // Enchant red or green creature - TargetPermanent auraTarget = new TargetCreaturePermanent(filter); + TargetPermanent auraTarget = new TargetPermanent(filter); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); this.addAbility(new EnchantAbility(auraTarget)); diff --git a/Mage.Sets/src/mage/cards/c/ConvalescentCare.java b/Mage.Sets/src/mage/cards/c/ConvalescentCare.java index 6df37fb1d05..462c541f382 100644 --- a/Mage.Sets/src/mage/cards/c/ConvalescentCare.java +++ b/Mage.Sets/src/mage/cards/c/ConvalescentCare.java @@ -1,11 +1,10 @@ package mage.cards.c; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.Ability; import mage.abilities.condition.common.FatefulHourCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -13,19 +12,17 @@ import mage.constants.CardType; import java.util.UUID; /** - * * @author fireshoes */ public final class ConvalescentCare extends CardImpl { public ConvalescentCare(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{W}"); // At the beginning of your upkeep, if you have 5 or less life, you gain 3 life and draw a card. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new GainLifeEffect(3)); - ability.addEffect(new DrawCardSourceControllerEffect(1)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, FatefulHourCondition.instance, - "At the beginning of your upkeep, if you have 5 or less life, you gain 3 life and draw a card.")); + Ability ability = new BeginningOfUpkeepTriggeredAbility(new GainLifeEffect(3)).withInterveningIf(FatefulHourCondition.instance); + ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); + this.addAbility(ability); } private ConvalescentCare(final ConvalescentCare card) { @@ -36,6 +33,6 @@ public final class ConvalescentCare extends CardImpl { public ConvalescentCare copy() { return new ConvalescentCare(this); } - + } diff --git a/Mage.Sets/src/mage/cards/c/CoralNet.java b/Mage.Sets/src/mage/cards/c/CoralNet.java index 2fccfb646fd..8526fadae55 100644 --- a/Mage.Sets/src/mage/cards/c/CoralNet.java +++ b/Mage.Sets/src/mage/cards/c/CoralNet.java @@ -41,7 +41,7 @@ public final class CoralNet extends CardImpl { this.subtype.add(SubType.AURA); // Enchant green or white creature - TargetPermanent auraTarget = new TargetCreaturePermanent(filter); + TargetPermanent auraTarget = new TargetPermanent(filter); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); this.addAbility(new EnchantAbility(auraTarget)); diff --git a/Mage.Sets/src/mage/cards/c/CoralReef.java b/Mage.Sets/src/mage/cards/c/CoralReef.java index 46bd9d0d43e..a8935d15e9b 100644 --- a/Mage.Sets/src/mage/cards/c/CoralReef.java +++ b/Mage.Sets/src/mage/cards/c/CoralReef.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; @@ -17,25 +16,23 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class CoralReef extends CardImpl { - + private static final FilterControlledPermanent islandFilter = new FilterControlledPermanent("an Island"); private static final FilterControlledCreaturePermanent untappedBlueCreatureFilter = new FilterControlledCreaturePermanent("an untapped blue creature you control"); - + static { islandFilter.add(SubType.ISLAND.getPredicate()); untappedBlueCreatureFilter.add(TappedPredicate.UNTAPPED); @@ -43,22 +40,22 @@ public final class CoralReef extends CardImpl { } public CoralReef(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}{U}"); // Coral Reef enters the battlefield with four polyp counters on it. Effect effect = new AddCountersSourceEffect(CounterType.POLYP.createInstance(4)); effect.setText("with four polyp counters on it"); this.addAbility(new EntersBattlefieldAbility(effect)); - + // Sacrifice an Island: Put two polyp counters on Coral Reef. effect = new AddCountersSourceEffect(CounterType.POLYP.createInstance(2), true); effect.setText("Put two polyp counters on {this}"); this.addAbility(new SimpleActivatedAbility(effect, new SacrificeTargetCost(islandFilter))); - + // {U}, Tap an untapped blue creature you control, Remove a polyp counter from Coral Reef: Put a +0/+1 counter on target creature. Ability ability = new SimpleActivatedAbility(new AddCountersTargetEffect(CounterType.P0P1.createInstance()), new ManaCostsImpl<>("{U}")); - ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(untappedBlueCreatureFilter))); + ability.addCost(new TapTargetCost(untappedBlueCreatureFilter)); ability.addCost(new RemoveCountersSourceCost(CounterType.POLYP.createInstance())); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/c/Corpsehatch.java b/Mage.Sets/src/mage/cards/c/Corpsehatch.java index 254bb590334..2a039f0f94c 100644 --- a/Mage.Sets/src/mage/cards/c/Corpsehatch.java +++ b/Mage.Sets/src/mage/cards/c/Corpsehatch.java @@ -8,8 +8,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; import mage.game.permanent.token.EldraziSpawnToken; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author North @@ -19,7 +22,7 @@ public final class Corpsehatch extends CardImpl { public Corpsehatch(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}{B}"); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addEffect(new CreateTokenEffect(new EldraziSpawnToken(), 2).withTextOptions(true)); } diff --git a/Mage.Sets/src/mage/cards/c/CosmicHorror.java b/Mage.Sets/src/mage/cards/c/CosmicHorror.java index 4d01d7a3a47..5bc52c79bc8 100644 --- a/Mage.Sets/src/mage/cards/c/CosmicHorror.java +++ b/Mage.Sets/src/mage/cards/c/CosmicHorror.java @@ -16,7 +16,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import java.util.Locale; import java.util.UUID; /** @@ -34,7 +33,7 @@ public final class CosmicHorror extends CardImpl { this.addAbility(FirstStrikeAbility.getInstance()); // At the beginning of your upkeep, destroy Cosmic Horror unless you pay {3}{B}{B}{B}. If Cosmic Horror is destroyed this way, it deals 7 damage to you. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CosmicHorrorEffect(new ManaCostsImpl<>("{3}{B}{B}{B}")))); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CosmicHorrorEffect())); } private CosmicHorror(final CosmicHorror card) { @@ -49,30 +48,22 @@ public final class CosmicHorror extends CardImpl { class CosmicHorrorEffect extends OneShotEffect { - protected Cost cost; - - public CosmicHorrorEffect(Cost cost) { + CosmicHorrorEffect() { super(Outcome.DestroyPermanent); - this.cost = cost; - staticText = "destroy {this} unless you pay {3}{B}{B}{B}. If {this} is destroyed this way it deals 7 damage to you"; + staticText = "destroy {this} unless you pay {3}{B}{B}{B}. If {this} is destroyed this way, it deals 7 damage to you"; } private CosmicHorrorEffect(final CosmicHorrorEffect effect) { super(effect); - this.cost = effect.cost.copy(); } @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent cosmicHorror = game.getPermanentOrLKIBattlefield(source.getSourceId()); + Permanent cosmicHorror = source.getSourcePermanentIfItStillExists(game); if (controller != null && cosmicHorror != null) { - StringBuilder sb = new StringBuilder(cost.getText()).append('?'); - if (!sb.toString().toLowerCase(Locale.ENGLISH).startsWith("exile ") && !sb.toString().toLowerCase(Locale.ENGLISH).startsWith("return ")) { - sb.insert(0, "Pay "); - } - if (controller.chooseUse(Outcome.Benefit, sb.toString(), source, game)) { - cost.clearPaid(); + if (controller.chooseUse(Outcome.Benefit, "Pay {3}{B}{B}{B} to prevent destroy effect?", source, game)) { + Cost cost = new ManaCostsImpl<>("{3}{B}{B}{B}"); if (cost.pay(source, game, source, source.getControllerId(), false, null)) { return true; } diff --git a/Mage.Sets/src/mage/cards/c/CouncilOfEchoes.java b/Mage.Sets/src/mage/cards/c/CouncilOfEchoes.java index 38d74ce68ad..e80987d6522 100644 --- a/Mage.Sets/src/mage/cards/c/CouncilOfEchoes.java +++ b/Mage.Sets/src/mage/cards/c/CouncilOfEchoes.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DescendCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -42,12 +41,7 @@ public final class CouncilOfEchoes extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Descend 4 -- When Council of Echoes enters the battlefield, if there are four or more permanent cards in your graveyard, return up to one target nonland permanent other than Council of Echoes to its owner's hand. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), false), - DescendCondition.FOUR, "When {this} enters, " - + "if there are four or more permanent cards in your graveyard, " - + "return up to one target nonland permanent other than {this} to its owner's hand" - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), false).withInterveningIf(DescendCondition.FOUR); ability.addTarget(new TargetPermanent(0, 1, filter)); this.addAbility(ability.addHint(DescendCondition.getHint()).setAbilityWord(AbilityWord.DESCEND_4)); } diff --git a/Mage.Sets/src/mage/cards/c/CouncilsDeliberation.java b/Mage.Sets/src/mage/cards/c/CouncilsDeliberation.java index 4f2ffba28ef..49f43c0d995 100644 --- a/Mage.Sets/src/mage/cards/c/CouncilsDeliberation.java +++ b/Mage.Sets/src/mage/cards/c/CouncilsDeliberation.java @@ -4,7 +4,6 @@ import mage.abilities.common.ScryTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.ExileSourceFromGraveCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; @@ -22,7 +21,7 @@ import java.util.UUID; public final class CouncilsDeliberation extends CardImpl { private static final Condition condition - = new PermanentsOnTheBattlefieldCondition(new FilterControlledPermanent(SubType.ISLAND)); + = new PermanentsOnTheBattlefieldCondition(new FilterControlledPermanent(SubType.ISLAND, "you control an Island")); public CouncilsDeliberation(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); @@ -31,15 +30,11 @@ public final class CouncilsDeliberation extends CardImpl { this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); // Whenever you scry, if you control an Island, you may exile Council's Deliberation from your graveyard. If you do, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new ScryTriggeredAbility( - Zone.GRAVEYARD, - new DoIfCostPaid( - new DrawCardSourceControllerEffect(1), new ExileSourceFromGraveCost() - ), false - ), condition, "Whenever you scry, if you control an Island, " + - "you may exile {this} from your graveyard. If you do, draw a card." - )); + this.addAbility(new ScryTriggeredAbility( + Zone.GRAVEYARD, + new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new ExileSourceFromGraveCost()), + false + ).withInterveningIf(condition)); } private CouncilsDeliberation(final CouncilsDeliberation card) { diff --git a/Mage.Sets/src/mage/cards/c/CourierBat.java b/Mage.Sets/src/mage/cards/c/CourierBat.java index 185c1319596..b4c358748bb 100644 --- a/Mage.Sets/src/mage/cards/c/CourierBat.java +++ b/Mage.Sets/src/mage/cards/c/CourierBat.java @@ -1,28 +1,30 @@ package mage.cards.c; -import java.util.UUID; - import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.YouGainedLifeCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.common.ControllerGainedLifeCount; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; -import mage.constants.ComparisonType; -import mage.constants.SubType; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; import mage.watchers.common.PlayerGainedLifeWatcher; +import java.util.UUID; + /** * @author weirddan455 */ public final class CourierBat extends CardImpl { + private static final Condition condition = new YouGainedLifeCondition(); + public CourierBat(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); @@ -34,13 +36,9 @@ public final class CourierBat extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Courier Bat enters the battlefield, if you gained life this turn, return up to one target creature card from your graveyard to your hand. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()), - new YouGainedLifeCondition(), - "When {this} enters, if you gained life this turn, return up to one target creature card from your graveyard to your hand." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()).withInterveningIf(condition); ability.addTarget(new TargetCardInYourGraveyard(0, 1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); - this.addAbility(ability, new PlayerGainedLifeWatcher()); + this.addAbility(ability.addHint(ControllerGainedLifeCount.getHint()), new PlayerGainedLifeWatcher()); } private CourierBat(final CourierBat card) { diff --git a/Mage.Sets/src/mage/cards/c/CourtStreetDenizen.java b/Mage.Sets/src/mage/cards/c/CourtStreetDenizen.java index d2d133e22f1..14846759d64 100644 --- a/Mage.Sets/src/mage/cards/c/CourtStreetDenizen.java +++ b/Mage.Sets/src/mage/cards/c/CourtStreetDenizen.java @@ -15,8 +15,11 @@ import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -38,7 +41,7 @@ public final class CourtStreetDenizen extends CardImpl { // Whenever another white creature you control enters, tap target creature an opponent controls. Ability ability = new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, new TapTargetEffect(), filter, false); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CrackInTime.java b/Mage.Sets/src/mage/cards/c/CrackInTime.java index 3213303b327..afe8a24b114 100644 --- a/Mage.Sets/src/mage/cards/c/CrackInTime.java +++ b/Mage.Sets/src/mage/cards/c/CrackInTime.java @@ -11,10 +11,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * @author Susucr */ @@ -32,7 +35,7 @@ public final class CrackInTime extends CardImpl { new EntersBattlefieldTriggeredAbility(null), new BeginningOfFirstMainTriggeredAbility(null) ); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/Crackleburr.java b/Mage.Sets/src/mage/cards/c/Crackleburr.java index 861aecc1944..9674500e9a2 100644 --- a/Mage.Sets/src/mage/cards/c/Crackleburr.java +++ b/Mage.Sets/src/mage/cards/c/Crackleburr.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -17,34 +15,34 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; -/** - * - * @author jeffwadsworth +import java.util.UUID; +/** + * @author jeffwadsworth */ public final class Crackleburr extends CardImpl { - - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped red creatures you control"); - private static final FilterControlledCreaturePermanent filter2 = new FilterControlledCreaturePermanent("tapped blue creature you control"); - + + private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("untapped red creatures you control"); + private static final FilterControlledPermanent filter2 = new FilterControlledCreaturePermanent("tapped blue creature you control"); + static { filter.add(new ColorPredicate(ObjectColor.RED)); filter.add(TappedPredicate.UNTAPPED); - + filter2.add(new ColorPredicate(ObjectColor.BLUE)); filter2.add(TappedPredicate.TAPPED); } public Crackleburr(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U/R}{U/R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U/R}{U/R}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(2); @@ -53,17 +51,16 @@ public final class Crackleburr extends CardImpl { // {UR}{UR}, {tap}, Tap two untapped red creatures you control: Crackleburr deals 3 damage to any target. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(3), new ManaCostsImpl<>("{U/R}{U/R}")); ability.addCost(new TapSourceCost()); - ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(2, 2, filter, true))); + ability.addCost(new TapTargetCost(new TargetControlledPermanent(2, filter))); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); - + // {UR}{UR}, {untap}, Untap two tapped blue creatures you control: Return target creature to its owner's hand. Ability ability2 = new SimpleActivatedAbility(new ReturnToHandTargetEffect(), new ManaCostsImpl<>("{U/R}{U/R}")); ability2.addCost(new UntapSourceCost()); - ability2.addCost(new UntapTargetCost(new TargetControlledCreaturePermanent(2, 2, filter2, true))); + ability2.addCost(new UntapTargetCost(new TargetControlledPermanent(2, filter2))); ability2.addTarget(new TargetCreaturePermanent()); this.addAbility(ability2); - } private Crackleburr(final Crackleburr card) { diff --git a/Mage.Sets/src/mage/cards/c/CracklingDoom.java b/Mage.Sets/src/mage/cards/c/CracklingDoom.java index 107510d19af..5b00be3738d 100644 --- a/Mage.Sets/src/mage/cards/c/CracklingDoom.java +++ b/Mage.Sets/src/mage/cards/c/CracklingDoom.java @@ -15,14 +15,13 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.ArrayList; import java.util.List; import java.util.UUID; /** - * * @author LevelX2 */ public final class CracklingDoom extends CardImpl { @@ -49,9 +48,11 @@ public final class CracklingDoom extends CardImpl { class CracklingDoomEffect extends OneShotEffect { static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature with the greatest power among creatures you control"); + static { filter.add(GreatestPowerControlledPredicate.instance); } + public CracklingDoomEffect() { super(Outcome.Sacrifice); this.staticText = "Each opponent sacrifices a creature with the greatest power among creatures that player controls"; @@ -75,7 +76,7 @@ class CracklingDoomEffect extends OneShotEffect { if (controller.hasOpponent(playerId, game)) { Player opponent = game.getPlayer(playerId); if (opponent != null) { - Target target = new TargetControlledCreaturePermanent(filter); + Target target = new TargetPermanent(filter); target.withNotTarget(true); if (opponent.choose(outcome, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/c/CracklingSpellslinger.java b/Mage.Sets/src/mage/cards/c/CracklingSpellslinger.java index 03acec9a9fa..bbd694b8ce0 100644 --- a/Mage.Sets/src/mage/cards/c/CracklingSpellslinger.java +++ b/Mage.Sets/src/mage/cards/c/CracklingSpellslinger.java @@ -3,7 +3,6 @@ package mage.cards.c; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.NextSpellCastHasAbilityEffect; import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.StormAbility; @@ -35,12 +34,9 @@ public final class CracklingSpellslinger extends CardImpl { this.addAbility(FlashAbility.getInstance()); // When Crackling Spellslinger enters the battlefield, if you cast it, the next instant or sorcery spell you cast this turn has storm. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new NextSpellCastHasAbilityEffect(new StormAbility(), filter)), - CastFromEverywhereSourceCondition.instance, - "When {this} enters, if you cast it, " - + "the next instant or sorcery spell you cast this turn has storm" - )); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new NextSpellCastHasAbilityEffect(new StormAbility(), filter) + ).withInterveningIf(CastFromEverywhereSourceCondition.instance)); } private CracklingSpellslinger(final CracklingSpellslinger card) { diff --git a/Mage.Sets/src/mage/cards/c/CradleToGrave.java b/Mage.Sets/src/mage/cards/c/CradleToGrave.java index 891f2598985..54195e27d7e 100644 --- a/Mage.Sets/src/mage/cards/c/CradleToGrave.java +++ b/Mage.Sets/src/mage/cards/c/CradleToGrave.java @@ -11,6 +11,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.permanent.EnteredThisTurnPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -30,7 +31,7 @@ public final class CradleToGrave extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}"); // Destroy target nonblack creature that entered the battlefield this turn. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/c/CraftyPathmage.java b/Mage.Sets/src/mage/cards/c/CraftyPathmage.java index 0da1201b615..85a23d16eea 100644 --- a/Mage.Sets/src/mage/cards/c/CraftyPathmage.java +++ b/Mage.Sets/src/mage/cards/c/CraftyPathmage.java @@ -15,6 +15,7 @@ import mage.constants.ComparisonType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class CraftyPathmage extends CardImpl { // {tap}: Target creature with power 2 or less can't be blocked this turn. Ability ability = new SimpleActivatedAbility(new CantBeBlockedTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CrashLanding.java b/Mage.Sets/src/mage/cards/c/CrashLanding.java index bd667657fd5..c075f6df546 100644 --- a/Mage.Sets/src/mage/cards/c/CrashLanding.java +++ b/Mage.Sets/src/mage/cards/c/CrashLanding.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class CrashLanding extends CardImpl { this.getSpellAbility().addEffect(new LoseAbilityTargetEffect( FlyingAbility.getInstance(), Duration.EndOfTurn)); this.getSpellAbility().addEffect(new DamageTargetEffect(amount).setText("{this} deals damage to that creature equal to the number of Forests you control")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter2)); + this.getSpellAbility().addTarget(new TargetPermanent(filter2)); } private CrashLanding(final CrashLanding card) { diff --git a/Mage.Sets/src/mage/cards/c/CrashingBoars.java b/Mage.Sets/src/mage/cards/c/CrashingBoars.java index 87806c9607b..375dc6f7763 100644 --- a/Mage.Sets/src/mage/cards/c/CrashingBoars.java +++ b/Mage.Sets/src/mage/cards/c/CrashingBoars.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; @@ -11,25 +9,28 @@ import mage.abilities.effects.common.combat.MustBeBlockedByTargetSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author emerald000 */ public final class CrashingBoars extends CardImpl { public CrashingBoars(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); this.subtype.add(SubType.BOAR); this.power = new MageInt(4); this.toughness = new MageInt(4); @@ -49,38 +50,42 @@ public final class CrashingBoars extends CardImpl { } class CrashingBoarsEffect extends OneShotEffect { - - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); + static { filter.add(TappedPredicate.UNTAPPED); } - + CrashingBoarsEffect() { super(Outcome.Benefit); this.staticText = "defending player chooses an untapped creature they control. That creature blocks {this} this turn if able"; } - + private CrashingBoarsEffect(final CrashingBoarsEffect effect) { super(effect); } - + @Override public CrashingBoarsEffect copy() { return new CrashingBoarsEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player defendingPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); - if (defendingPlayer != null) { - Target target = new TargetControlledCreaturePermanent(1, 1, filter, true); - if (target.choose(Outcome.Neutral, defendingPlayer.getId(), source.getSourceId(), source, game)) { - RequirementEffect effect = new MustBeBlockedByTargetSourceEffect(); - effect.setTargetPointer(new FixedTarget(target.getFirstTarget(), game)); - game.addEffect(effect, source); - } - return true; + if (defendingPlayer == null || !game.getBattlefield().contains( + StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE, + defendingPlayer.getId(), source, game, 1 + )) { + return false; } - return false; + Target target = new TargetPermanent(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE); + target.withNotTarget(true); + defendingPlayer.choose(Outcome.Neutral, target, source, game); + RequirementEffect effect = new MustBeBlockedByTargetSourceEffect(); + effect.setTargetPointer(new FixedTarget(target.getFirstTarget(), game)); + game.addEffect(effect, source); + return true; } } diff --git a/Mage.Sets/src/mage/cards/c/CraterElemental.java b/Mage.Sets/src/mage/cards/c/CraterElemental.java index aa0bea29657..b9377dc293d 100644 --- a/Mage.Sets/src/mage/cards/c/CraterElemental.java +++ b/Mage.Sets/src/mage/cards/c/CraterElemental.java @@ -12,7 +12,10 @@ import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.continuous.SetBasePowerSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -38,14 +41,10 @@ public final class CraterElemental extends CardImpl { this.addAbility(ability); // Formidable — {2}{R}: Crater Elemental has base power 8 until end of turn. Activate this ability only if creatures you control have total power 8 or greater. - ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, + this.addAbility(new ActivateIfConditionActivatedAbility( new SetBasePowerSourceEffect(8, Duration.EndOfTurn), - new ManaCostsImpl<>("{2}{R}"), - FormidableCondition.instance - ); - ability.setAbilityWord(AbilityWord.FORMIDABLE); - this.addAbility(ability); + new ManaCostsImpl<>("{2}{R}"), FormidableCondition.instance + ).setAbilityWord(AbilityWord.FORMIDABLE)); } private CraterElemental(final CraterElemental card) { diff --git a/Mage.Sets/src/mage/cards/c/CrawlingSensation.java b/Mage.Sets/src/mage/cards/c/CrawlingSensation.java index b5e844cb915..b6688f2adf3 100644 --- a/Mage.Sets/src/mage/cards/c/CrawlingSensation.java +++ b/Mage.Sets/src/mage/cards/c/CrawlingSensation.java @@ -1,10 +1,9 @@ package mage.cards.c; -import java.util.UUID; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.MillCardsControllerEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -15,8 +14,9 @@ import mage.game.events.GameEvent; import mage.game.events.ZoneChangeGroupEvent; import mage.game.permanent.token.InsectToken; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class CrawlingSensation extends CardImpl { @@ -25,7 +25,7 @@ public final class CrawlingSensation extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); // At the beginning of your upkeep, you may put the top two cards of your library into your graveyard. - this.addAbility(new OnEventTriggeredAbility(GameEvent.EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", new MillCardsControllerEffect(2), true)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new MillCardsControllerEffect(2), true)); // Whenever one or more land cards are put into your graveyard from anywhere for the first time each turn, create a 1/1 green Insect creature token. this.addAbility(new CrawlingSensationTriggeredAbility()); diff --git a/Mage.Sets/src/mage/cards/c/CreepingInn.java b/Mage.Sets/src/mage/cards/c/CreepingInn.java index 22cdd1d9244..106c64a1076 100644 --- a/Mage.Sets/src/mage/cards/c/CreepingInn.java +++ b/Mage.Sets/src/mage/cards/c/CreepingInn.java @@ -13,7 +13,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.ExileZone; import mage.game.Game; @@ -64,7 +63,7 @@ class CreepingInnEffect extends OneShotEffect { super(Outcome.Exile); this.staticText = "you may exile a creature card from your graveyard. " + "If you do, each opponent loses X life and you gain X life, " + - "where X is the number of creature cards exiled with Creeping Inn."; + "where X is the number of creature cards exiled with {this}."; } private CreepingInnEffect(final CreepingInnEffect effect) { diff --git a/Mage.Sets/src/mage/cards/c/CrestedSunmare.java b/Mage.Sets/src/mage/cards/c/CrestedSunmare.java index 69e0f814e7c..8d171ec6652 100644 --- a/Mage.Sets/src/mage/cards/c/CrestedSunmare.java +++ b/Mage.Sets/src/mage/cards/c/CrestedSunmare.java @@ -1,17 +1,20 @@ package mage.cards.c; import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.YouGainedLifeCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.ControllerGainedLifeCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.TargetController; import mage.filter.common.FilterControlledPermanent; import mage.game.permanent.token.CrestedSunmareToken; import mage.watchers.common.PlayerGainedLifeWatcher; @@ -29,6 +32,8 @@ public final class CrestedSunmare extends CardImpl { filter.add(SubType.HORSE.getPredicate()); } + private static final Condition condition = new YouGainedLifeCondition(); + public CrestedSunmare(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); @@ -42,14 +47,9 @@ public final class CrestedSunmare extends CardImpl { ))); // At the beginning of each end step, if you gained life this turn, create a 5/5 white Horse creature token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - TargetController.ANY, new CreateTokenEffect(new CrestedSunmareToken()), - false - ), new YouGainedLifeCondition(), - "At the beginning of each end step, if you gained life this turn, " + - "create a 5/5 white Horse creature token." - ).addHint(ControllerGainedLifeCount.getHint()), new PlayerGainedLifeWatcher()); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.ANY, new CreateTokenEffect(new CrestedSunmareToken()), false + ).withInterveningIf(condition).addHint(ControllerGainedLifeCount.getHint()), new PlayerGainedLifeWatcher()); } private CrestedSunmare(final CrestedSunmare card) { diff --git a/Mage.Sets/src/mage/cards/c/CrestingMosasaurus.java b/Mage.Sets/src/mage/cards/c/CrestingMosasaurus.java index a23c3221b7a..1d771b4e084 100644 --- a/Mage.Sets/src/mage/cards/c/CrestingMosasaurus.java +++ b/Mage.Sets/src/mage/cards/c/CrestingMosasaurus.java @@ -1,22 +1,21 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnToHandFromBattlefieldAllEffect; import mage.abilities.keyword.EmergeAbility; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import java.util.UUID; + /** - * * @author jimga150 */ public final class CrestingMosasaurus extends CardImpl { @@ -29,7 +28,7 @@ public final class CrestingMosasaurus extends CardImpl { public CrestingMosasaurus(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{U}{U}"); - + this.subtype.add(SubType.DINOSAUR); this.power = new MageInt(4); this.toughness = new MageInt(8); @@ -38,10 +37,9 @@ public final class CrestingMosasaurus extends CardImpl { this.addAbility(new EmergeAbility(this, "{6}{U}")); // When Cresting Mosasaurus enters the battlefield, if you cast it, return each non-Dinosaur creature to its owner's hand. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ReturnToHandFromBattlefieldAllEffect(filter), false), - CastFromEverywhereSourceCondition.instance, - "When {this} enters, if you cast it, return each non-Dinosaur creature to its owner's hand.")); + this.addAbility(new EntersBattlefieldTriggeredAbility(new ReturnToHandFromBattlefieldAllEffect(filter) + .setText("return each non-Dinosaur creature to its owner's hand"), false) + .withInterveningIf(CastFromEverywhereSourceCondition.instance)); } private CrestingMosasaurus(final CrestingMosasaurus card) { diff --git a/Mage.Sets/src/mage/cards/c/CroakingCounterpart.java b/Mage.Sets/src/mage/cards/c/CroakingCounterpart.java index a7172e58211..419dc393dde 100644 --- a/Mage.Sets/src/mage/cards/c/CroakingCounterpart.java +++ b/Mage.Sets/src/mage/cards/c/CroakingCounterpart.java @@ -13,6 +13,7 @@ import mage.constants.SubType; import mage.constants.TimingRule; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class CroakingCounterpart extends CardImpl { effect.setOnlySubType(SubType.FROG); effect.setText("Create a token that's a copy of target non-Frog creature, except it's a 1/1 green Frog"); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Flashback {3}{G}{U} this.addAbility(new FlashbackAbility(this, new ManaCostsImpl<>("{3}{G}{U}"))); diff --git a/Mage.Sets/src/mage/cards/c/CropSigil.java b/Mage.Sets/src/mage/cards/c/CropSigil.java index e5e3284ebe9..e96d2e1a4b9 100644 --- a/Mage.Sets/src/mage/cards/c/CropSigil.java +++ b/Mage.Sets/src/mage/cards/c/CropSigil.java @@ -1,25 +1,24 @@ package mage.cards.c; -import java.util.UUID; - import mage.abilities.Ability; -import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; import mage.target.targetpointer.EachTargetPointer; +import java.util.UUID; + /** * @author fireshoes */ @@ -33,17 +32,14 @@ public final class CropSigil extends CardImpl { // Delirium — {2}{G}, Sacrifice Crop Sigil: Return up to one target creature card and up to one target land card from your graveyard to your hand. // Activate this ability only if there are four or more card types among cards in your graveyard. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, + Ability ability = new ActivateIfConditionActivatedAbility( new ReturnFromGraveyardToHandTargetEffect().setTargetPointer(new EachTargetPointer()), - new ManaCostsImpl<>("{2}{G}"), - DeliriumCondition.instance); + new ManaCostsImpl<>("{2}{G}"), DeliriumCondition.instance + ); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetCardInYourGraveyard(0, 1, StaticFilters.FILTER_CARD_CREATURE)); ability.addTarget(new TargetCardInYourGraveyard(0, 1, StaticFilters.FILTER_CARD_LAND)); - ability.setAbilityWord(AbilityWord.DELIRIUM); - ability.addHint(CardTypesInGraveyardCount.YOU.getHint()); - this.addAbility(ability); + this.addAbility(ability.setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); } private CropSigil(final CropSigil card) { diff --git a/Mage.Sets/src/mage/cards/c/CrosissCharm.java b/Mage.Sets/src/mage/cards/c/CrosissCharm.java index 6b1f220a260..96a79f17cc4 100644 --- a/Mage.Sets/src/mage/cards/c/CrosissCharm.java +++ b/Mage.Sets/src/mage/cards/c/CrosissCharm.java @@ -13,6 +13,8 @@ import mage.target.TargetPermanent; import mage.target.common.TargetArtifactPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author LevelX2 @@ -27,7 +29,7 @@ public final class CrosissCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent()); // or destroy target nonblack creature, and it can't be regenerated; Mode mode = new Mode(new DestroyTargetEffect(true)); - mode.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + mode.addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.getSpellAbility().addMode(mode); // or destroy target artifact. mode = new Mode(new DestroyTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/c/CrownOfDoom.java b/Mage.Sets/src/mage/cards/c/CrownOfDoom.java index 3f88e155142..c9ea284b93a 100644 --- a/Mage.Sets/src/mage/cards/c/CrownOfDoom.java +++ b/Mage.Sets/src/mage/cards/c/CrownOfDoom.java @@ -4,16 +4,18 @@ import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.AttacksAllTriggeredAbility; import mage.abilities.condition.common.MyTurnCondition; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.abilities.hint.common.MyTurnHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SetTargetPointer; import mage.filter.FilterPlayer; import mage.filter.StaticFilters; import mage.filter.predicate.ObjectSourcePlayer; @@ -42,22 +44,18 @@ public final class CrownOfDoom extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // Whenever a creature attacks you or a planeswalker you control, it gets +2/+0 until end of turn. - Effect effect = new BoostTargetEffect(2, 0, Duration.EndOfTurn); - effect.setText("it gets +2/+0 until end of turn"); this.addAbility(new AttacksAllTriggeredAbility( - effect, - false, - StaticFilters.FILTER_PERMANENT_CREATURE, - SetTargetPointer.PERMANENT, - true)); + new BoostTargetEffect(2, 0, Duration.EndOfTurn) + .setText("it gets +2/+0 until end of turn"), + false, StaticFilters.FILTER_PERMANENT_CREATURE, + SetTargetPointer.PERMANENT, true + )); // {2}: Target player other than Crown of Doom's owner gains control of it. Activate this ability only during your turn. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new CrownOfDoomEffect(), - new ManaCostsImpl<>("{2}"), - MyTurnCondition.instance); - ability.addTarget(new TargetPlayer(1, 1, false, filter)); + new CrownOfDoomEffect(), new GenericManaCost(2), MyTurnCondition.instance + ); + ability.addTarget(new TargetPlayer(filter)); ability.addHint(MyTurnHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CrownOfGondor.java b/Mage.Sets/src/mage/cards/c/CrownOfGondor.java index d9c7c0cb3f9..01867a0d052 100644 --- a/Mage.Sets/src/mage/cards/c/CrownOfGondor.java +++ b/Mage.Sets/src/mage/cards/c/CrownOfGondor.java @@ -6,7 +6,6 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.MonarchIsNotSetCondition; import mage.abilities.condition.common.MonarchIsSourceControllerCondition; import mage.abilities.costs.CostAdjuster; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.BecomesMonarchSourceEffect; @@ -18,7 +17,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; import mage.util.CardUtil; @@ -42,14 +40,10 @@ public final class CrownOfGondor extends CardImpl { this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(xValue, xValue))); // When a legendary creature you control enters, if there is no monarch, you become the monarch. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldControlledTriggeredAbility( - new BecomesMonarchSourceEffect(), - StaticFilters.FILTER_CREATURE_LEGENDARY - ), - MonarchIsNotSetCondition.instance, - "When a legendary creature you control enters, if there is no monarch, you become the monarch." - ).addHint(MonarchHint.instance)); + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + new BecomesMonarchSourceEffect(), StaticFilters.FILTER_CREATURE_LEGENDARY + ).setTriggerPhrase("When a legendary creature you control enters, ") + .withInterveningIf(MonarchIsNotSetCondition.instance).addHint(MonarchHint.instance)); // Equip {4}. This ability costs {3} less to activate if you're the monarch. EquipAbility equip = new EquipAbility(4, false); diff --git a/Mage.Sets/src/mage/cards/c/CruelCut.java b/Mage.Sets/src/mage/cards/c/CruelCut.java index 075e67261a9..e22e130756b 100644 --- a/Mage.Sets/src/mage/cards/c/CruelCut.java +++ b/Mage.Sets/src/mage/cards/c/CruelCut.java @@ -7,6 +7,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -28,7 +29,7 @@ public final class CruelCut extends CardImpl { // Destroy target creature with power 2 or less. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private CruelCut(final CruelCut card) { diff --git a/Mage.Sets/src/mage/cards/c/CruelDeceiver.java b/Mage.Sets/src/mage/cards/c/CruelDeceiver.java index db1d48f65c4..0e923f3ee06 100644 --- a/Mage.Sets/src/mage/cards/c/CruelDeceiver.java +++ b/Mage.Sets/src/mage/cards/c/CruelDeceiver.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -15,14 +14,12 @@ import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.LookLibraryControllerEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.cards.*; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** * * @author LevelX2 @@ -57,7 +54,7 @@ class CruelDeceiverEffect extends OneShotEffect { CruelDeceiverEffect() { super(Outcome.AddAbility); - this.staticText = "Reveal the top card of your library. If it's a land card, {this} gains \"Whenever Cruel Deceiver deals damage to a creature, destroy that creature\" until end of turn"; + this.staticText = "Reveal the top card of your library. If it's a land card, {this} gains \"Whenever {this} deals damage to a creature, destroy that creature\" until end of turn"; } private CruelDeceiverEffect(final CruelDeceiverEffect effect) { diff --git a/Mage.Sets/src/mage/cards/c/CrumblingAshes.java b/Mage.Sets/src/mage/cards/c/CrumblingAshes.java index eba3857a9a1..907864f6625 100644 --- a/Mage.Sets/src/mage/cards/c/CrumblingAshes.java +++ b/Mage.Sets/src/mage/cards/c/CrumblingAshes.java @@ -11,6 +11,7 @@ import mage.constants.CardType; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -31,7 +32,7 @@ public final class CrumblingAshes extends CardImpl { // At the beginning of your upkeep, destroy target creature with a -1/-1 counter on it. Ability ability = new BeginningOfUpkeepTriggeredAbility(new DestroyTargetEffect()); - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); ability.addTarget(target); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/c/CrushUnderfoot.java b/Mage.Sets/src/mage/cards/c/CrushUnderfoot.java index 1df8a71620c..f802c195bf0 100644 --- a/Mage.Sets/src/mage/cards/c/CrushUnderfoot.java +++ b/Mage.Sets/src/mage/cards/c/CrushUnderfoot.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -9,30 +7,29 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class CrushUnderfoot extends CardImpl { public CrushUnderfoot(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.KINDRED,CardType.INSTANT},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.KINDRED, CardType.INSTANT}, "{1}{R}"); this.subtype.add(SubType.GIANT); - // Choose a Giant creature you control. It deals damage equal to its power to target creature. this.getSpellAbility().addEffect(new CrushUnderfootEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature damage is dealt to"))); - + this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("to deal damage to")); } private CrushUnderfoot(final CrushUnderfoot card) { @@ -47,10 +44,7 @@ public final class CrushUnderfoot extends CardImpl { class CrushUnderfootEffect extends OneShotEffect { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Giant creature you control"); - static { - filter.add(SubType.GIANT.getPredicate()); - } + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(SubType.GIANT, "Giant creature you control"); public CrushUnderfootEffect() { super(Outcome.Damage); @@ -69,22 +63,24 @@ class CrushUnderfootEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - // Choose a Giant creature you control (not targeted, happens during effect resolving ) - Target target = new TargetControlledCreaturePermanent(1,1, filter,false); - if (target.canChoose(controller.getId(), source, game) - && controller.chooseTarget(outcome, target, source, game)) { - Permanent giant = game.getPermanent(target.getFirstTarget()); - if (giant != null) { - game.informPlayers("Crush Underfoot: Chosen Giant is " + giant.getName()); - Permanent targetCreature = game.getPermanent(this.getTargetPointer().getFirst(game, source)); - if (targetCreature != null) { - targetCreature.damage(giant.getPower().getValue(), source.getSourceId(), source, game, false, true); - return true; - } - } - } + if (controller == null) { + return false; } - return false; + // Choose a Giant creature you control (not targeted, happens during effect resolving ) + Target target = new TargetPermanent(filter); + target.withNotTarget(true); + if (!target.canChoose(controller.getId(), source, game) + || !controller.chooseTarget(outcome, target, source, game)) { + return false; + } + Permanent giant = game.getPermanent(target.getFirstTarget()); + if (giant == null) { + return false; + } + game.informPlayers("Crush Underfoot: Chosen Giant is " + giant.getName()); + Permanent targetCreature = game.getPermanent(this.getTargetPointer().getFirst(game, source)); + return targetCreature != null && targetCreature.damage( + giant.getPower().getValue(), source.getSourceId(), source, game, false, true + ) > 0; } } diff --git a/Mage.Sets/src/mage/cards/c/CrushingCanopy.java b/Mage.Sets/src/mage/cards/c/CrushingCanopy.java index e55610d8772..7ca22a17ec1 100644 --- a/Mage.Sets/src/mage/cards/c/CrushingCanopy.java +++ b/Mage.Sets/src/mage/cards/c/CrushingCanopy.java @@ -10,6 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetEnchantmentPermanent; @@ -30,7 +31,7 @@ public final class CrushingCanopy extends CardImpl { // Choose one -- // * Destroy target creature with flying. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); // * Destroy target enchantment. Mode mode = new Mode(new DestroyTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/c/CrushingVines.java b/Mage.Sets/src/mage/cards/c/CrushingVines.java index 4492a1c88cb..43cc576d3d8 100644 --- a/Mage.Sets/src/mage/cards/c/CrushingVines.java +++ b/Mage.Sets/src/mage/cards/c/CrushingVines.java @@ -10,6 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetArtifactPermanent; import mage.target.common.TargetCreaturePermanent; @@ -30,7 +31,7 @@ public final class CrushingVines extends CardImpl { // Choose one - Destroy target creature with flying; or destroy target artifact. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); Mode mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetArtifactPermanent()); diff --git a/Mage.Sets/src/mage/cards/c/CryptFeaster.java b/Mage.Sets/src/mage/cards/c/CryptFeaster.java index df3a1fe5d6e..52f0ca7bf21 100644 --- a/Mage.Sets/src/mage/cards/c/CryptFeaster.java +++ b/Mage.Sets/src/mage/cards/c/CryptFeaster.java @@ -3,7 +3,6 @@ package mage.cards.c; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.ThresholdCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.MenaceAbility; import mage.cards.CardImpl; @@ -31,11 +30,8 @@ public final class CryptFeaster extends CardImpl { this.addAbility(new MenaceAbility()); // Threshold -- Whenever this creature attacks, if there are seven or more cards in your graveyard, this creature gets +2/+0 until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new BoostSourceEffect(2, 0, Duration.EndOfTurn)), - ThresholdCondition.instance, "Whenever this creature attacks, if there are seven " + - "or more cards in your graveyard, this creature gets +2/+0 until end of turn." - ).setAbilityWord(AbilityWord.THRESHOLD)); + this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(2, 0, Duration.EndOfTurn)) + .withInterveningIf(ThresholdCondition.instance).setAbilityWord(AbilityWord.THRESHOLD)); } private CryptFeaster(final CryptFeaster card) { diff --git a/Mage.Sets/src/mage/cards/c/Cryptex.java b/Mage.Sets/src/mage/cards/c/Cryptex.java index 0972dbec9cd..d3266951d55 100644 --- a/Mage.Sets/src/mage/cards/c/Cryptex.java +++ b/Mage.Sets/src/mage/cards/c/Cryptex.java @@ -4,7 +4,7 @@ import mage.abilities.Ability; import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.costs.common.CollectEvidenceCost; import mage.abilities.costs.common.SacrificeSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.keyword.SurveilEffect; @@ -31,7 +31,7 @@ public final class Cryptex extends CardImpl { this.addAbility(ability); // Sacrifice Cryptex: Surveil 3, then draw three cards. Activate only if Cryptex has five or more unlock counters on it. - Ability sacAbility = new ConditionalActivatedAbility(new SurveilEffect(3, false), new SacrificeSourceCost(), + Ability sacAbility = new ActivateIfConditionActivatedAbility(new SurveilEffect(3, false), new SacrificeSourceCost(), new SourceHasCounterCondition(CounterType.UNLOCK, 5)); sacAbility.addEffect(new DrawCardSourceControllerEffect(3).concatBy(", then")); this.addAbility(sacAbility); diff --git a/Mage.Sets/src/mage/cards/c/CrypticCaves.java b/Mage.Sets/src/mage/cards/c/CrypticCaves.java index 477b0128c45..6bb1fbb463f 100644 --- a/Mage.Sets/src/mage/cards/c/CrypticCaves.java +++ b/Mage.Sets/src/mage/cards/c/CrypticCaves.java @@ -8,13 +8,12 @@ import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.hint.common.LandsYouControlHint; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; -import mage.constants.Zone; -import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledLandPermanent; import java.util.UUID; @@ -24,10 +23,9 @@ import java.util.UUID; */ public final class CrypticCaves extends CardImpl { - private static final FilterPermanent filter - = new FilterControlledLandPermanent("you control five or more lands"); - private static final Condition condition - = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 4); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledLandPermanent("you control five or more lands"), ComparisonType.MORE_THAN, 4 + ); public CrypticCaves(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); @@ -37,12 +35,11 @@ public final class CrypticCaves extends CardImpl { // {1}, {T}, Sacrifice Cryptic Caves: Draw a card. Activate this ability only if you control five or more lands. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), - new GenericManaCost(1), condition + new DrawCardSourceControllerEffect(1), new GenericManaCost(1), condition ); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); - this.addAbility(ability); + this.addAbility(ability.addHint(LandsYouControlHint.instance)); } private CrypticCaves(final CrypticCaves card) { diff --git a/Mage.Sets/src/mage/cards/c/CryptolithFragment.java b/Mage.Sets/src/mage/cards/c/CryptolithFragment.java index 5203e1feac5..ec264beae69 100644 --- a/Mage.Sets/src/mage/cards/c/CryptolithFragment.java +++ b/Mage.Sets/src/mage/cards/c/CryptolithFragment.java @@ -1,14 +1,14 @@ package mage.cards.c; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.LifeCompareCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.LoseLifeAllPlayersEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.TransformAbility; import mage.abilities.mana.AnyColorManaAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -22,6 +22,8 @@ import java.util.UUID; */ public final class CryptolithFragment extends CardImpl { + private static final Condition condition = new LifeCompareCondition(TargetController.EACH_PLAYER, ComparisonType.OR_LESS, 10); + public CryptolithFragment(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); @@ -37,10 +39,7 @@ public final class CryptolithFragment extends CardImpl { // At the beginning of your upkeep, if each player has 10 or less life, transform Cryptolith Fragment. this.addAbility(new TransformAbility()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()), - new LifeCompareCondition(TargetController.EACH_PLAYER, ComparisonType.OR_LESS, 10), - "At the beginning of your upkeep, if each player has 10 or less life, transform {this}.")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()).withInterveningIf(condition)); } private CryptolithFragment(final CryptolithFragment card) { diff --git a/Mage.Sets/src/mage/cards/c/Cryptoplasm.java b/Mage.Sets/src/mage/cards/c/Cryptoplasm.java index cf026f39adf..992c3065349 100644 --- a/Mage.Sets/src/mage/cards/c/Cryptoplasm.java +++ b/Mage.Sets/src/mage/cards/c/Cryptoplasm.java @@ -15,6 +15,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.util.functions.CopyApplier; @@ -40,7 +41,7 @@ public final class Cryptoplasm extends CardImpl { // At the beginning of your upkeep, you may have Cryptoplasm become a copy of another target creature. If you do, Cryptoplasm gains this ability. Ability ability = new BeginningOfUpkeepTriggeredAbility(new CryptoplasmEffect(), true); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CultConscript.java b/Mage.Sets/src/mage/cards/c/CultConscript.java index 4c8f1f78044..35efa4a9d12 100644 --- a/Mage.Sets/src/mage/cards/c/CultConscript.java +++ b/Mage.Sets/src/mage/cards/c/CultConscript.java @@ -7,7 +7,7 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; import mage.constants.SubType; import mage.cards.CardImpl; @@ -39,7 +39,7 @@ public final class CultConscript extends CardImpl { this.addAbility(new EntersBattlefieldTappedAbility()); // {1}{B}: Return Cult Conscript from your graveyard to the battlefield. Activate only if a non-Skeleton creature died under your control this turn. - this.addAbility(new ConditionalActivatedAbility( + this.addAbility(new ActivateIfConditionActivatedAbility( Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(false, false), new ManaCostsImpl<>("{1}{B}"), diff --git a/Mage.Sets/src/mage/cards/c/CultivatorOfBlades.java b/Mage.Sets/src/mage/cards/c/CultivatorOfBlades.java index c5631434c44..1211fff8723 100644 --- a/Mage.Sets/src/mage/cards/c/CultivatorOfBlades.java +++ b/Mage.Sets/src/mage/cards/c/CultivatorOfBlades.java @@ -32,7 +32,7 @@ public final class CultivatorOfBlades extends CardImpl { // Whenever Cultivator of Blades attacks, you may have other attacking creatures get +X/+X until end of turn, where X is Cultivator of Blades's power. this.addAbility(new AttacksTriggeredAbility(new BoostControlledEffect(SourcePermanentPowerValue.NOT_NEGATIVE, SourcePermanentPowerValue.NOT_NEGATIVE, Duration.EndOfTurn, StaticFilters.FILTER_ATTACKING_CREATURES, true), - true, "Whenever Cultivator of Blades attacks, you may have other attacking creatures get +X/+X until end of turn, where X is Cultivator of Blades's power.")); + true, "Whenever {this} attacks, you may have other attacking creatures get +X/+X until end of turn, where X is {this}'s power.")); } private CultivatorOfBlades(final CultivatorOfBlades card) { diff --git a/Mage.Sets/src/mage/cards/c/CulturalExchange.java b/Mage.Sets/src/mage/cards/c/CulturalExchange.java index 8e6820e0200..b876d746db0 100644 --- a/Mage.Sets/src/mage/cards/c/CulturalExchange.java +++ b/Mage.Sets/src/mage/cards/c/CulturalExchange.java @@ -14,8 +14,8 @@ import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.TargetPlayer; -import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; import java.util.UUID; @@ -79,10 +79,10 @@ class CulturalExchangeEffect extends OneShotEffect { if (creaturesToSwitch == 0) { return true; } - TargetCreaturePermanent target1 = new TargetCreaturePermanent(0, creaturesToSwitch, filter1, true); + TargetPermanent target1 = new TargetPermanent(0, creaturesToSwitch, filter1, true); if (target1.choose(Outcome.Benefit, controller.getId(), source.getSourceId(), source, game)) { int otherToSwitch = target1.getTargets().size(); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(otherToSwitch, otherToSwitch, filter2, true); + TargetPermanent target2 = new TargetPermanent(otherToSwitch, otherToSwitch, filter2, true); if (target2.choose(Outcome.Benefit, controller.getId(), source.getSourceId(), source, game)) { for (UUID creatureId : target1.getTargets()) { Permanent creature = game.getPermanent(creatureId); diff --git a/Mage.Sets/src/mage/cards/c/CunningAdvisor.java b/Mage.Sets/src/mage/cards/c/CunningAdvisor.java index 0ef8c384154..5ec352170ea 100644 --- a/Mage.Sets/src/mage/cards/c/CunningAdvisor.java +++ b/Mage.Sets/src/mage/cards/c/CunningAdvisor.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -12,25 +10,27 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class CunningAdvisor extends CardImpl { public CunningAdvisor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ADVISOR); this.power = new MageInt(1); this.toughness = new MageInt(1); // {tap}: Target opponent discards a card. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new DiscardTargetEffect(1), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DiscardTargetEffect(1), new TapSourceCost(), + MyTurnBeforeAttackersDeclaredCondition.instance + ); ability.addTarget(new TargetOpponent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CunningGeysermage.java b/Mage.Sets/src/mage/cards/c/CunningGeysermage.java index d3591788dfb..f787e9e7f9b 100644 --- a/Mage.Sets/src/mage/cards/c/CunningGeysermage.java +++ b/Mage.Sets/src/mage/cards/c/CunningGeysermage.java @@ -4,16 +4,13 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.StaticFilters; import mage.target.TargetPermanent; import java.util.UUID; @@ -23,12 +20,6 @@ import java.util.UUID; */ public final class CunningGeysermage extends CardImpl { - private static final FilterPermanent filter = new FilterCreaturePermanent("another creature"); - - static { - filter.add(AnotherPredicate.instance); - } - public CunningGeysermage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); @@ -41,12 +32,9 @@ public final class CunningGeysermage extends CardImpl { this.addAbility(new KickerAbility("{2}{U}")); // When Cunning Geysermage enters the battlefield, if it was kicked, return up to one other target creature to its owner's hand. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()), - KickedCondition.ONCE, "When {this} enters, " + - "if it was kicked, return up to one other target creature to its owner's hand." - ); - ability.addTarget(new TargetPermanent(0, 1, filter, false)); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect() + .setText("return up to one other target creature to its owner's hand")).withInterveningIf(KickedCondition.ONCE); + ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_ANOTHER_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CunningLethemancer.java b/Mage.Sets/src/mage/cards/c/CunningLethemancer.java index 8bf48e56af8..6db2bc16b5a 100644 --- a/Mage.Sets/src/mage/cards/c/CunningLethemancer.java +++ b/Mage.Sets/src/mage/cards/c/CunningLethemancer.java @@ -1,31 +1,29 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.events.GameEvent.EventType; + +import java.util.UUID; /** - * * @author North */ public final class CunningLethemancer extends CardImpl { public CunningLethemancer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(2); this.toughness = new MageInt(2); - this.addAbility(new OnEventTriggeredAbility(EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", new DiscardEachPlayerEffect())); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DiscardEachPlayerEffect())); } private CunningLethemancer(final CunningLethemancer card) { diff --git a/Mage.Sets/src/mage/cards/c/Curfew.java b/Mage.Sets/src/mage/cards/c/Curfew.java index bfcb760aa8c..903e3720e0a 100644 --- a/Mage.Sets/src/mage/cards/c/Curfew.java +++ b/Mage.Sets/src/mage/cards/c/Curfew.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -13,10 +11,12 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author maxlebedev */ public final class Curfew extends CardImpl { @@ -51,16 +51,17 @@ class CurfewEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - game.informPlayers("Each player returns a creature they control to its owner's hand"); for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); - if (player != null && game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game) > 0) { - TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(1, 1, StaticFilters.FILTER_CONTROLLED_CREATURE, true); - player.choose(Outcome.ReturnToHand, target, source, game); - Permanent permanent = game.getPermanent(target.getFirstTarget()); - if (permanent != null) { - player.moveCards(permanent, Zone.HAND, source, game); - } + if (player == null || game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game) <= 0) { + continue; + } + TargetPermanent target = new TargetControlledCreaturePermanent(); + target.withNotTarget(true); + player.choose(Outcome.ReturnToHand, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + player.moveCards(permanent, Zone.HAND, source, game); } } return true; diff --git a/Mage.Sets/src/mage/cards/c/CuriousHomunculus.java b/Mage.Sets/src/mage/cards/c/CuriousHomunculus.java index 7e04a100d66..b78941496aa 100644 --- a/Mage.Sets/src/mage/cards/c/CuriousHomunculus.java +++ b/Mage.Sets/src/mage/cards/c/CuriousHomunculus.java @@ -1,31 +1,34 @@ - package mage.cards.c; -import java.util.UUID; - import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CardsInControllerGraveyardCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; import mage.abilities.keyword.TransformAbility; import mage.abilities.mana.ConditionalColorlessManaAbility; import mage.abilities.mana.builder.common.InstantOrSorcerySpellManaBuilder; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.StaticFilters; import mage.filter.common.FilterInstantOrSorceryCard; -import mage.game.Game; -import mage.players.Player; + +import java.util.UUID; /** * @author fireshoes */ public final class CuriousHomunculus extends CardImpl { + private static final Condition condition = new CardsInControllerGraveyardCondition(3, new FilterInstantOrSorceryCard("instant and/or sorcery cards")); + private static final Hint hint = new ValueHint("Instant and sorcery cards in your graveyard", new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY)); + public CuriousHomunculus(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.subtype.add(SubType.HOMUNCULUS); @@ -39,10 +42,7 @@ public final class CuriousHomunculus extends CardImpl { // At the beginning of your upkeep, if there are three or more instant and/or sorcery cards in your graveyard, transform Curious Homunculus. this.addAbility(new TransformAbility()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()), - new InstantOrSorceryCardsInControllerGraveyardCondition(3), - "At the beginning of your upkeep, if there are three or more instant and/or sorcery cards in your graveyard, transform {this}")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()).withInterveningIf(condition).addHint(hint)); } private CuriousHomunculus(final CuriousHomunculus card) { @@ -54,21 +54,3 @@ public final class CuriousHomunculus extends CardImpl { return new CuriousHomunculus(this); } } - -class InstantOrSorceryCardsInControllerGraveyardCondition implements Condition { - - private int value; - - public InstantOrSorceryCardsInControllerGraveyardCondition(int value) { - this.value = value; - } - - @Override - public boolean apply(Game game, Ability source) { - Player p = game.getPlayer(source.getControllerId()); - if (p != null && p.getGraveyard().count(new FilterInstantOrSorceryCard(), game) >= value) { - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/c/CuriousObsession.java b/Mage.Sets/src/mage/cards/c/CuriousObsession.java index 87ecb417fc4..beff959e018 100644 --- a/Mage.Sets/src/mage/cards/c/CuriousObsession.java +++ b/Mage.Sets/src/mage/cards/c/CuriousObsession.java @@ -1,14 +1,11 @@ package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.SacrificeSourceEffect; @@ -16,23 +13,26 @@ import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.hint.common.RaidHint; import mage.abilities.keyword.EnchantAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AttachmentType; import mage.constants.CardType; -import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.SubType; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.watchers.common.PlayerAttackedWatcher; +import java.util.UUID; + /** - * * @author awjackson */ public final class CuriousObsession extends CardImpl { + private static final Condition condition = new InvertCondition(RaidCondition.instance, "you didn't attack with a creature this turn"); + public CuriousObsession(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); @@ -42,25 +42,20 @@ public final class CuriousObsession extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget)); // Enchanted creature gets +1/+1 and has "Whenever this creature deals combat damage to a player, you may draw a card. - ability = new SimpleStaticAbility(new BoostEnchantedEffect(1, 1, Duration.WhileOnBattlefield)); - Ability gainedAbility = new DealsCombatDamageToAPlayerTriggeredAbility(new DrawCardSourceControllerEffect(1), true); - Effect effect = new GainAbilityAttachedEffect(gainedAbility, AttachmentType.AURA); - effect.setText("and has \"Whenever this creature deals combat damage to a player, you may draw a card.\""); - ability.addEffect(effect); + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(1, 1)); + ability.addEffect(new GainAbilityAttachedEffect( + new DealsCombatDamageToAPlayerTriggeredAbility( + new DrawCardSourceControllerEffect(1), true + ), AttachmentType.AURA + ).setText("and has \"Whenever this creature deals combat damage to a player, you may draw a card.\"")); this.addAbility(ability); // At the beginning of your end step, if you didn't attack with a creature this turn sacrifice Curious Obsession. - ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility(new SacrificeSourceEffect()), - new InvertCondition(RaidCondition.instance), - "At the beginning of your end step, if you didn't attack with a creature this turn, sacrifice {this}." - ); - ability.addHint(RaidHint.instance); - this.addAbility(ability, new PlayerAttackedWatcher()); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new SacrificeSourceEffect()) + .withInterveningIf(condition).addHint(RaidHint.instance), new PlayerAttackedWatcher()); } private CuriousObsession(final CuriousObsession card) { diff --git a/Mage.Sets/src/mage/cards/c/CurseOfInertia.java b/Mage.Sets/src/mage/cards/c/CurseOfInertia.java index ee6c5120633..c31c6e391dc 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfInertia.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfInertia.java @@ -13,11 +13,11 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; import mage.target.TargetPlayer; +import mage.target.targetadjustment.DefineByTriggerTargetAdjuster; import java.util.UUID; @@ -56,6 +56,7 @@ class CurseOfInertiaTriggeredAbility extends TriggeredAbilityImpl { public CurseOfInertiaTriggeredAbility() { super(Zone.BATTLEFIELD, new CurseOfInertiaTapOrUntapTargetEffect(), false); + setTargetAdjuster(DefineByTriggerTargetAdjuster.instance); } private CurseOfInertiaTriggeredAbility(final CurseOfInertiaTriggeredAbility ability) { @@ -75,7 +76,8 @@ class CurseOfInertiaTriggeredAbility extends TriggeredAbilityImpl { && game.getCombat().getPlayerDefenders(game, false).contains(enchantment.getAttachedTo())) { TargetPermanent target = new TargetPermanent(); target.setTargetController(game.getCombat().getAttackingPlayerId()); - addTarget(target); + this.getTargets().clear(); + this.addTarget(target); return true; } return false; diff --git a/Mage.Sets/src/mage/cards/c/CurseOfMisfortunes.java b/Mage.Sets/src/mage/cards/c/CurseOfMisfortunes.java index a47226e30e8..253a069fb3f 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfMisfortunes.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfMisfortunes.java @@ -1,11 +1,10 @@ - package mage.cards.c; import mage.abilities.Ability; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.keyword.EnchantAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -17,7 +16,6 @@ import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.NamePredicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPlayer; @@ -27,16 +25,14 @@ import mage.target.targetpointer.FixedTarget; import java.util.UUID; /** - * * @author BetaSteward */ public final class CurseOfMisfortunes extends CardImpl { public CurseOfMisfortunes(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{4}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{B}"); this.subtype.add(SubType.AURA, SubType.CURSE); - // Enchant player TargetPlayer auraTarget = new TargetPlayer(); this.getSpellAbility().addTarget(auraTarget); @@ -44,7 +40,7 @@ public final class CurseOfMisfortunes extends CardImpl { this.addAbility(new EnchantAbility(auraTarget)); // At the beginning of your upkeep, you may search your library for a Curse card that doesn't have the same name as a Curse attached to enchanted player, put it onto the battlefield attached to that player, then shuffle your library. - this.addAbility(new OnEventTriggeredAbility(GameEvent.EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", new CurseOfMisfortunesEffect(), true)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CurseOfMisfortunesEffect(), true)); } private CurseOfMisfortunes(final CurseOfMisfortunes card) { @@ -79,7 +75,7 @@ class CurseOfMisfortunesEffect extends OneShotEffect { FilterCard filter = new FilterCard("Curse card that doesn't have the same name as a Curse attached to enchanted player"); filter.add(SubType.CURSE.getPredicate()); // get the names of attached Curses - for (UUID attachmentId: targetPlayer.getAttachments()) { + for (UUID attachmentId : targetPlayer.getAttachments()) { Permanent attachment = game.getPermanent(attachmentId); if (attachment != null && attachment.hasSubtype(SubType.CURSE, game)) { filter.add(Predicates.not(new NamePredicate(attachment.getName()))); diff --git a/Mage.Sets/src/mage/cards/c/CurseOfTheCabal.java b/Mage.Sets/src/mage/cards/c/CurseOfTheCabal.java index 179dd87f298..cb5eefc9879 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfTheCabal.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfTheCabal.java @@ -1,16 +1,15 @@ package mage.cards.c; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.common.SuspendedCondition; import mage.abilities.costs.Cost; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.SuspendAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -44,8 +43,9 @@ public final class CurseOfTheCabal extends CardImpl { this.addAbility(new SuspendAbility(2, new ManaCostsImpl<>("{2}{B}{B}"), this)); // At the beginning of each player's upkeep, if Curse of the Cabal is suspended, that player may sacrifice a permanent. If they do, put two time counters on Curse of the Cabal. - this.addAbility(new CurseOfTheCabalInterveningIfTriggeredAbility()); - + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + Zone.EXILED, TargetController.EACH_PLAYER, new CurseOfTheCabalTriggeredAbilityConditionalDelay(), false + ).withInterveningIf(SuspendedCondition.instance)); } private CurseOfTheCabal(final CurseOfTheCabal card) { @@ -62,7 +62,7 @@ class CurseOfTheCabalSacrificeEffect extends OneShotEffect { CurseOfTheCabalSacrificeEffect() { super(Outcome.Sacrifice); - this.staticText = "Target player sacrifices half the permanents they control, rounded down."; + this.staticText = "Target player sacrifices half the permanents they control of their choice, rounded down."; } private CurseOfTheCabalSacrificeEffect(final CurseOfTheCabalSacrificeEffect effect) { @@ -100,36 +100,11 @@ class CurseOfTheCabalSacrificeEffect extends OneShotEffect { } } -class CurseOfTheCabalInterveningIfTriggeredAbility extends ConditionalInterveningIfTriggeredAbility { - - public CurseOfTheCabalInterveningIfTriggeredAbility() { - super(new BeginningOfUpkeepTriggeredAbility( - Zone.EXILED, TargetController.ANY, new CurseOfTheCabalTriggeredAbilityConditionalDelay(), - false - ), - SuspendedCondition.instance, - "At the beginning of each player's upkeep, if {this} is suspended, " - + "that player may sacrifice a permanent. If the player does, " - + "put two time counters on {this}." - ); - // controller has to sac a permanent - // counters aren't placed - } - - private CurseOfTheCabalInterveningIfTriggeredAbility(final CurseOfTheCabalInterveningIfTriggeredAbility effect) { - super(effect); - } - - @Override - public CurseOfTheCabalInterveningIfTriggeredAbility copy() { - return new CurseOfTheCabalInterveningIfTriggeredAbility(this); - } -} - class CurseOfTheCabalTriggeredAbilityConditionalDelay extends AddCountersSourceEffect { public CurseOfTheCabalTriggeredAbilityConditionalDelay() { super(CounterType.TIME.createInstance(), StaticValue.get(2), false, true); + staticText = "that player may sacrifice a permanent of their choice. If the player does, put two time counters on this card"; } @Override diff --git a/Mage.Sets/src/mage/cards/c/CurseOfTheWerefox.java b/Mage.Sets/src/mage/cards/c/CurseOfTheWerefox.java index a9e2e82d4ed..4a6deeea660 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfTheWerefox.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfTheWerefox.java @@ -3,8 +3,6 @@ package mage.cards.c; import mage.abilities.Ability; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateRoleAttachedTargetEffect; -import mage.abilities.effects.common.FightTargetsEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -13,11 +11,9 @@ import mage.constants.RoleType; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; -import mage.target.common.TargetOpponentsCreaturePermanent; import mage.target.targetpointer.FixedTarget; -import mage.util.GameLog; import java.util.UUID; @@ -64,24 +60,15 @@ class CurseOfTheWerefoxEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent target = game.getPermanent(source.getFirstTarget()); - if (target == null) { - return false; - } - - boolean didCreate = - new CreateRoleAttachedTargetEffect(RoleType.MONSTER) - .setTargetPointer(new FixedTarget(target, game)) - .apply(game, source); - if (!didCreate) { + if (target == null || RoleType.MONSTER.createToken(target, game, source).getLastAddedTokenIds().isEmpty()) { return false; } ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( - new CurseOfTheWerefoxFightEffect(), false, - "that creature fights up to one target creature you don't control" + new CurseOfTheWerefoxFightEffect().setTargetPointer(new FixedTarget(target.getId(), game)), + false, "that creature fights up to one target creature you don't control" ); - ability.getEffects().setTargetPointer(new FixedTarget(target.getId(), game)); - ability.addTarget(new TargetCreaturePermanent(0, 1, StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL, false)); + ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); game.fireReflexiveTriggeredAbility(ability, source); return true; } diff --git a/Mage.Sets/src/mage/cards/c/CurtainOfLight.java b/Mage.Sets/src/mage/cards/c/CurtainOfLight.java index 16632d142da..934755dad62 100644 --- a/Mage.Sets/src/mage/cards/c/CurtainOfLight.java +++ b/Mage.Sets/src/mage/cards/c/CurtainOfLight.java @@ -12,6 +12,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.AttackingPredicate; import mage.filter.predicate.permanent.BlockedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -39,7 +40,7 @@ public final class CurtainOfLight extends CardImpl { // Target unblocked attacking creature becomes blocked. this.getSpellAbility().addEffect(new BecomeBlockedTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); diff --git a/Mage.Sets/src/mage/cards/c/CurtainsCall.java b/Mage.Sets/src/mage/cards/c/CurtainsCall.java index 8b9c310c7b4..92beebc118e 100644 --- a/Mage.Sets/src/mage/cards/c/CurtainsCall.java +++ b/Mage.Sets/src/mage/cards/c/CurtainsCall.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.UndauntedAbility; import mage.cards.CardImpl; @@ -9,8 +7,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class CurtainsCall extends CardImpl { @@ -20,6 +19,7 @@ public final class CurtainsCall extends CardImpl { // Undaunted this.addAbility(new UndauntedAbility()); + // Destroy two target creatures. this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent(2)); diff --git a/Mage.Sets/src/mage/cards/c/CutRibbons.java b/Mage.Sets/src/mage/cards/c/CutRibbons.java index 46f1fa21685..b2e78bcde6d 100644 --- a/Mage.Sets/src/mage/cards/c/CutRibbons.java +++ b/Mage.Sets/src/mage/cards/c/CutRibbons.java @@ -1,6 +1,5 @@ package mage.cards.c; -import java.util.UUID; import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.LoseLifeOpponentsEffect; @@ -11,6 +10,8 @@ import mage.constants.CardType; import mage.constants.SpellAbilityType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * @author Stravant */ @@ -22,7 +23,7 @@ public final class CutRibbons extends SplitCard { // Cut // Cut deals 4 damage to target creature. getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); - getLeftHalfCard().getSpellAbility().addEffect(new DamageTargetEffect(4).setText("Cut deals 4 damage to target creature")); + getLeftHalfCard().getSpellAbility().addEffect(new DamageTargetEffect(4).setText("{this} deals 4 damage to target creature")); // to // Ribbons diff --git a/Mage.Sets/src/mage/cards/c/Cyclone.java b/Mage.Sets/src/mage/cards/c/Cyclone.java index 7f21d7eea62..09d716b667d 100644 --- a/Mage.Sets/src/mage/cards/c/Cyclone.java +++ b/Mage.Sets/src/mage/cards/c/Cyclone.java @@ -1,14 +1,13 @@ package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageEverythingEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -18,6 +17,8 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** @@ -48,7 +49,7 @@ class CycloneEffect extends OneShotEffect { CycloneEffect() { super(Outcome.Damage); - this.staticText = "Pay Green Mana for each counter to damage everything or sacrifice Cyclone."; + this.staticText = ", then sacrifice {this} unless you pay {G} for each wind counter on it. If you pay, {this} deals damage equal to the number of wind counters on it to each creature and each player"; } private CycloneEffect(final CycloneEffect effect) { diff --git a/Mage.Sets/src/mage/cards/c/CycloneSummoner.java b/Mage.Sets/src/mage/cards/c/CycloneSummoner.java index a04b95d6d78..e1875bcc528 100644 --- a/Mage.Sets/src/mage/cards/c/CycloneSummoner.java +++ b/Mage.Sets/src/mage/cards/c/CycloneSummoner.java @@ -3,7 +3,6 @@ package mage.cards.c; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromHandSourcePermanentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnToHandFromBattlefieldAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -37,13 +36,10 @@ public final class CycloneSummoner extends CardImpl { this.toughness = new MageInt(7); // When Cyclone Summoner enters the battlefield, if you cast it from your hand, return all permanents to their owners' hands except for Giants, Wizards, and lands. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility( - new ReturnToHandFromBattlefieldAllEffect(filter), false - ), CastFromHandSourcePermanentCondition.instance, "When {this} enters, " + - "if you cast it from your hand, return all permanents to their owners' hands " + - "except for Giants, Wizards, and lands." - ), new CastFromHandWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new ReturnToHandFromBattlefieldAllEffect(filter) + .setText("return all permanents to their owners' hands except for Giants, Wizards, and lands") + ).withInterveningIf(CastFromHandSourcePermanentCondition.instance), new CastFromHandWatcher()); } private CycloneSummoner(final CycloneSummoner card) { diff --git a/Mage.Sets/src/mage/cards/c/CyclopeanTomb.java b/Mage.Sets/src/mage/cards/c/CyclopeanTomb.java index 8e6b3f92fad..ed13a036276 100644 --- a/Mage.Sets/src/mage/cards/c/CyclopeanTomb.java +++ b/Mage.Sets/src/mage/cards/c/CyclopeanTomb.java @@ -9,7 +9,7 @@ import mage.abilities.common.delayed.AtTheBeginOfYourNextUpkeepDelayedTriggeredA import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BecomesBasicLandTargetEffect; @@ -38,7 +38,7 @@ import java.util.*; */ public final class CyclopeanTomb extends CardImpl { - private static final FilterPermanent filter = new FilterLandPermanent(); + private static final FilterPermanent filter = new FilterLandPermanent("non-Swamp land"); static { filter.add(Predicates.not(SubType.SWAMP.getPredicate())); @@ -48,7 +48,10 @@ public final class CyclopeanTomb extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // {2}, {tap}: Put a mire counter on target non-Swamp land. That land is a Swamp for as long as it has a mire counter on it. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.MIRE.createInstance()), new GenericManaCost(2), new IsStepCondition(PhaseStep.UPKEEP), "{2}, {T}: Put a mire counter on target non-Swamp land. That land is a Swamp for as long as it has a mire counter on it. Activate only during your upkeep."); + Ability ability = new ActivateIfConditionActivatedAbility( + new AddCountersTargetEffect(CounterType.MIRE.createInstance()), + new GenericManaCost(2), IsStepCondition.getMyUpkeep() + ); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetPermanent(filter)); ability.addEffect(new BecomeSwampEffect()); diff --git a/Mage.Sets/src/mage/cards/c/CyclopsGladiator.java b/Mage.Sets/src/mage/cards/c/CyclopsGladiator.java index d9ffd2ac569..c2c3f3e1b74 100644 --- a/Mage.Sets/src/mage/cards/c/CyclopsGladiator.java +++ b/Mage.Sets/src/mage/cards/c/CyclopsGladiator.java @@ -2,7 +2,6 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; @@ -10,14 +9,15 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.constants.SubType; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; + +import java.util.UUID; /** * @@ -26,7 +26,7 @@ import mage.target.common.TargetCreaturePermanent; public final class CyclopsGladiator extends CardImpl { public CyclopsGladiator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}{R}"); this.subtype.add(SubType.CYCLOPS); this.subtype.add(SubType.WARRIOR); @@ -36,6 +36,8 @@ public final class CyclopsGladiator extends CardImpl { // Whenever Cyclops Gladiator attacks, you may have it deal damage equal to its power to target creature defending player controls. // If you do, that creature deals damage equal to its power to Cyclops Gladiator. Ability ability = new AttacksTriggeredAbility(new CyclopsGladiatorEffect(), true); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE)); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); this.addAbility(ability); } @@ -63,23 +65,12 @@ class CyclopsGladiatorEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - UUID defenderId = game.getCombat().getDefenderId(source.getSourceId()); - if (defenderId != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); - filter.add(new ControllerIdPredicate(defenderId)); - TargetCreaturePermanent target = new TargetCreaturePermanent(filter); - Player player = game.getPlayer(source.getControllerId()); - if (target.canChoose(source.getControllerId(), source, game)) { - if (player != null && player.chooseTarget(Outcome.Detriment, target, source, game)) { - Permanent permanent = game.getPermanent(target.getFirstTarget()); - Permanent cyclops = game.getPermanent(source.getSourceId()); - if (permanent != null && cyclops != null) { - permanent.damage(cyclops.getPower().getValue(), cyclops.getId(), source, game, false, true); - cyclops.damage(permanent.getPower().getValue(), permanent.getId(), source, game, false, true); - return true; - } - } - } + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + Permanent cyclops = game.getPermanent(source.getSourceId()); + if (permanent != null && cyclops != null) { + permanent.damage(cyclops.getPower().getValue(), cyclops.getId(), source, game, false, true); + cyclops.damage(permanent.getPower().getValue(), permanent.getId(), source, game, false, true); + return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/c/CytoplastManipulator.java b/Mage.Sets/src/mage/cards/c/CytoplastManipulator.java index 2c91d858969..2a1ad209c57 100644 --- a/Mage.Sets/src/mage/cards/c/CytoplastManipulator.java +++ b/Mage.Sets/src/mage/cards/c/CytoplastManipulator.java @@ -18,8 +18,11 @@ import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_CREATURE_P1P1; + /** * * @author JotaPeRL @@ -44,7 +47,7 @@ public final class CytoplastManipulator extends CardImpl { "gain control of target creature with a +1/+1 counter on it for as long as {this} remains on the battlefield"); Ability ability = new SimpleActivatedAbility(effect, new ManaCostsImpl<>("{U}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_P1P1)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_P1P1)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/Cytoshape.java b/Mage.Sets/src/mage/cards/c/Cytoshape.java index bbbed0cfc4d..fb6807cd653 100644 --- a/Mage.Sets/src/mage/cards/c/Cytoshape.java +++ b/Mage.Sets/src/mage/cards/c/Cytoshape.java @@ -1,4 +1,3 @@ - package mage.cards.c; import mage.abilities.Ability; @@ -14,26 +13,22 @@ import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import mage.util.functions.EmptyCopyApplier; import java.util.UUID; /** - * * @author jeffwadsworth */ public final class Cytoshape extends CardImpl { - public Cytoshape(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}{U}"); // Choose a nonlegendary creature on the battlefield. Target creature becomes a copy of that creature until end of turn. this.getSpellAbility().addEffect(new CytoshapeEffect()); - - FilterCreaturePermanent filter = new FilterCreaturePermanent("target creature that will become a copy"); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent().withChooseHint("to become a copy")); } private Cytoshape(final Cytoshape card) { @@ -53,9 +48,11 @@ class CytoshapeEffect extends OneShotEffect { static { filter.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); } + CytoshapeEffect() { super(Outcome.Copy); - this.staticText = "Choose a nonlegendary creature on the battlefield. Target creature becomes a copy of that creature until end of turn."; + this.staticText = "Choose a nonlegendary creature on the battlefield. " + + "Target creature becomes a copy of that creature until end of turn."; } private CytoshapeEffect(final CytoshapeEffect effect) { @@ -69,7 +66,7 @@ class CytoshapeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability ability) { - Target target = new TargetCreaturePermanent(1, 1, filter, true); + Target target = new TargetPermanent(1, 1, filter, true); target.choose(Outcome.Copy, ability.getControllerId(), ability, game); Permanent copyFrom = game.getPermanent(target.getFirstTarget()); if (copyFrom != null) { diff --git a/Mage.Sets/src/mage/cards/c/CytospawnShambler.java b/Mage.Sets/src/mage/cards/c/CytospawnShambler.java index 93a3487f1b2..7f885b399f4 100644 --- a/Mage.Sets/src/mage/cards/c/CytospawnShambler.java +++ b/Mage.Sets/src/mage/cards/c/CytospawnShambler.java @@ -16,8 +16,11 @@ import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_CREATURE_P1P1; + /** * * @author JotaPeRL @@ -36,7 +39,7 @@ public final class CytospawnShambler extends CardImpl { // {G}: Target creature with a +1/+1 counter on it gains trample until end of turn. Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{G}")); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_P1P1)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_P1P1)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DakmorLancer.java b/Mage.Sets/src/mage/cards/d/DakmorLancer.java index 0014e1a5257..07a2c8fb163 100644 --- a/Mage.Sets/src/mage/cards/d/DakmorLancer.java +++ b/Mage.Sets/src/mage/cards/d/DakmorLancer.java @@ -10,8 +10,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author LoneFox @@ -28,7 +31,7 @@ public final class DakmorLancer extends CardImpl { // When Dakmor Lancer enters the battlefield, destroy target nonblack creature. Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + ability.addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DanceOfMany.java b/Mage.Sets/src/mage/cards/d/DanceOfMany.java index 1b266fb784e..d85eb04151c 100644 --- a/Mage.Sets/src/mage/cards/d/DanceOfMany.java +++ b/Mage.Sets/src/mage/cards/d/DanceOfMany.java @@ -23,6 +23,7 @@ import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -45,7 +46,7 @@ public final class DanceOfMany extends CardImpl { // When Dance of Many enters the battlefield, create a token that's a copy of target nontoken creature. Ability ability = new EntersBattlefieldTriggeredAbility(new DanceOfManyCreateTokenCopyEffect(), false); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // When Dance of Many leaves the battlefield, exile the token. diff --git a/Mage.Sets/src/mage/cards/d/DanceWithCalamity.java b/Mage.Sets/src/mage/cards/d/DanceWithCalamity.java index 5d947b3f73a..3b111b5bd05 100644 --- a/Mage.Sets/src/mage/cards/d/DanceWithCalamity.java +++ b/Mage.Sets/src/mage/cards/d/DanceWithCalamity.java @@ -78,6 +78,8 @@ class DanceWithCalamityEffect extends OneShotEffect { player.moveCards(card, Zone.EXILED, source, game); cards.add(card); } + game.processAction(); + cards.retainZone(Zone.EXILED, game); if (cards .getCards(game) .stream() diff --git a/Mage.Sets/src/mage/cards/d/DarajaGriffin.java b/Mage.Sets/src/mage/cards/d/DarajaGriffin.java index 06f046cd475..1448c10141c 100644 --- a/Mage.Sets/src/mage/cards/d/DarajaGriffin.java +++ b/Mage.Sets/src/mage/cards/d/DarajaGriffin.java @@ -16,6 +16,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -41,7 +42,7 @@ public final class DarajaGriffin extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Sacrifice Daraja Griffin: Destroy target black creature. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DaredevilDragster.java b/Mage.Sets/src/mage/cards/d/DaredevilDragster.java index 742cabce635..b5d5b6f1965 100644 --- a/Mage.Sets/src/mage/cards/d/DaredevilDragster.java +++ b/Mage.Sets/src/mage/cards/d/DaredevilDragster.java @@ -1,32 +1,33 @@ - package mage.cards.d; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EndOfCombatTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.AttackedOrBlockedThisCombatSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.CrewAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; +import mage.constants.ComparisonType; import mage.constants.SubType; import mage.counters.CounterType; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.watchers.common.AttackedOrBlockedThisCombatWatcher; import java.util.UUID; /** - * * @author spjspj */ public final class DaredevilDragster extends CardImpl { + private static final Condition condition = new SourceHasCounterCondition(CounterType.VELOCITY, ComparisonType.OR_GREATER, 2); + public DaredevilDragster(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); @@ -35,11 +36,15 @@ public final class DaredevilDragster extends CardImpl { this.toughness = new MageInt(4); // At end of combat, if Daredevil Dragster attacked or blocked this combat, put a velocity counter on it. Then if it has two or more velocity counters on it, sacrifice it and draw two cards. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EndOfCombatTriggeredAbility(new DaredevilDragsterEffect(), false), - AttackedOrBlockedThisCombatSourceCondition.instance, - "At end of combat, if {this} attacked or blocked this combat, put a velocity counter on it. Then if it has two or more velocity counters on it, sacrifice it and draw two cards."), - new AttackedOrBlockedThisCombatWatcher()); + Ability ability = new EndOfCombatTriggeredAbility( + new AddCountersSourceEffect(CounterType.VELOCITY.createInstance()) + .setText("put a velocity counter on it"), false + ).withInterveningIf(AttackedOrBlockedThisCombatSourceCondition.instance); + ability.addEffect(new ConditionalOneShotEffect( + new SacrificeSourceEffect(), condition, "Then if it has two " + + "or more velocity counters on it, sacrifice it and draw two cards" + ).addEffect(new DrawCardSourceControllerEffect(2))); + this.addAbility(ability, new AttackedOrBlockedThisCombatWatcher()); // Crew 2 this.addAbility(new CrewAbility(2)); @@ -54,35 +59,3 @@ public final class DaredevilDragster extends CardImpl { return new DaredevilDragster(this); } } - -class DaredevilDragsterEffect extends OneShotEffect { - - DaredevilDragsterEffect() { - super(Outcome.Damage); - this.staticText = "put a velocity counter on it. Then if it has two or more velocity counters on it, sacrifice it and draw two cards"; - } - - private DaredevilDragsterEffect(final DaredevilDragsterEffect effect) { - super(effect); - } - - @Override - public DaredevilDragsterEffect copy() { - return new DaredevilDragsterEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null && permanent != null) { - permanent.addCounters(CounterType.VELOCITY.createInstance(), source.getControllerId(), source, game); - if (permanent.getCounters(game).getCount(CounterType.VELOCITY) >= 2) { - permanent.sacrifice(source, game); - controller.drawCards(2, source, game); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DarigaazReincarnated.java b/Mage.Sets/src/mage/cards/d/DarigaazReincarnated.java index 5a05b6caaee..45f2e5e18aa 100644 --- a/Mage.Sets/src/mage/cards/d/DarigaazReincarnated.java +++ b/Mage.Sets/src/mage/cards/d/DarigaazReincarnated.java @@ -2,16 +2,15 @@ package mage.cards.d; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -52,7 +51,9 @@ public final class DarigaazReincarnated extends CardImpl { this.addAbility(new SimpleStaticAbility(new DarigaazReincarnatedDiesEffect())); // At the beginning of your upkeep, if Darigaaz is exiled with an egg counter on it, remove an egg counter from it. Then if Darigaaz has no egg counters on it, return it to the battlefield. - this.addAbility(new DarigaazReincarnatedInterveningIfTriggeredAbility()); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + Zone.EXILED, TargetController.YOU, new DarigaazReincarnatedReturnEffect(), false + ).withInterveningIf(DarigaazReincarnatedCondition.instance)); } private DarigaazReincarnated(final DarigaazReincarnated card) { @@ -108,30 +109,11 @@ class DarigaazReincarnatedDiesEffect extends ReplacementEffectImpl { } -class DarigaazReincarnatedInterveningIfTriggeredAbility extends ConditionalInterveningIfTriggeredAbility { - - public DarigaazReincarnatedInterveningIfTriggeredAbility() { - super(new BeginningOfUpkeepTriggeredAbility(Zone.EXILED, TargetController.YOU, new DarigaazReincarnatedReturnEffect(), false), - DarigaazReincarnatedCondition.instance, - "At the beginning of your upkeep, if {this} is exiled with an egg counter on it, " - + "remove an egg counter from it. Then if {this} has no egg counters on it, return it to the battlefield"); - } - - private DarigaazReincarnatedInterveningIfTriggeredAbility(final DarigaazReincarnatedInterveningIfTriggeredAbility effect) { - super(effect); - } - - @Override - public DarigaazReincarnatedInterveningIfTriggeredAbility copy() { - return new DarigaazReincarnatedInterveningIfTriggeredAbility(this); - } -} - class DarigaazReincarnatedReturnEffect extends OneShotEffect { DarigaazReincarnatedReturnEffect() { super(Outcome.Benefit); - this.staticText = ""; + this.staticText = "remove an egg counter from it. Then if this card has no egg counters on it, return it to the battlefield"; } private DarigaazReincarnatedReturnEffect(final DarigaazReincarnatedReturnEffect effect) { @@ -165,10 +147,13 @@ enum DarigaazReincarnatedCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Card card = game.getCard(source.getSourceId()); - if (card != null) { - return game.getState().getZone(card.getId()) == Zone.EXILED - && card.getCounters(game).getCount(CounterType.EGG) > 0; - } - return false; + return card != null + && game.getState().getZone(card.getId()) == Zone.EXILED + && card.getCounters(game).getCount(CounterType.EGG) > 0; + } + + @Override + public String toString() { + return "this card is exiled with an egg counter on it"; } } diff --git a/Mage.Sets/src/mage/cards/d/DarkApprenticeship.java b/Mage.Sets/src/mage/cards/d/DarkApprenticeship.java index 92fa2bdaf75..0cd1317e3c0 100644 --- a/Mage.Sets/src/mage/cards/d/DarkApprenticeship.java +++ b/Mage.Sets/src/mage/cards/d/DarkApprenticeship.java @@ -1,20 +1,19 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.common.HateCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.target.TargetPlayer; import mage.watchers.common.LifeLossOtherFromCombatWatcher; +import java.util.UUID; + /** - * * @author Styxo */ public final class DarkApprenticeship extends CardImpl { @@ -23,12 +22,10 @@ public final class DarkApprenticeship extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); // Hate — At the beggining of your end step, if an opponent lost life from source other than combat damage this turn, Dark Apprenticeship deals 2 damage to target player. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility(new DamageTargetEffect(2)), - HateCondition.instance, - "Hate — At the beggining of your end step, if an opponent lost life from source other than combat damage this turn, Dark Apprenticeship deals 2 damage to target player."); + Ability ability = new BeginningOfEndStepTriggeredAbility(new DamageTargetEffect(2)) + .withInterveningIf(HateCondition.instance); ability.addTarget(new TargetPlayer()); - this.addAbility(ability, new LifeLossOtherFromCombatWatcher()); + this.addAbility(ability.setAbilityWord(AbilityWord.HATE), new LifeLossOtherFromCombatWatcher()); } private DarkApprenticeship(final DarkApprenticeship card) { diff --git a/Mage.Sets/src/mage/cards/d/DarkBanishing.java b/Mage.Sets/src/mage/cards/d/DarkBanishing.java index b162617a5d8..4d75ffcd23d 100644 --- a/Mage.Sets/src/mage/cards/d/DarkBanishing.java +++ b/Mage.Sets/src/mage/cards/d/DarkBanishing.java @@ -6,8 +6,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author Loki @@ -18,7 +21,7 @@ public final class DarkBanishing extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{B}"); this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); } private DarkBanishing(final DarkBanishing card) { diff --git a/Mage.Sets/src/mage/cards/d/DarkBetrayal.java b/Mage.Sets/src/mage/cards/d/DarkBetrayal.java index 1cc12dcc10a..91ecc4dab9b 100644 --- a/Mage.Sets/src/mage/cards/d/DarkBetrayal.java +++ b/Mage.Sets/src/mage/cards/d/DarkBetrayal.java @@ -10,6 +10,7 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class DarkBetrayal extends CardImpl { // Destroy target black creature. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); this.getSpellAbility().addTarget(target); } diff --git a/Mage.Sets/src/mage/cards/d/DarkHatchling.java b/Mage.Sets/src/mage/cards/d/DarkHatchling.java index 3e7398fb753..471b262b837 100644 --- a/Mage.Sets/src/mage/cards/d/DarkHatchling.java +++ b/Mage.Sets/src/mage/cards/d/DarkHatchling.java @@ -11,8 +11,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author LevelX2 @@ -31,7 +34,7 @@ public final class DarkHatchling extends CardImpl { // When Dark Hatchling enters the battlefield, destroy target nonblack creature. It can't be regenerated. Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(true)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + ability.addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DarkOffering.java b/Mage.Sets/src/mage/cards/d/DarkOffering.java index dd094ee0d4d..a8161e9afb7 100644 --- a/Mage.Sets/src/mage/cards/d/DarkOffering.java +++ b/Mage.Sets/src/mage/cards/d/DarkOffering.java @@ -7,8 +7,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author fireshoes @@ -21,7 +24,7 @@ public final class DarkOffering extends CardImpl { // Destroy target nonblack creature. You gain 3 life. this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addEffect(new GainLifeEffect(3)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); } private DarkOffering(final DarkOffering card) { diff --git a/Mage.Sets/src/mage/cards/d/DarkWithering.java b/Mage.Sets/src/mage/cards/d/DarkWithering.java index 9d2cdb6eae6..e3a6f87ff33 100644 --- a/Mage.Sets/src/mage/cards/d/DarkWithering.java +++ b/Mage.Sets/src/mage/cards/d/DarkWithering.java @@ -8,8 +8,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author magenoxx_at_gmail.com @@ -20,7 +23,7 @@ public final class DarkWithering extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{4}{B}{B}"); // Destroy target nonblack creature. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); // Madness {B} diff --git a/Mage.Sets/src/mage/cards/d/DarthMaul.java b/Mage.Sets/src/mage/cards/d/DarthMaul.java index 0a733776e9a..ea146b426bf 100644 --- a/Mage.Sets/src/mage/cards/d/DarthMaul.java +++ b/Mage.Sets/src/mage/cards/d/DarthMaul.java @@ -1,26 +1,21 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.HateCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.combat.CantBeBlockedByTargetSourceEffect; import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.SuperType; +import mage.constants.*; import mage.target.common.TargetCreaturePermanent; import mage.watchers.common.LifeLossOtherFromCombatWatcher; +import java.util.UUID; + /** - * * @author Styxo */ public final class DarthMaul extends CardImpl { @@ -40,12 +35,10 @@ public final class DarthMaul extends CardImpl { this.addAbility(HasteAbility.getInstance()); // Hate — Whenever Darth Maul attacks, if an opponent loses life from a source other than combat damage this turn, target creature can't block this turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new CantBeBlockedByTargetSourceEffect(Duration.EndOfTurn), false), - HateCondition.instance, - "Hate — Whenever Darth Maul attacks, if an opponent loses life from a source other than combat damage this turn, target creature can't block this turn."); + Ability ability = new AttacksTriggeredAbility(new CantBeBlockedByTargetSourceEffect(Duration.EndOfTurn)) + .withInterveningIf(HateCondition.instance); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability, new LifeLossOtherFromCombatWatcher()); + this.addAbility(ability.setAbilityWord(AbilityWord.HATE), new LifeLossOtherFromCombatWatcher()); } private DarthMaul(final DarthMaul card) { diff --git a/Mage.Sets/src/mage/cards/d/DaruEncampment.java b/Mage.Sets/src/mage/cards/d/DaruEncampment.java index b5d8a77173c..d55e0b8801e 100644 --- a/Mage.Sets/src/mage/cards/d/DaruEncampment.java +++ b/Mage.Sets/src/mage/cards/d/DaruEncampment.java @@ -14,6 +14,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class DaruEncampment extends CardImpl { new BoostTargetEffect(1, 1, Duration.EndOfTurn), new ManaCostsImpl<>("{W}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DaughterOfAutumn.java b/Mage.Sets/src/mage/cards/d/DaughterOfAutumn.java index 732032ad82f..635fe9c3888 100644 --- a/Mage.Sets/src/mage/cards/d/DaughterOfAutumn.java +++ b/Mage.Sets/src/mage/cards/d/DaughterOfAutumn.java @@ -45,7 +45,7 @@ public final class DaughterOfAutumn extends CardImpl { // {W}: The next 1 damage that would be dealt to target white creature this turn is dealt to Daughter of Autumn instead. Ability ability = new SimpleActivatedAbility(new DaughterOfAutumnPreventDamageTargetEffect(Duration.EndOfTurn, 1), new ManaCostsImpl<>("{W}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DauthiCutthroat.java b/Mage.Sets/src/mage/cards/d/DauthiCutthroat.java index 59f10702451..3eacea98f57 100644 --- a/Mage.Sets/src/mage/cards/d/DauthiCutthroat.java +++ b/Mage.Sets/src/mage/cards/d/DauthiCutthroat.java @@ -16,6 +16,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -42,7 +43,7 @@ public final class DauthiCutthroat extends CardImpl { // {1}{B}, {tap}: Destroy target creature with shadow. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{1}{B}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DauthiJackal.java b/Mage.Sets/src/mage/cards/d/DauthiJackal.java index 34039f12d65..d1e3a29c6fe 100644 --- a/Mage.Sets/src/mage/cards/d/DauthiJackal.java +++ b/Mage.Sets/src/mage/cards/d/DauthiJackal.java @@ -15,6 +15,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterBlockingCreature; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -36,7 +37,7 @@ public final class DauthiJackal extends CardImpl { // {B}{B}, Sacrifice Dauthi Jackal: Destroy target blocking creature. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{B}{B}")); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(new FilterBlockingCreature())); + ability.addTarget(new TargetPermanent(new FilterBlockingCreature())); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DavrielRogueShadowmage.java b/Mage.Sets/src/mage/cards/d/DavrielRogueShadowmage.java index d73c39d5fdf..6d5c900626c 100644 --- a/Mage.Sets/src/mage/cards/d/DavrielRogueShadowmage.java +++ b/Mage.Sets/src/mage/cards/d/DavrielRogueShadowmage.java @@ -2,16 +2,14 @@ package mage.cards.d; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.CardsInHandCondition; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.game.Game; -import mage.players.Player; import mage.target.TargetPlayer; import java.util.UUID; @@ -21,6 +19,8 @@ import java.util.UUID; */ public final class DavrielRogueShadowmage extends CardImpl { + private static final Condition condition = new CardsInHandCondition(ComparisonType.OR_LESS, 1, TargetController.ACTIVE); + public DavrielRogueShadowmage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{B}"); @@ -29,13 +29,12 @@ public final class DavrielRogueShadowmage extends CardImpl { this.setStartingLoyalty(3); // At the beginning of each opponent's upkeep, if that player has one or fewer cards in hand, Davriel, Rogue Shadowmage deals 2 damage to them. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - Zone.BATTLEFIELD, TargetController.OPPONENT, new DamageTargetEffect(2), - false - ), DavrielRogueShadowmageCondition.instance, "At the beginning of each opponent's upkeep, " + - "if that player has one or fewer cards in hand, {this} deals 2 damage to them." - )); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.OPPONENT, + new DamageTargetEffect( + 2, true, "them", "{this}" + ), false + ).withInterveningIf(condition)); // -1: Target player discards a card. Ability ability = new LoyaltyAbility(new DiscardTargetEffect(1), -1); @@ -52,13 +51,3 @@ public final class DavrielRogueShadowmage extends CardImpl { return new DavrielRogueShadowmage(this); } } - -enum DavrielRogueShadowmageCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(game.getActivePlayerId()); - return player != null && player.getHand().size() < 2; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DawnhartMentor.java b/Mage.Sets/src/mage/cards/d/DawnhartMentor.java index 6f3341802c6..231300568d9 100644 --- a/Mage.Sets/src/mage/cards/d/DawnhartMentor.java +++ b/Mage.Sets/src/mage/cards/d/DawnhartMentor.java @@ -13,7 +13,10 @@ import mage.abilities.hint.common.CovenHint; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.game.permanent.token.HumanToken; import mage.target.common.TargetControlledCreaturePermanent; @@ -37,8 +40,8 @@ public final class DawnhartMentor extends CardImpl { // Coven — {5}{G}: Target creature you control gets +3/+3 and gains trample until end of turn. Activate only if you control three or more creatures with different powers. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new BoostTargetEffect(3, 3) - .setText("target creature you control gets +3/+3"), + new BoostTargetEffect(3, 3) + .setText("target creature you control gets +3/+3"), new ManaCostsImpl<>("{5}{G}"), CovenCondition.instance ); ability.addEffect(new GainAbilityTargetEffect( diff --git a/Mage.Sets/src/mage/cards/d/DawnhartWardens.java b/Mage.Sets/src/mage/cards/d/DawnhartWardens.java index 64db6ce7043..162fd925da1 100644 --- a/Mage.Sets/src/mage/cards/d/DawnhartWardens.java +++ b/Mage.Sets/src/mage/cards/d/DawnhartWardens.java @@ -1,15 +1,17 @@ package mage.cards.d; import mage.MageInt; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.common.CovenCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.hint.common.CovenHint; import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import java.util.UUID; @@ -30,13 +32,8 @@ public final class DawnhartWardens extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // Coven — At the beginning of combat on your turn, if you control three or more creatures with different powers, creatures you control get +1/+0 until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - new BoostControlledEffect(1, 0, Duration.EndOfTurn) - ), CovenCondition.instance, "At the beginning of combat on your turn, " + - "if you control three or more creatures with different powers, " + - "creatures you control get +1/+0 until end of turn." - ).addHint(CovenHint.instance).setAbilityWord(AbilityWord.COVEN)); + this.addAbility(new BeginningOfCombatTriggeredAbility(new BoostControlledEffect(1, 0, Duration.EndOfTurn)) + .withInterveningIf(CovenCondition.instance).addHint(CovenHint.instance).setAbilityWord(AbilityWord.COVEN)); } private DawnhartWardens(final DawnhartWardens card) { diff --git a/Mage.Sets/src/mage/cards/d/DaybreakRanger.java b/Mage.Sets/src/mage/cards/d/DaybreakRanger.java index ef18fe46a36..cc653c12f4d 100644 --- a/Mage.Sets/src/mage/cards/d/DaybreakRanger.java +++ b/Mage.Sets/src/mage/cards/d/DaybreakRanger.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -44,7 +45,7 @@ public final class DaybreakRanger extends CardImpl { // {tap}: Daybreak Ranger deals 2 damage to target creature with flying. Ability activatedAbility = new SimpleActivatedAbility(new DamageTargetEffect(2), new TapSourceCost()); - activatedAbility.addTarget(new TargetCreaturePermanent(filter)); + activatedAbility.addTarget(new TargetPermanent(filter)); this.addAbility(activatedAbility); // At the beginning of each upkeep, if no spells were cast last turn, transform Daybreak Ranger. this.addAbility(new TransformAbility()); diff --git a/Mage.Sets/src/mage/cards/d/DazzlingBeauty.java b/Mage.Sets/src/mage/cards/d/DazzlingBeauty.java index f039a87452f..f4308183362 100644 --- a/Mage.Sets/src/mage/cards/d/DazzlingBeauty.java +++ b/Mage.Sets/src/mage/cards/d/DazzlingBeauty.java @@ -13,6 +13,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.AttackingPredicate; import mage.filter.predicate.permanent.BlockedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -40,7 +41,7 @@ public final class DazzlingBeauty extends CardImpl { // Target unblocked attacking creature becomes blocked. this.getSpellAbility().addEffect(new BecomeBlockedTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Draw a card at the beginning of the next turn's upkeep. this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextUpkeepDelayedTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/d/DeadGone.java b/Mage.Sets/src/mage/cards/d/DeadGone.java index eb3e1c7da47..6f67087d7be 100644 --- a/Mage.Sets/src/mage/cards/d/DeadGone.java +++ b/Mage.Sets/src/mage/cards/d/DeadGone.java @@ -6,11 +6,13 @@ import mage.cards.CardSetInfo; import mage.cards.SplitCard; import mage.constants.CardType; import mage.constants.SpellAbilityType; -import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author dustinconrad */ @@ -21,13 +23,13 @@ public final class DeadGone extends SplitCard { // Dead // Dead deals 2 damage to target creature. - getLeftHalfCard().getSpellAbility().addEffect(new DamageTargetEffect(2, "Dead")); + getLeftHalfCard().getSpellAbility().addEffect(new DamageTargetEffect(2)); getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); // Gone // Return target creature you don't control to its owner's hand. getRightHalfCard().getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + getRightHalfCard().getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); } private DeadGone(final DeadGone card) { diff --git a/Mage.Sets/src/mage/cards/d/DeadRingers.java b/Mage.Sets/src/mage/cards/d/DeadRingers.java index 125edf0b560..ba6077eea68 100644 --- a/Mage.Sets/src/mage/cards/d/DeadRingers.java +++ b/Mage.Sets/src/mage/cards/d/DeadRingers.java @@ -1,19 +1,22 @@ package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Outcome; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; /** - * * @author LoneFox */ public final class DeadRingers extends CardImpl { @@ -23,7 +26,7 @@ public final class DeadRingers extends CardImpl { // Destroy two target nonblack creatures unless either one is a color the other isn't. They can't be regenerated. this.getSpellAbility().addEffect(new DeadRingersEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(2, 2, StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK, false)); + this.getSpellAbility().addTarget(new TargetPermanent(2, StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); } private DeadRingers(final DeadRingers card) { @@ -36,11 +39,11 @@ public final class DeadRingers extends CardImpl { } } -class DeadRingersEffect extends DestroyTargetEffect { +class DeadRingersEffect extends OneShotEffect { DeadRingersEffect() { - super(true); - staticText = "Destroy two target nonblack creatures unless either one is a color the other isn't. They can't be regenerated."; + super(Outcome.DestroyPermanent); + staticText = "destroy two target nonblack creatures unless either one is a color the other isn't. They can't be regenerated."; } private DeadRingersEffect(final DeadRingersEffect effect) { @@ -54,17 +57,23 @@ class DeadRingersEffect extends DestroyTargetEffect { @Override public boolean apply(Game game, Ability source) { - Target target = source.getTargets().get(0); - if (target != null - && target.getTargets().size() > 1) { - Permanent first = game.getPermanentOrLKIBattlefield(target.getTargets().get(0)); - Permanent second = game.getPermanentOrLKIBattlefield(target.getTargets().get(1)); - if (first != null - && second != null - && first.getColor(game).equals(second.getColor(game))) { - return super.apply(game, source); - } + List permanents = this + .getTargetPointer() + .getTargets(game, source) + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + if (permanents.size() < 2) { + return false; } - return false; + Permanent first = permanents.get(0); + Permanent second = permanents.get(1); + if (!first.getColor(game).equals(second.getColor(game))) { + return false; + } + first.destroy(source, game, true); + second.destroy(source, game, true); + return true; } } diff --git a/Mage.Sets/src/mage/cards/d/DeadWeight.java b/Mage.Sets/src/mage/cards/d/DeadWeight.java index 0f7e6378f6f..76d576642b5 100644 --- a/Mage.Sets/src/mage/cards/d/DeadWeight.java +++ b/Mage.Sets/src/mage/cards/d/DeadWeight.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; @@ -10,30 +8,30 @@ import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.SubType; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Alvin */ public final class DeadWeight extends CardImpl { public DeadWeight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}"); this.subtype.add(SubType.AURA); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); Ability ability = new EnchantAbility(auraTarget); this.addAbility(ability); + // Enchanted creature gets -2/-2. this.addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(-2, -2, Duration.WhileOnBattlefield))); } diff --git a/Mage.Sets/src/mage/cards/d/DeadeyeBrawler.java b/Mage.Sets/src/mage/cards/d/DeadeyeBrawler.java index 2918f6274b6..c71dc1e5727 100644 --- a/Mage.Sets/src/mage/cards/d/DeadeyeBrawler.java +++ b/Mage.Sets/src/mage/cards/d/DeadeyeBrawler.java @@ -3,7 +3,6 @@ package mage.cards.d; import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.condition.common.CitysBlessingCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; @@ -35,11 +34,8 @@ public final class DeadeyeBrawler extends CardImpl { this.addAbility(new AscendAbility()); // Whenever Deadeye Brawler deals combat damage to a player, if you have the city's blessing, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new DealsCombatDamageToAPlayerTriggeredAbility( - new DrawCardSourceControllerEffect(1), false, false), CitysBlessingCondition.instance, - "Whenever {this} deals combat damage to a player, if you have the city's blessing, draw a card.") - .addHint(CitysBlessingHint.instance)); - + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .withInterveningIf(CitysBlessingCondition.instance).addHint(CitysBlessingHint.instance)); } private DeadeyeBrawler(final DeadeyeBrawler card) { diff --git a/Mage.Sets/src/mage/cards/d/DeadeyeRigHauler.java b/Mage.Sets/src/mage/cards/d/DeadeyeRigHauler.java index e8636b36be1..e791f67dbd8 100644 --- a/Mage.Sets/src/mage/cards/d/DeadeyeRigHauler.java +++ b/Mage.Sets/src/mage/cards/d/DeadeyeRigHauler.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.hint.common.RaidHint; import mage.cards.CardImpl; @@ -31,8 +30,7 @@ public final class DeadeyeRigHauler extends CardImpl { this.toughness = new MageInt(2); // Raid— When Deadeye Rig-Hauler enters the battlefield, if you attacked this turn, you may return target creature to its owner's hand. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true), RaidCondition.instance, - "When {this} enters, if you attacked this turn, you may return target creature to its owner's hand."); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true).withInterveningIf(RaidCondition.instance); ability.addTarget(new TargetCreaturePermanent()); ability.setAbilityWord(AbilityWord.RAID); ability.addHint(RaidHint.instance); diff --git a/Mage.Sets/src/mage/cards/d/DeadlyGrub.java b/Mage.Sets/src/mage/cards/d/DeadlyGrub.java index 80e03776e96..7f1134f0253 100644 --- a/Mage.Sets/src/mage/cards/d/DeadlyGrub.java +++ b/Mage.Sets/src/mage/cards/d/DeadlyGrub.java @@ -3,7 +3,6 @@ package mage.cards.d; import mage.MageInt; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.condition.common.LastTimeCounterRemovedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.VanishingAbility; import mage.cards.CardImpl; @@ -29,8 +28,7 @@ public final class DeadlyGrub extends CardImpl { this.addAbility(new VanishingAbility(3)); // When Deadly Grub dies, if it had no time counters on it, create a 6/1 green Insect creature token with shroud. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new DeadlyGrubInsectToken(), 1)), - LastTimeCounterRemovedCondition.instance, "When {this} dies, if it had no time counters on it, create a 6/1 green Insect creature token with shroud.")); + this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new DeadlyGrubInsectToken(), 1)).withInterveningIf(LastTimeCounterRemovedCondition.instance)); } private DeadlyGrub(final DeadlyGrub card) { diff --git a/Mage.Sets/src/mage/cards/d/Deadshot.java b/Mage.Sets/src/mage/cards/d/Deadshot.java index f58e7d91df0..fa17bc469fa 100644 --- a/Mage.Sets/src/mage/cards/d/Deadshot.java +++ b/Mage.Sets/src/mage/cards/d/Deadshot.java @@ -1,42 +1,31 @@ - package mage.cards.d; -import java.util.UUID; +import mage.abilities.effects.common.DamageWithPowerFromOneToAnotherTargetEffect; import mage.abilities.effects.common.TapTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.other.AnotherTargetPredicate; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; -import mage.abilities.effects.common.DamageWithPowerFromOneToAnotherTargetEffect; + +import java.util.UUID; /** - * * @author fireshoes, xenohedron */ public final class Deadshot extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); - - static { - filter.add(new AnotherTargetPredicate(2)); - } - public Deadshot(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}"); // Tap target creature. this.getSpellAbility().addEffect(new TapTargetEffect()); - TargetCreaturePermanent target = new TargetCreaturePermanent(); - target.setTargetTag(1); - this.getSpellAbility().addTarget(target); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().setTargetTag(1)); // It deals damage equal to its power to another target creature. this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect("It")); - target = new TargetCreaturePermanent(filter); - target.setTargetTag(2); - this.getSpellAbility().addTarget(target); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2).setTargetTag(2)); } private Deadshot(final Deadshot card) { @@ -48,4 +37,3 @@ public final class Deadshot extends CardImpl { return new Deadshot(this); } } - diff --git a/Mage.Sets/src/mage/cards/d/DeadshotMinotaur.java b/Mage.Sets/src/mage/cards/d/DeadshotMinotaur.java index 54a594fe08f..8ebaa2c9e90 100644 --- a/Mage.Sets/src/mage/cards/d/DeadshotMinotaur.java +++ b/Mage.Sets/src/mage/cards/d/DeadshotMinotaur.java @@ -15,6 +15,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class DeadshotMinotaur extends CardImpl { // When Deadshot Minotaur enters the battlefield, it deals 3 damage to target creature with flying. Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(3, "it"), false); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Cycling {RG} this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{R/G}"))); diff --git a/Mage.Sets/src/mage/cards/d/DealBroker.java b/Mage.Sets/src/mage/cards/d/DealBroker.java index 9bc0502b888..a3c28f28cfa 100644 --- a/Mage.Sets/src/mage/cards/d/DealBroker.java +++ b/Mage.Sets/src/mage/cards/d/DealBroker.java @@ -1,6 +1,5 @@ package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -13,6 +12,8 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; +import java.util.UUID; + /** * * @author L_J @@ -28,7 +29,7 @@ public final class DealBroker extends CardImpl { // TODO: Draft specific abilities not implemented // Draft Deal Broker face up. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft Deal Broker face up."))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft {this} face up."))); // Immediately after the draft, you may reveal a card in your card pool. Each other player may offer you one card in their card pool in exchange. You may accept any one offer. this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Immediately after the draft, you may reveal a card in your card pool. " diff --git a/Mage.Sets/src/mage/cards/d/DeathBomb.java b/Mage.Sets/src/mage/cards/d/DeathBomb.java index 1eb2242cc76..fa69db16a6b 100644 --- a/Mage.Sets/src/mage/cards/d/DeathBomb.java +++ b/Mage.Sets/src/mage/cards/d/DeathBomb.java @@ -8,9 +8,12 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author LoneFox @@ -25,7 +28,7 @@ public final class DeathBomb extends CardImpl { // Destroy target nonblack creature. It can't be regenerated. Its controller loses 2 life. this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); this.getSpellAbility().addEffect(new LoseLifeTargetControllerEffect(2)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK).withChooseHint("to destroy")); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK).withChooseHint("to destroy")); } private DeathBomb(final DeathBomb card) { diff --git a/Mage.Sets/src/mage/cards/d/DeathRattle.java b/Mage.Sets/src/mage/cards/d/DeathRattle.java index a3017aa83b8..9f91487cbae 100644 --- a/Mage.Sets/src/mage/cards/d/DeathRattle.java +++ b/Mage.Sets/src/mage/cards/d/DeathRattle.java @@ -11,6 +11,7 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -33,7 +34,7 @@ public final class DeathRattle extends CardImpl { // Destroy target nongreen creature. It can't be regenerated. this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } diff --git a/Mage.Sets/src/mage/cards/d/DeathSpark.java b/Mage.Sets/src/mage/cards/d/DeathSpark.java index 7cdca5d2a58..a0a2ea34509 100644 --- a/Mage.Sets/src/mage/cards/d/DeathSpark.java +++ b/Mage.Sets/src/mage/cards/d/DeathSpark.java @@ -1,15 +1,12 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -20,8 +17,9 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author emerald000 */ public final class DeathSpark extends CardImpl { @@ -29,19 +27,15 @@ public final class DeathSpark extends CardImpl { public DeathSpark(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); - // Death Spark deals 1 damage to any target. this.getSpellAbility().addEffect(new DamageTargetEffect(1)); this.getSpellAbility().addTarget(new TargetAnyTarget()); // At the beginning of your upkeep, if Death Spark is in your graveyard with a creature card directly above it, you may pay {1}. If you do, return Death Spark to your hand. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - Zone.GRAVEYARD, - TargetController.YOU, new DoIfCostPaid(new ReturnSourceFromGraveyardToHandEffect(), new GenericManaCost(1)), - false), - DeathSparkCondition.instance, - "At the beginning of your upkeep, if {this} is in your graveyard with a creature card directly above it, you may pay {1}. If you do, return {this} to your hand.")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + Zone.GRAVEYARD, TargetController.YOU, + new DoIfCostPaid(new ReturnSourceFromGraveyardToHandEffect().setText("return this card to your hand"), new GenericManaCost(1)), false + ).withInterveningIf(DeathSparkCondition.instance)); } private DeathSpark(final DeathSpark card) { @@ -55,21 +49,21 @@ public final class DeathSpark extends CardImpl { } enum DeathSparkCondition implements Condition { - instance; @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - boolean nextCard = false; - for (Card card : controller.getGraveyard().getCards(game)) { - if (nextCard) { - return card.isCreature(game); - } - if (card.getId().equals(source.getSourceId())) { - nextCard = true; - } + if (controller == null) { + return false; + } + boolean nextCard = false; + for (Card card : controller.getGraveyard().getCards(game)) { + if (nextCard) { + return card.isCreature(game); + } + if (card.getId().equals(source.getSourceId())) { + nextCard = true; } } return false; @@ -77,6 +71,6 @@ enum DeathSparkCondition implements Condition { @Override public String toString() { - return "{this} is in your graveyard with a creature card directly above it"; + return "this card is in your graveyard with a creature card directly above it"; } } diff --git a/Mage.Sets/src/mage/cards/d/DeathStroke.java b/Mage.Sets/src/mage/cards/d/DeathStroke.java index 53a57c1b803..7b1de0240e5 100644 --- a/Mage.Sets/src/mage/cards/d/DeathStroke.java +++ b/Mage.Sets/src/mage/cards/d/DeathStroke.java @@ -8,6 +8,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -26,7 +27,7 @@ public final class DeathStroke extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{B}{B}"); // Destroy target tapped creature. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/d/DeathbringerRegent.java b/Mage.Sets/src/mage/cards/d/DeathbringerRegent.java index 4e84fd7c6ae..66086b530ac 100644 --- a/Mage.Sets/src/mage/cards/d/DeathbringerRegent.java +++ b/Mage.Sets/src/mage/cards/d/DeathbringerRegent.java @@ -1,27 +1,25 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.CompoundCondition; import mage.abilities.condition.Condition; import mage.abilities.condition.common.CastFromHandSourcePermanentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.game.Game; import mage.watchers.common.CastFromHandWatcher; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class DeathbringerRegent extends CardImpl { @@ -32,6 +30,12 @@ public final class DeathbringerRegent extends CardImpl { filter.add(AnotherPredicate.instance); } + private static final Condition condition = new CompoundCondition( + "you cast it from your hand and there are five or more other creatures on the battlefield", + CastFromHandSourcePermanentCondition.instance, + new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 4) + ); + public DeathbringerRegent(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}"); this.subtype.add(SubType.DRAGON); @@ -42,11 +46,8 @@ public final class DeathbringerRegent extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Deathbringer Regent enters the battlefield, if you cast it from your hand and there are five or more other creatures on the battlefield, destroy all other creatures. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(filter), false), - new DeathbringerRegentCondition(), - "When {this} enters, if you cast it from your hand and there are five or more other creatures on the battlefield, destroy all other creatures."), - new CastFromHandWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(filter)) + .withInterveningIf(condition), new CastFromHandWatcher()); } private DeathbringerRegent(final DeathbringerRegent card) { @@ -58,12 +59,3 @@ public final class DeathbringerRegent extends CardImpl { return new DeathbringerRegent(this); } } - -class DeathbringerRegentCondition implements Condition { - - @Override - public boolean apply(Game game, Ability source) { - return CastFromHandSourcePermanentCondition.instance.apply(game, source) - && game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game).size() >= 6; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DeathknellBerserker.java b/Mage.Sets/src/mage/cards/d/DeathknellBerserker.java index 5c40296135c..11a3d6a4119 100644 --- a/Mage.Sets/src/mage/cards/d/DeathknellBerserker.java +++ b/Mage.Sets/src/mage/cards/d/DeathknellBerserker.java @@ -1,22 +1,23 @@ package mage.cards.d; -import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.ZombieBerserkerToken; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author weirddan455 */ public final class DeathknellBerserker extends CardImpl { @@ -30,11 +31,8 @@ public final class DeathknellBerserker extends CardImpl { this.toughness = new MageInt(2); // When Deathknell Berserker dies, if its power was 3 or greater, create a 2/2 black Zombie Berserker creature token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new DiesSourceTriggeredAbility(new CreateTokenEffect(new ZombieBerserkerToken())), - DeathknellBerserkerCondtion.instance, - "When {this} dies, if its power was 3 or greater, create a 2/2 black Zombie Berserker creature token." - )); + this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new ZombieBerserkerToken())) + .withInterveningIf(DeathknellBerserkerCondtion.instance)); } private DeathknellBerserker(final DeathknellBerserker card) { @@ -53,7 +51,16 @@ enum DeathknellBerserkerCondtion implements Condition { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) source.getEffects().get(0).getValue("permanentLeftBattlefield"); - return permanent != null && permanent.getPower().getValue() >= 3; + return CardUtil + .getEffectValueFromAbility(source, "permanentLeftBattlefield", Permanent.class) + .map(MageObject::getPower) + .map(MageInt::getValue) + .filter(x -> x >= 3) + .isPresent(); + } + + @Override + public String toString() { + return "its power was 3 or greater"; } } diff --git a/Mage.Sets/src/mage/cards/d/Deathmark.java b/Mage.Sets/src/mage/cards/d/Deathmark.java index 1423365d92a..bb046fd03ee 100644 --- a/Mage.Sets/src/mage/cards/d/Deathmark.java +++ b/Mage.Sets/src/mage/cards/d/Deathmark.java @@ -11,6 +11,7 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -30,7 +31,7 @@ public final class Deathmark extends CardImpl { public Deathmark(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{B}"); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/d/DeathmarkPrelate.java b/Mage.Sets/src/mage/cards/d/DeathmarkPrelate.java index 794f8afcd02..134aece3c74 100644 --- a/Mage.Sets/src/mage/cards/d/DeathmarkPrelate.java +++ b/Mage.Sets/src/mage/cards/d/DeathmarkPrelate.java @@ -17,6 +17,7 @@ import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; @@ -46,7 +47,7 @@ public final class DeathmarkPrelate extends CardImpl { Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(true), new ManaCostsImpl<>("{2}{B}")); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeTargetCost(filter1)); - ability.addTarget(new TargetCreaturePermanent(filter2)); + ability.addTarget(new TargetPermanent(filter2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DeathsPresence.java b/Mage.Sets/src/mage/cards/d/DeathsPresence.java index 8ccfce29cac..bba8dbe3e9b 100644 --- a/Mage.Sets/src/mage/cards/d/DeathsPresence.java +++ b/Mage.Sets/src/mage/cards/d/DeathsPresence.java @@ -1,20 +1,20 @@ package mage.cards.d; -import java.util.UUID; - -import mage.MageObject; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.counters.CounterType; +import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** * @@ -23,10 +23,14 @@ import mage.target.common.TargetControlledCreaturePermanent; public final class DeathsPresence extends CardImpl { public DeathsPresence(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{5}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{5}{G}"); // Whenever a creature you control dies, put X +1/+1 counters on target creature you control, where X is the power of the creature that died. - this.addAbility(new DeathsPresenceTriggeredAbility()); + Ability ability = new DiesCreatureTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance(), DeathsPresenceDiedPermanentPowerCount.instance), + false, StaticFilters.FILTER_CONTROLLED_CREATURE); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED)); + this.addAbility(ability); } private DeathsPresence(final DeathsPresence card) { @@ -39,50 +43,30 @@ public final class DeathsPresence extends CardImpl { } } -class DeathsPresenceTriggeredAbility extends TriggeredAbilityImpl { - - public DeathsPresenceTriggeredAbility() { - super(Zone.BATTLEFIELD, null); - setLeavesTheBattlefieldTrigger(true); - } - - private DeathsPresenceTriggeredAbility(final DeathsPresenceTriggeredAbility ability) { - super(ability); - } +enum DeathsPresenceDiedPermanentPowerCount implements DynamicValue { + instance; @Override - public DeathsPresenceTriggeredAbility copy() { - return new DeathsPresenceTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ZONE_CHANGE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - ZoneChangeEvent zoneChangeEvent = (ZoneChangeEvent) event; - if (zoneChangeEvent.isDiesEvent()) { - Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); - if (permanent != null && permanent.isControlledBy(this.getControllerId()) && permanent.isCreature(game)) { - this.getTargets().clear(); - this.addTarget(new TargetControlledCreaturePermanent()); - this.getEffects().clear(); - this.addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(permanent.getPower().getValue()))); - return true; - } + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Permanent targetPermanent = (Permanent) effect.getValue("creatureDied"); + if (targetPermanent != null) { + return targetPermanent.getPower().getValue(); } - return false; + return 0; } @Override - public String getRule() { - return "Whenever a creature you control dies, put X +1/+1 counters on target creature you control, where X is the power of the creature that died."; + public DeathsPresenceDiedPermanentPowerCount copy() { + return DeathsPresenceDiedPermanentPowerCount.instance; } @Override - public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) { - return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game); + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return "the power of the creature that died"; } } diff --git a/Mage.Sets/src/mage/cards/d/DeceiverOfForm.java b/Mage.Sets/src/mage/cards/d/DeceiverOfForm.java index 46472f791f6..274f2984b79 100644 --- a/Mage.Sets/src/mage/cards/d/DeceiverOfForm.java +++ b/Mage.Sets/src/mage/cards/d/DeceiverOfForm.java @@ -1,12 +1,11 @@ package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CopyEffect; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.*; import mage.constants.*; import mage.filter.StaticFilters; @@ -15,6 +14,8 @@ import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; import mage.players.Player; +import java.util.UUID; + /** * * @author LevelX2 @@ -47,7 +48,9 @@ class DeceiverOfFormEffect extends OneShotEffect { DeceiverOfFormEffect() { super(Outcome.Copy); - this.staticText = "reveal the top card of your library. If a creature card is revealed this way, you may have creatures you control other than Deceiver of Form becomes copies of that card until end of turn. You may put that card on the bottom of your library"; + this.staticText = "reveal the top card of your library. If a creature card is revealed this way, " + + "you may have creatures you control other than {this} become copies of that card until end of turn. " + + "You may put that card on the bottom of your library"; } private DeceiverOfFormEffect(final DeceiverOfFormEffect effect) { diff --git a/Mage.Sets/src/mage/cards/d/DecimatorBeetle.java b/Mage.Sets/src/mage/cards/d/DecimatorBeetle.java index 29e3b1a0b2e..1b0d6459c4c 100644 --- a/Mage.Sets/src/mage/cards/d/DecimatorBeetle.java +++ b/Mage.Sets/src/mage/cards/d/DecimatorBeetle.java @@ -18,8 +18,8 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; import java.util.UUID; @@ -51,7 +51,7 @@ public final class DecimatorBeetle extends CardImpl { // Whenever Decimator Beetle attacks, remove a -1/-1 counter from target creature you control and put a -1/-1 counter on up to one target creature defending player controls. ability = new AttacksTriggeredAbility(new DecimatorBeetleEffect(), false); ability.addTarget(new TargetControlledCreaturePermanent()); - ability.addTarget(new TargetCreaturePermanent(0, 1, filter, false)); + ability.addTarget(new TargetPermanent(0, 1, filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DecisiveDenial.java b/Mage.Sets/src/mage/cards/d/DecisiveDenial.java index d6957b31e90..e6a20f79eca 100644 --- a/Mage.Sets/src/mage/cards/d/DecisiveDenial.java +++ b/Mage.Sets/src/mage/cards/d/DecisiveDenial.java @@ -8,12 +8,15 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.TargetSpell; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author TheElk801 */ @@ -28,7 +31,7 @@ public final class DecisiveDenial extends CardImpl { .setText("target creature you control fights target creature you don't control. " + "(Each deals damage equal to its power to the other.)")); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); // • Counter target noncreature spell unless its controller pays {3}. Mode mode = new Mode(new CounterUnlessPaysEffect(new GenericManaCost(3))); diff --git a/Mage.Sets/src/mage/cards/d/DecodeTransmissions.java b/Mage.Sets/src/mage/cards/d/DecodeTransmissions.java new file mode 100644 index 00000000000..7e9b55d24d6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DecodeTransmissions.java @@ -0,0 +1,45 @@ +package mage.cards.d; + +import mage.abilities.condition.common.VoidCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.watchers.common.VoidWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DecodeTransmissions extends CardImpl { + + public DecodeTransmissions(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); + + // You draw two cards and lose 2 life. + // Void -- If a nonland permanent left the battlefield this turn or a spell was warped this turn, instead you draw two cards and each opponent loses 2 life. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2, true)); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new LoseLifeOpponentsEffect(2), new LoseLifeSourceControllerEffect(2), + VoidCondition.instance, "and lose 2 life.
" + AbilityWord.VOID.formatWord() + + "If a nonland permanent left the battlefield this turn or a spell was warped this turn, " + + "instead you draw two cards and each opponent loses 2 life" + )); + this.getSpellAbility().addHint(VoidCondition.getHint()); + this.getSpellAbility().addWatcher(new VoidWatcher()); + } + + private DecodeTransmissions(final DecodeTransmissions card) { + super(card); + } + + @Override + public DecodeTransmissions copy() { + return new DecodeTransmissions(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/Decomposition.java b/Mage.Sets/src/mage/cards/d/Decomposition.java index 521456ac0c8..8fbe385fa0b 100644 --- a/Mage.Sets/src/mage/cards/d/Decomposition.java +++ b/Mage.Sets/src/mage/cards/d/Decomposition.java @@ -36,7 +36,7 @@ public final class Decomposition extends CardImpl { this.subtype.add(SubType.AURA); // Enchant black creature - TargetPermanent auraTarget = new TargetCreaturePermanent(filter); + TargetPermanent auraTarget = new TargetPermanent(filter); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); this.addAbility(new EnchantAbility(auraTarget)); diff --git a/Mage.Sets/src/mage/cards/d/DeepwaterHypnotist.java b/Mage.Sets/src/mage/cards/d/DeepwaterHypnotist.java index 35021e43a5d..28f5f23770a 100644 --- a/Mage.Sets/src/mage/cards/d/DeepwaterHypnotist.java +++ b/Mage.Sets/src/mage/cards/d/DeepwaterHypnotist.java @@ -12,8 +12,11 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Duration; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -30,7 +33,7 @@ public final class DeepwaterHypnotist extends CardImpl { // Inspired — Whenever Deepwater Hypnotist becomes untapped, target creature an opponent controls gets -3/-0 until end of turn. Ability ability = new InspiredAbility(new BoostTargetEffect(-3,0,Duration.EndOfTurn)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/Defeat.java b/Mage.Sets/src/mage/cards/d/Defeat.java index 8c281809849..9b85431acd7 100644 --- a/Mage.Sets/src/mage/cards/d/Defeat.java +++ b/Mage.Sets/src/mage/cards/d/Defeat.java @@ -9,6 +9,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -28,7 +29,7 @@ public final class Defeat extends CardImpl { // Destroy target creature with power 2 or less. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private Defeat(final Defeat card) { diff --git a/Mage.Sets/src/mage/cards/d/DefendersOfHumanity.java b/Mage.Sets/src/mage/cards/d/DefendersOfHumanity.java index e20d84241bd..d79a39f35fb 100644 --- a/Mage.Sets/src/mage/cards/d/DefendersOfHumanity.java +++ b/Mage.Sets/src/mage/cards/d/DefendersOfHumanity.java @@ -17,7 +17,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.permanent.token.WhiteAstartesWarriorToken; @@ -29,7 +28,8 @@ import java.util.UUID; public final class DefendersOfHumanity extends CardImpl { private static final Condition condition = new CompoundCondition( - "you control no creatures and only during your turn", MyTurnCondition.instance, + "you control no creatures and only during your turn", + MyTurnCondition.instance, new PermanentsOnTheBattlefieldCondition( StaticFilters.FILTER_PERMANENT_CREATURE, ComparisonType.EQUAL_TO, 0, true @@ -46,13 +46,12 @@ public final class DefendersOfHumanity extends CardImpl { // {X}{2}{W}, Exile Defenders of Humanity: Create X 2/2 white Astartes Warrior creature tokens with vigilance. Activate only if you control no creatures and only during your turn. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new CreateTokenEffect( - new WhiteAstartesWarriorToken(), mage.abilities.dynamicvalue.common.GetXValue.instance + new WhiteAstartesWarriorToken(), GetXValue.instance ), new ManaCostsImpl<>("{X}{2}{W}"), condition - ).addHint(CreaturesYouControlHint.instance).addHint(MyTurnHint.instance); + ); ability.addCost(new ExileSourceCost()); - this.addAbility(ability); + this.addAbility(ability.addHint(CreaturesYouControlHint.instance).addHint(MyTurnHint.instance)); } private DefendersOfHumanity(final DefendersOfHumanity card) { diff --git a/Mage.Sets/src/mage/cards/d/DefenseOfTheHeart.java b/Mage.Sets/src/mage/cards/d/DefenseOfTheHeart.java index 7c5aa889e76..7278452a172 100644 --- a/Mage.Sets/src/mage/cards/d/DefenseOfTheHeart.java +++ b/Mage.Sets/src/mage/cards/d/DefenseOfTheHeart.java @@ -1,36 +1,40 @@ package mage.cards.d; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.filter.StaticFilters; -import mage.game.Game; +import mage.filter.common.FilterOpponentsCreaturePermanent; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author Plopman */ public final class DefenseOfTheHeart extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterOpponentsCreaturePermanent("an opponent controls three or more creatures"), + ComparisonType.MORE_THAN, 2 + ); + public DefenseOfTheHeart(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); // At the beginning of your upkeep, if an opponent controls three or more creatures, sacrifice Defense of the Heart, search your library for up to two creature cards, and put those cards onto the battlefield. Then shuffle your library. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceEffect()); - ability.addEffect(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(0, 2, StaticFilters.FILTER_CARD_CREATURE), false)); - DefenseOfTheHeartCondition contition = new DefenseOfTheHeartCondition(); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, contition, "At the beginning of your upkeep, if an opponent controls three or more creatures, sacrifice {this}, search your library for up to two creature cards, put those cards onto the battlefield, then shuffle")); - + Ability ability = new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceEffect()).withInterveningIf(condition); + ability.addEffect(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary( + 0, 2, StaticFilters.FILTER_CARD_CREATURES + )).concatBy(",")); + this.addAbility(ability); } private DefenseOfTheHeart(final DefenseOfTheHeart card) { @@ -41,18 +45,4 @@ public final class DefenseOfTheHeart extends CardImpl { public DefenseOfTheHeart copy() { return new DefenseOfTheHeart(this); } - - static class DefenseOfTheHeartCondition implements Condition { - - @Override - public boolean apply(Game game, Ability source) { - Set opponents = game.getOpponents(source.getControllerId()); - for (UUID uuid : opponents) { - if (game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, uuid, game) >= 3) { - return true; - } - } - return false; - } - } } diff --git a/Mage.Sets/src/mage/cards/d/DefiantGreatmaw.java b/Mage.Sets/src/mage/cards/d/DefiantGreatmaw.java index 7731c6c3471..48df4f2c41f 100644 --- a/Mage.Sets/src/mage/cards/d/DefiantGreatmaw.java +++ b/Mage.Sets/src/mage/cards/d/DefiantGreatmaw.java @@ -17,6 +17,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; import mage.game.events.GameEvent; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; @@ -64,7 +65,7 @@ class DefiantGreatmawTriggeredAbility extends TriggeredAbilityImpl { DefiantGreatmawTriggeredAbility() { super(Zone.BATTLEFIELD, new RemoveCounterTargetEffect(CounterType.M1M1.createInstance(1)), false); - this.addTarget(new TargetCreaturePermanent(filter)); + this.addTarget(new TargetPermanent(filter)); } private DefiantGreatmawTriggeredAbility(final DefiantGreatmawTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/d/DegaSanctuary.java b/Mage.Sets/src/mage/cards/d/DegaSanctuary.java index 6d1b49c3aee..c127a371083 100644 --- a/Mage.Sets/src/mage/cards/d/DegaSanctuary.java +++ b/Mage.Sets/src/mage/cards/d/DegaSanctuary.java @@ -1,17 +1,15 @@ - package mage.cards.d; -import java.util.UUID; import mage.ObjectColor; -import mage.abilities.Ability; -import mage.abilities.common.SanctuaryInterveningIfTriggeredAbility; +import mage.abilities.common.SanctuaryTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class DegaSanctuary extends CardImpl { @@ -20,12 +18,10 @@ public final class DegaSanctuary extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); // At the beginning of your upkeep, if you control a black or red permanent, you gain 2 life. If you control a black permanent and a red permanent, you gain 4 life instead. - Ability ability = new SanctuaryInterveningIfTriggeredAbility( + this.addAbility(new SanctuaryTriggeredAbility( new GainLifeEffect(2), new GainLifeEffect(4), ObjectColor.BLACK, ObjectColor.RED, - "At the beginning of your upkeep, if you control a black or red permanent, you gain 2 life. " - + "If you control a black permanent and a red permanent, you gain 4 life instead." - ); - this.addAbility(ability); + "you gain 2 life. If you control a black permanent and a red permanent, you gain 4 life instead." + )); } private DegaSanctuary(final DegaSanctuary card) { diff --git a/Mage.Sets/src/mage/cards/d/Degavolver.java b/Mage.Sets/src/mage/cards/d/Degavolver.java index ca554f5db41..753be670bad 100644 --- a/Mage.Sets/src/mage/cards/d/Degavolver.java +++ b/Mage.Sets/src/mage/cards/d/Degavolver.java @@ -1,7 +1,6 @@ package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -16,11 +15,12 @@ import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; import mage.counters.CounterType; +import java.util.UUID; + /** * * @author Loki @@ -41,16 +41,16 @@ public final class Degavolver extends CardImpl { // If Degavolver was kicked with its {1}{B} kicker, it enters with two +1/+1 counters on it and with "Pay 3 life: Regenerate Degavolver." EntersBattlefieldAbility ability1 = new EntersBattlefieldAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance(2),false), - new KickedCostCondition("{1}{B}"), "If Degavolver was kicked with its {1}{B} kicker, it enters with two +1/+1 counters on it and with \"Pay 3 life: Regenerate Degavolver.\"", - "{this} enters with two +1/+1 counters on it and with \"Pay 3 life: Regenerate Degavolver.\""); + new AddCountersSourceEffect(CounterType.P1P1.createInstance(2), false), + new KickedCostCondition("{1}{B}"), "If {this} was kicked with its {1}{B} kicker, it enters with two +1/+1 counters on it and with \"Pay 3 life: Regenerate this creature.\"", + "{this} enters with two +1/+1 counters on it and with \"Pay 3 life: Regenerate this creature.\""); ((EntersBattlefieldEffect)ability1.getEffects().get(0)).addEffect(new GainAbilitySourceEffect(new SimpleActivatedAbility(new RegenerateSourceEffect(), new PayLifeCost(3)), Duration.WhileOnBattlefield)); this.addAbility(ability1); // If Degavolver was kicked with its {R} kicker, it enters with a +1/+1 counter on it and with first strike. EntersBattlefieldAbility ability2 = new EntersBattlefieldAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance(1),false), new KickedCostCondition("{R}"), - "If Degavolver was kicked with its {R} kicker, it enters with a +1/+1 counter on it and with first strike.", + new AddCountersSourceEffect(CounterType.P1P1.createInstance(1), false), new KickedCostCondition("{R}"), + "If {this} was kicked with its {R} kicker, it enters with a +1/+1 counter on it and with first strike.", "{this} enters with a +1/+1 counter on it and with first strike"); ((EntersBattlefieldEffect)ability2.getEffects().get(0)).addEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield)); this.addAbility(ability2); diff --git a/Mage.Sets/src/mage/cards/d/Delirium.java b/Mage.Sets/src/mage/cards/d/Delirium.java index 62cc5e30fe6..7ec4f49004d 100644 --- a/Mage.Sets/src/mage/cards/d/Delirium.java +++ b/Mage.Sets/src/mage/cards/d/Delirium.java @@ -17,6 +17,7 @@ import mage.filter.predicate.permanent.ControllerIsActivePlayerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -40,7 +41,7 @@ public final class Delirium extends CardImpl { this.addAbility(new CastOnlyIfConditionIsTrueAbility(OnOpponentsTurnCondition.instance, "Cast this spell only during an opponent's turn.")); // Tap target creature that player controls. That creature deals damage equal to its power to the player. Prevent all combat damage that would be dealt to and dealt by the creature this turn. this.getSpellAbility().addEffect(new TapTargetEffect("tap target creature that player controls")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DeliriumEffect()); this.getSpellAbility().addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, true).setText("Prevent all combat damage that would be dealt to")); this.getSpellAbility().addEffect(new PreventDamageByTargetEffect(Duration.EndOfTurn, true).setText("and dealt by the creature this turn.")); diff --git a/Mage.Sets/src/mage/cards/d/DementiaSliver.java b/Mage.Sets/src/mage/cards/d/DementiaSliver.java index 92b47218904..5a5a50ed8e2 100644 --- a/Mage.Sets/src/mage/cards/d/DementiaSliver.java +++ b/Mage.Sets/src/mage/cards/d/DementiaSliver.java @@ -10,10 +10,13 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseACardNameEffect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.cards.*; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetOpponent; @@ -39,12 +42,15 @@ public final class DementiaSliver extends CardImpl { this.toughness = new MageInt(3); // All Slivers have "{T}: Name a card. Target opponent reveals a card at random from their hand. If it's the named card, that player discards it. Activate this ability only during your turn." - Ability gainedAbility = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new ChooseACardNameEffect(ChooseACardNameEffect.TypeOfName.ALL), new TapSourceCost(), MyTurnCondition.instance); + Ability gainedAbility = new ActivateIfConditionActivatedAbility( + new ChooseACardNameEffect(ChooseACardNameEffect.TypeOfName.ALL), + new TapSourceCost(), MyTurnCondition.instance + ); gainedAbility.addEffect(new DementiaSliverEffect()); gainedAbility.addTarget(new TargetOpponent()); - gainedAbility.addHint(MyTurnHint.instance); this.addAbility(new SimpleStaticAbility( - new GainAbilityAllEffect(gainedAbility, Duration.WhileOnBattlefield, filter, + new GainAbilityAllEffect( + gainedAbility, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_ALL_SLIVERS, "All Slivers have \"{T}: Choose a card name. " + "Target opponent reveals a card at random from their hand." + " If that card has the chosen name, that player discards it." @@ -67,7 +73,7 @@ class DementiaSliverEffect extends OneShotEffect { DementiaSliverEffect() { super(Outcome.Damage); - staticText = "Target opponent reveals a card at random from their hand. If that card has the chose name, that player discards it"; + staticText = "Target opponent reveals a card at random from their hand. If that card has the chosen name, that player discards it"; } private DementiaSliverEffect(final DementiaSliverEffect effect) { diff --git a/Mage.Sets/src/mage/cards/d/DemolisherSpawn.java b/Mage.Sets/src/mage/cards/d/DemolisherSpawn.java index 952cff306cb..7fd32cd0fad 100644 --- a/Mage.Sets/src/mage/cards/d/DemolisherSpawn.java +++ b/Mage.Sets/src/mage/cards/d/DemolisherSpawn.java @@ -3,7 +3,6 @@ package mage.cards.d; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.keyword.HasteAbility; @@ -37,13 +36,9 @@ public final class DemolisherSpawn extends CardImpl { this.addAbility(HasteAbility.getInstance()); // Delirium -- Whenever Demolisher Spawn attacks, if there are four or more card types among cards in your graveyard, other attacking creatures get +4/+4 until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new BoostAllEffect( - 4, 4, Duration.EndOfTurn, - StaticFilters.FILTER_ATTACKING_CREATURES, true - )), DeliriumCondition.instance, "Whenever {this} attacks, if there are four or more " + - "card types among cards in your graveyard, other attacking creatures get +4/+4 until end of turn." - ).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); + this.addAbility(new AttacksTriggeredAbility(new BoostAllEffect( + 4, 4, Duration.EndOfTurn, StaticFilters.FILTER_ATTACKING_CREATURES, true + )).withInterveningIf(DeliriumCondition.instance).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); } private DemolisherSpawn(final DemolisherSpawn card) { diff --git a/Mage.Sets/src/mage/cards/d/DemonicCovenant.java b/Mage.Sets/src/mage/cards/d/DemonicCovenant.java index 02be019387c..0ab82065414 100644 --- a/Mage.Sets/src/mage/cards/d/DemonicCovenant.java +++ b/Mage.Sets/src/mage/cards/d/DemonicCovenant.java @@ -1,7 +1,7 @@ package mage.cards.d; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.AttacksPlayerWithCreaturesTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -12,12 +12,11 @@ import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.SetTargetPointer; import mage.constants.SubType; -import mage.constants.Zone; -import mage.game.Controllable; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.game.Game; -import mage.game.events.DefenderAttackedEvent; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.permanent.token.DemonToken; import mage.players.Player; @@ -30,6 +29,7 @@ import java.util.UUID; * @author TheElk801 */ public final class DemonicCovenant extends CardImpl { + FilterPermanent filter = new FilterControlledPermanent(SubType.DEMON,"Demons you control"); public DemonicCovenant(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.KINDRED, CardType.ENCHANTMENT}, "{4}{B}{B}"); @@ -37,12 +37,14 @@ public final class DemonicCovenant extends CardImpl { this.subtype.add(SubType.DEMON); // Whenever one or more Demons you control attack a player, you draw a card and lose 1 life. - this.addAbility(new DemonicCovenantTriggeredAbility()); + Ability abilityAttack = new AttacksPlayerWithCreaturesTriggeredAbility(new DrawCardSourceControllerEffect(1, true), filter, SetTargetPointer.NONE); + abilityAttack.addEffect(new LoseLifeSourceControllerEffect(1).setText("and lose 1 life")); + this.addAbility(abilityAttack); // At the beginning of your end step, create a 5/5 black Demon creature token with flying, then mill two cards. If two cards that share all their card types were milled this way, sacrifice Demonic Covenant. - Ability ability = new BeginningOfEndStepTriggeredAbility(new CreateTokenEffect(new DemonToken())); - ability.addEffect(new DemonicCovenantEffect()); - this.addAbility(ability); + Ability abilityEndStep = new BeginningOfEndStepTriggeredAbility(new CreateTokenEffect(new DemonToken())); + abilityEndStep.addEffect(new DemonicCovenantEffect()); + this.addAbility(abilityEndStep); } private DemonicCovenant(final DemonicCovenant card) { @@ -55,40 +57,6 @@ public final class DemonicCovenant extends CardImpl { } } -class DemonicCovenantTriggeredAbility extends TriggeredAbilityImpl { - - DemonicCovenantTriggeredAbility() { - super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1, true)); - this.addEffect(new LoseLifeSourceControllerEffect(1).setText("and lose 1 life")); - this.setTriggerPhrase("Whenever one or more Demons you control attack a player, "); - } - - private DemonicCovenantTriggeredAbility(final DemonicCovenantTriggeredAbility ability) { - super(ability); - } - - @Override - public DemonicCovenantTriggeredAbility copy() { - return new DemonicCovenantTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DEFENDER_ATTACKED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - return game.getPlayer(event.getTargetId()) != null - && ((DefenderAttackedEvent) event) - .getAttackers(game) - .stream() - .filter(permanent -> permanent.hasSubtype(SubType.DEMON, game)) - .map(Controllable::getControllerId) - .anyMatch(this::isControlledBy); - } -} - class DemonicCovenantEffect extends OneShotEffect { DemonicCovenantEffect() { diff --git a/Mage.Sets/src/mage/cards/d/DemonicRising.java b/Mage.Sets/src/mage/cards/d/DemonicRising.java index 8ded22ba9d3..b60875f6ba6 100644 --- a/Mage.Sets/src/mage/cards/d/DemonicRising.java +++ b/Mage.Sets/src/mage/cards/d/DemonicRising.java @@ -1,31 +1,33 @@ - package mage.cards.d; -import java.util.UUID; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.abilities.condition.common.CreatureCountCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.TargetController; +import mage.constants.ComparisonType; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.permanent.token.DemonToken; +import java.util.UUID; + /** * @author noxx */ public final class DemonicRising extends CardImpl { - private static final String ruleText = "At the beginning of your end step, if you control exactly one creature, create a 5/5 black Demon creature token with flying"; + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledCreaturePermanent("you control exactly one creature"), + ComparisonType.EQUAL_TO, 1 + ); public DemonicRising(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}{B}"); // At the beginning of your end step, if you control exactly one creature, create a 5/5 black Demon creature token with flying. - TriggeredAbility ability = new BeginningOfEndStepTriggeredAbility(new CreateTokenEffect(new DemonToken())); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new CreatureCountCondition(1, TargetController.YOU), ruleText)); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new CreateTokenEffect(new DemonToken())).withInterveningIf(condition)); } private DemonicRising(final DemonicRising card) { diff --git a/Mage.Sets/src/mage/cards/d/DenryKlinEditorInChief.java b/Mage.Sets/src/mage/cards/d/DenryKlinEditorInChief.java index 5e2adce6336..94b6e76573d 100644 --- a/Mage.Sets/src/mage/cards/d/DenryKlinEditorInChief.java +++ b/Mage.Sets/src/mage/cards/d/DenryKlinEditorInChief.java @@ -3,9 +3,8 @@ package mage.cards.d; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.condition.common.SourceHasCountersCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCounterChoiceSourceEffect; import mage.cards.CardImpl; @@ -43,14 +42,9 @@ public class DenryKlinEditorInChief extends CardImpl { // Whenever a nontoken creature you control enters, // if Denry has counters on it, put the same number of each kind of counter on that creature. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldControlledTriggeredAbility( - new DenryKlinEditorInChiefCopyCountersEffect(), - StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN), - SourceHasCountersCondition.instance, - "Whenever a nontoken creature you control enters, " + - "if Denry has counters on it, put the same number of each kind of counter on that creature.") - ); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new DenryKlinEditorInChiefCopyCountersEffect(), StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN + ).withInterveningIf(SourceHasCountersCondition.instance)); } @@ -68,6 +62,7 @@ class DenryKlinEditorInChiefCopyCountersEffect extends OneShotEffect { DenryKlinEditorInChiefCopyCountersEffect() { super(Outcome.Benefit); + staticText = "put the same number of each kind of counter on that creature"; } @Override diff --git a/Mage.Sets/src/mage/cards/d/DepartedDeckhand.java b/Mage.Sets/src/mage/cards/d/DepartedDeckhand.java index eb731ca38e6..1d26fc870d3 100644 --- a/Mage.Sets/src/mage/cards/d/DepartedDeckhand.java +++ b/Mage.Sets/src/mage/cards/d/DepartedDeckhand.java @@ -1,6 +1,6 @@ package mage.cards.d; -import java.util.UUID; +import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BecomesTargetSourceTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -9,20 +9,19 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; -import mage.target.common.TargetControlledCreaturePermanent; -import mage.MageInt; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class DepartedDeckhand extends CardImpl { @@ -63,7 +62,7 @@ public final class DepartedDeckhand extends CardImpl { ).setText("Another target creature you control can't be blocked this turn except by Spirits"), new ManaCostsImpl<>("{3}{U}") ); - ability.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/Desert.java b/Mage.Sets/src/mage/cards/d/Desert.java index 65f2fdb2149..27aee857b66 100644 --- a/Mage.Sets/src/mage/cards/d/Desert.java +++ b/Mage.Sets/src/mage/cards/d/Desert.java @@ -1,45 +1,47 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.PhaseStep; -import mage.constants.Zone; +import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AttackingPredicate; -import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Desert extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking creature"); + static { filter.add(AttackingPredicate.instance); } + private static final Condition condition = new IsStepCondition(PhaseStep.END_COMBAT, false); + public Desert(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); this.subtype.add(SubType.DESERT); // {tap}: Add {C}. this.addAbility(new ColorlessManaAbility()); + // {tap}: Desert deals 1 damage to target attacking creature. Activate this ability only during the end of combat step. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new TapSourceCost(), new IsStepCondition(PhaseStep.END_COMBAT, false)); - Target target = new TargetCreaturePermanent(filter); - ability.addTarget(target); + Ability ability = new ActivateIfConditionActivatedAbility(new DamageTargetEffect(1), new TapSourceCost(), condition); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DesertsHold.java b/Mage.Sets/src/mage/cards/d/DesertsHold.java index 77e2c8f086c..4253a1dc1d3 100644 --- a/Mage.Sets/src/mage/cards/d/DesertsHold.java +++ b/Mage.Sets/src/mage/cards/d/DesertsHold.java @@ -3,7 +3,6 @@ package mage.cards.d; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.DesertControlledOrGraveyardCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.combat.CantBlockAttackActivateAttachedEffect; @@ -35,11 +34,9 @@ public final class DesertsHold extends CardImpl { this.addAbility(new EnchantAbility(auraTarget)); // When Desert's Hold enters the battlefield, if you control a Desert or there is a Desert card in your graveyard, you gain 3 life. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3)), - DesertControlledOrGraveyardCondition.instance, "When {this} enters, " + - "if you control a Desert or there is a Desert card in your graveyard, you gain 3 life." - ).addHint(DesertControlledOrGraveyardCondition.getHint())); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3)) + .withInterveningIf(DesertControlledOrGraveyardCondition.instance) + .addHint(DesertControlledOrGraveyardCondition.getHint())); // Enchanted creature can't attack or block, and its activated abilities can't be activated. this.addAbility(new SimpleStaticAbility(new CantBlockAttackActivateAttachedEffect())); diff --git a/Mage.Sets/src/mage/cards/d/DesiccatedNaga.java b/Mage.Sets/src/mage/cards/d/DesiccatedNaga.java index a429b6637d3..134a3c0679e 100644 --- a/Mage.Sets/src/mage/cards/d/DesiccatedNaga.java +++ b/Mage.Sets/src/mage/cards/d/DesiccatedNaga.java @@ -3,6 +3,7 @@ package mage.cards.d; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.GainLifeEffect; @@ -11,8 +12,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterPlaneswalkerPermanent; +import mage.filter.common.FilterControlledPlaneswalkerPermanent; import mage.target.common.TargetOpponent; import java.util.UUID; @@ -22,11 +22,7 @@ import java.util.UUID; */ public final class DesiccatedNaga extends CardImpl { - private static final FilterPlaneswalkerPermanent filter = new FilterPlaneswalkerPermanent("you control a Liliana planeswalker"); - - static { - filter.add(SubType.LILIANA.getPredicate()); - } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(new FilterControlledPlaneswalkerPermanent(SubType.LILIANA, "you control a Liliana planeswalker")); public DesiccatedNaga(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); @@ -37,10 +33,9 @@ public final class DesiccatedNaga extends CardImpl { this.toughness = new MageInt(2); // {3}{B}: Target opponent loses 2 life and you gain 2 life. Activate this ability only if you control a Liliana planeswalker. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new LoseLifeTargetEffect(2), - new ManaCostsImpl<>("{3}{B}"), - new PermanentsOnTheBattlefieldCondition(filter)); + Ability ability = new ActivateIfConditionActivatedAbility( + new LoseLifeTargetEffect(2), new ManaCostsImpl<>("{3}{B}"), condition + ); ability.addEffect(new GainLifeEffect(2).concatBy("and")); ability.addTarget(new TargetOpponent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/d/DestroyEvil.java b/Mage.Sets/src/mage/cards/d/DestroyEvil.java index 3c9e218e07a..6faf4381ac8 100644 --- a/Mage.Sets/src/mage/cards/d/DestroyEvil.java +++ b/Mage.Sets/src/mage/cards/d/DestroyEvil.java @@ -10,6 +10,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ToughnessPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetEnchantmentPermanent; @@ -31,7 +32,7 @@ public final class DestroyEvil extends CardImpl { // Choose one-- // * Destroy target creature with toughness 4 or greater. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // * Destroy target enchantment. Mode mode = new Mode(new DestroyTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/d/DetectivesSatchel.java b/Mage.Sets/src/mage/cards/d/DetectivesSatchel.java index 12357dd83fc..384f1f7edd1 100644 --- a/Mage.Sets/src/mage/cards/d/DetectivesSatchel.java +++ b/Mage.Sets/src/mage/cards/d/DetectivesSatchel.java @@ -3,7 +3,7 @@ package mage.cards.d; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.SacrificedArtifactThisTurnCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.keyword.InvestigateEffect; import mage.cards.CardImpl; @@ -26,7 +26,7 @@ public final class DetectivesSatchel extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new InvestigateEffect(2))); // {T}: Create a 1/1 colorless Thopter artifact creature token with flying. Activate only if you've sacrificed an artifact this turn. - this.addAbility(new ConditionalActivatedAbility( + this.addAbility(new ActivateIfConditionActivatedAbility( new CreateTokenEffect(new ThopterColorlessToken()), new TapSourceCost(), SacrificedArtifactThisTurnCondition.instance ).addHint(SacrificedArtifactThisTurnCondition.getHint()), new PermanentsSacrificedWatcher()); diff --git a/Mage.Sets/src/mage/cards/d/DeusOfCalamity.java b/Mage.Sets/src/mage/cards/d/DeusOfCalamity.java index 9c5a614d177..321aaca1eca 100644 --- a/Mage.Sets/src/mage/cards/d/DeusOfCalamity.java +++ b/Mage.Sets/src/mage/cards/d/DeusOfCalamity.java @@ -10,13 +10,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterLandPermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.events.GameEvent; -import mage.target.Target; -import mage.target.TargetPermanent; +import mage.target.common.TargetLandPermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; +import mage.target.targetpointer.FixedTarget; import java.util.UUID; @@ -53,6 +51,8 @@ class DeusOfCalamityTriggeredAbility extends TriggeredAbilityImpl { public DeusOfCalamityTriggeredAbility() { super(Zone.BATTLEFIELD, new DestroyTargetEffect(), false); + addTarget(new TargetLandPermanent()); + setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); } private DeusOfCalamityTriggeredAbility(final DeusOfCalamityTriggeredAbility ability) { @@ -74,11 +74,7 @@ class DeusOfCalamityTriggeredAbility extends TriggeredAbilityImpl { if (event.getSourceId().equals(this.getSourceId()) && event.getAmount() > 5 && game.getOpponents(this.getControllerId()).contains(event.getTargetId())) { - FilterPermanent filter = new FilterLandPermanent("land of the damaged player"); - filter.add(new ControllerIdPredicate(event.getTargetId())); - Target target = new TargetPermanent(filter); - this.getTargets().clear(); - this.addTarget(target); + this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game)); return true; } return false; @@ -86,6 +82,6 @@ class DeusOfCalamityTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever Deus of Calamity deals 6 or more damage to an opponent, destroy target land that player controls."; + return "Whenever {this} deals 6 or more damage to an opponent, destroy target land that player controls."; } } diff --git a/Mage.Sets/src/mage/cards/d/DiamondCity.java b/Mage.Sets/src/mage/cards/d/DiamondCity.java index c39088f9cb4..9df99ce625c 100644 --- a/Mage.Sets/src/mage/cards/d/DiamondCity.java +++ b/Mage.Sets/src/mage/cards/d/DiamondCity.java @@ -5,7 +5,7 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; @@ -16,7 +16,6 @@ import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; @@ -27,7 +26,6 @@ import java.util.List; import java.util.UUID; /** - * * @author notgreat */ public final class DiamondCity extends CardImpl { @@ -46,11 +44,12 @@ public final class DiamondCity extends CardImpl { this.addAbility(new ColorlessManaAbility()); // {T}: Move a shield counter from Diamond City onto target creature. Activate only if two or more creatures entered the battlefield under your control this turn. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new MoveCountersFromSourceToTargetEffect(CounterType.SHIELD), - new TapSourceCost(), DiamondCityCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new MoveCountersFromSourceToTargetEffect(CounterType.SHIELD), + new TapSourceCost(), DiamondCityCondition.instance + ); ability.addTarget(new TargetCreaturePermanent()); - ability.addHint(DiamondCityCreaturesThatEnteredThisTurnCount.getHint()); - this.addAbility(ability, new PermanentsEnteredBattlefieldWatcher()); + this.addAbility(ability.addHint(DiamondCityCreaturesThatEnteredThisTurnCount.getHint()), new PermanentsEnteredBattlefieldWatcher()); } private DiamondCity(final DiamondCity card) { diff --git a/Mage.Sets/src/mage/cards/d/DiaochanArtfulBeauty.java b/Mage.Sets/src/mage/cards/d/DiaochanArtfulBeauty.java index f1ae94a56c6..5f431d70650 100644 --- a/Mage.Sets/src/mage/cards/d/DiaochanArtfulBeauty.java +++ b/Mage.Sets/src/mage/cards/d/DiaochanArtfulBeauty.java @@ -5,16 +5,16 @@ import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.MyTurnBeforeAttackersDeclaredCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponentsChoicePermanent; +import mage.target.targetpointer.EachTargetPointer; import java.util.UUID; @@ -33,9 +33,16 @@ public final class DiaochanArtfulBeauty extends CardImpl { this.toughness = new MageInt(1); // {tap}: Destroy target creature of your choice, then destroy target creature of an opponent's choice. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new DiaochanArtfulBeautyDestroyEffect(), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DestroyTargetEffect() + .setTargetPointer(new EachTargetPointer()) + .setText("destroy target creature of your choice, then destroy target creature of an opponent's choice"), + new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance + ); ability.addTarget(new TargetCreaturePermanent()); - ability.addTarget(new TargetOpponentsChoicePermanent(1, 1, StaticFilters.FILTER_PERMANENT_CREATURE, false)); + ability.addTarget(new TargetOpponentsChoicePermanent( + 1, 1, StaticFilters.FILTER_PERMANENT_CREATURE, false + )); this.addAbility(ability); } @@ -48,38 +55,3 @@ public final class DiaochanArtfulBeauty extends CardImpl { return new DiaochanArtfulBeauty(this); } } - -class DiaochanArtfulBeautyDestroyEffect extends OneShotEffect { - - DiaochanArtfulBeautyDestroyEffect() { - super(Outcome.DestroyPermanent); - this.staticText = "Destroy target creature of your choice, then destroy target creature of an opponent's choice"; - } - - private DiaochanArtfulBeautyDestroyEffect(final DiaochanArtfulBeautyDestroyEffect effect) { - super(effect); - } - - @Override - public DiaochanArtfulBeautyDestroyEffect copy() { - return new DiaochanArtfulBeautyDestroyEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent firstTarget = game.getPermanent(source.getFirstTarget()); - if (firstTarget != null) { - firstTarget.destroy(source, game, false); - - } - Permanent secondTarget = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - if (secondTarget != null) { - secondTarget.destroy(source, game, false); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DihadaBinderOfWills.java b/Mage.Sets/src/mage/cards/d/DihadaBinderOfWills.java index 9ea7e36b145..dc1696e2297 100644 --- a/Mage.Sets/src/mage/cards/d/DihadaBinderOfWills.java +++ b/Mage.Sets/src/mage/cards/d/DihadaBinderOfWills.java @@ -19,7 +19,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.token.TreasureToken; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -51,7 +51,7 @@ public final class DihadaBinderOfWills extends CardImpl { ability.addEffect(new GainAbilityTargetEffect( IndestructibleAbility.getInstance(), Duration.UntilYourNextTurn ).setText(", and indestructible until your next turn.")); - ability.addTarget(new TargetCreaturePermanent(0, 1, filter, false)); + ability.addTarget(new TargetPermanent(0, 1, filter)); this.addAbility(ability); // -3: Reveal the top four cards of your library. diff --git a/Mage.Sets/src/mage/cards/d/DiminisherWitch.java b/Mage.Sets/src/mage/cards/d/DiminisherWitch.java index 2a439102f96..b9420c50703 100644 --- a/Mage.Sets/src/mage/cards/d/DiminisherWitch.java +++ b/Mage.Sets/src/mage/cards/d/DiminisherWitch.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.BargainedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateRoleAttachedTargetEffect; import mage.abilities.hint.common.BargainCostWasPaidHint; import mage.abilities.keyword.BargainAbility; @@ -34,11 +33,8 @@ public final class DiminisherWitch extends CardImpl { this.addAbility(new BargainAbility()); // When Diminisher Witch enters the battlefield, if it was bargained, create a Cursed Role token attached to target creature an opponent controls. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CreateRoleAttachedTargetEffect(RoleType.CURSED)), - BargainedCondition.instance, "When {this} enters, if it was bargained, " + - "create a Cursed Role token attached to target creature an opponent controls." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new CreateRoleAttachedTargetEffect(RoleType.CURSED)) + .withInterveningIf(BargainedCondition.instance); ability.addTarget(new TargetOpponentsCreaturePermanent()); this.addAbility(ability.addHint(BargainCostWasPaidHint.instance)); } diff --git a/Mage.Sets/src/mage/cards/d/DimirCharm.java b/Mage.Sets/src/mage/cards/d/DimirCharm.java index e17f78a2a69..a102a832ab3 100644 --- a/Mage.Sets/src/mage/cards/d/DimirCharm.java +++ b/Mage.Sets/src/mage/cards/d/DimirCharm.java @@ -19,6 +19,7 @@ import mage.filter.predicate.mageobject.PowerPredicate; import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; +import mage.target.TargetPermanent; import mage.target.TargetPlayer; import mage.target.TargetSpell; import mage.target.common.TargetCreaturePermanent; @@ -46,7 +47,7 @@ public final class DimirCharm extends CardImpl { //or destroy target creature with power 2 or less Mode mode1 = new Mode(new DestroyTargetEffect()); - mode1.addTarget(new TargetCreaturePermanent(filterCreature)); + mode1.addTarget(new TargetPermanent(filterCreature)); this.getSpellAbility().addMode(mode1); //or look at the top three cards of target player's library, then put one back and the rest into that player's graveyard diff --git a/Mage.Sets/src/mage/cards/d/DimirStrandcatcher.java b/Mage.Sets/src/mage/cards/d/DimirStrandcatcher.java new file mode 100644 index 00000000000..9f2c5e97a3d --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DimirStrandcatcher.java @@ -0,0 +1,174 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.players.Player; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DimirStrandcatcher extends CardImpl { + + public DimirStrandcatcher(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U/B}{U/B}"); + + this.subtype.add(SubType.FAERIE); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever you attack, surveil X, where X is the number of opponents being attacked. + this.addAbility(new AttacksWithCreaturesTriggeredAbility(new DimirStrandcatcherEffect(), 1)); + + // At the beginning of each end step, if three or more cards were put into your graveyard from anywhere other than the battlefield this turn, draw a card. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.EACH_PLAYER, new DrawCardSourceControllerEffect(1), + false, DimirStrandcatcherCondition.instance + ).addHint(DimirStrandcatcherValue.getHint()), new DimirStrandcatcherWatcher()); + } + + private DimirStrandcatcher(final DimirStrandcatcher card) { + super(card); + } + + @Override + public DimirStrandcatcher copy() { + return new DimirStrandcatcher(this); + } +} + +class DimirStrandcatcherEffect extends OneShotEffect { + + DimirStrandcatcherEffect() { + super(Outcome.Benefit); + staticText = "surveil X, where X is the number of opponents being attacked"; + } + + private DimirStrandcatcherEffect(final DimirStrandcatcherEffect effect) { + super(effect); + } + + @Override + public DimirStrandcatcherEffect copy() { + return new DimirStrandcatcherEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int count = game + .getOpponents(source.getControllerId()) + .stream() + .filter(game.getCombat().getDefenders()::contains) + .mapToInt(x -> 1) + .sum(); + return player.surveil(count, source, game); + } +} + +enum DimirStrandcatcherCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return DimirStrandcatcherValue.instance.calculate(game, source, null) >= 3; + } + + @Override + public String toString() { + return "three or more cards were put into your graveyard from anywhere other than the battlefield this turn"; + } +} + +enum DimirStrandcatcherValue implements DynamicValue { + instance; + private static final Hint hint = new ValueHint( + "Cards put into your graveyard from anywhere other than the battlefield this turn", instance + ); + + public static Hint getHint() { + return hint; + } + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return DimirStrandcatcherWatcher.getValue(game, sourceAbility); + } + + @Override + public DimirStrandcatcherValue copy() { + return this; + } + + @Override + public String getMessage() { + return ""; + } + + @Override + public String toString() { + return "1"; + } +} + +class DimirStrandcatcherWatcher extends Watcher { + + private final Map map = new HashMap<>(); + + DimirStrandcatcherWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.ZONE_CHANGE) { + return; + } + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (Zone.GRAVEYARD.match(zEvent.getToZone()) && !Zone.BATTLEFIELD.match(zEvent.getFromZone())) { + map.compute(game.getOwnerId(zEvent.getTargetId()), CardUtil::setOrIncrementValue); + } + } + + @Override + public void reset() { + super.reset(); + map.clear(); + } + + static int getValue(Game game, Ability source) { + return game + .getState() + .getWatcher(DimirStrandcatcherWatcher.class) + .map + .getOrDefault(source.getControllerId(), 0); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DionBahamutsDominant.java b/Mage.Sets/src/mage/cards/d/DionBahamutsDominant.java index 169722a42e3..1916be7d1ce 100644 --- a/Mage.Sets/src/mage/cards/d/DionBahamutsDominant.java +++ b/Mage.Sets/src/mage/cards/d/DionBahamutsDominant.java @@ -47,7 +47,7 @@ public final class DionBahamutsDominant extends CardImpl { MyTurnCondition.instance, "during your turn, {this}" )); ability.addEffect(new ConditionalContinuousEffect( - new GainAbilityControlledEffect(FlyingAbility.getInstance(), Duration.WhileControlled, filter), + new GainAbilityControlledEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield, filter), MyTurnCondition.instance, "and other Knights you control have flying" )); this.addAbility(ability.withFlavorWord("Dragonfire Dive")); diff --git a/Mage.Sets/src/mage/cards/d/DireFleetPoisoner.java b/Mage.Sets/src/mage/cards/d/DireFleetPoisoner.java index 58df2723d95..c4f5b9a6721 100644 --- a/Mage.Sets/src/mage/cards/d/DireFleetPoisoner.java +++ b/Mage.Sets/src/mage/cards/d/DireFleetPoisoner.java @@ -17,6 +17,7 @@ import mage.constants.SubType; import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -53,7 +54,7 @@ public final class DireFleetPoisoner extends CardImpl { effect = new GainAbilityTargetEffect(DeathtouchAbility.getInstance(), Duration.EndOfTurn); effect.setText("and gains deathtouch until end of turn"); ability.addEffect(effect); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DiscerningFinancier.java b/Mage.Sets/src/mage/cards/d/DiscerningFinancier.java index 6bd7aa7bfd3..a7a004406f0 100644 --- a/Mage.Sets/src/mage/cards/d/DiscerningFinancier.java +++ b/Mage.Sets/src/mage/cards/d/DiscerningFinancier.java @@ -2,18 +2,17 @@ package mage.cards.d; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.OpponentControlsMoreCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -34,11 +33,11 @@ import java.util.UUID; * @author Susucr */ public final class DiscerningFinancier extends CardImpl { - private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LAND); + private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS); private static final Hint hint = new ConditionHint( - condition, "An opponent controls more land than you", null, - "No opponent controls more land than you", null, true + condition, "An opponent controls more lands than you", null, + "No opponent controls more lands than you", null, true ); private static final FilterControlledPermanent filter = @@ -53,14 +52,9 @@ public final class DiscerningFinancier extends CardImpl { this.toughness = new MageInt(3); // At the beginning of your upkeep, if an opponent controls more lands than you, create a Treasure token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - new CreateTokenEffect(new TreasureToken()), false - ), - condition, - "At the beginning of your upkeep, if an opponent controls more lands than you, create a Treasure token." - ).addHint(hint)); - + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new CreateTokenEffect(new TreasureToken()), false + ).withInterveningIf(condition).addHint(hint)); // {2}{W}: Choose another player. That player gains control of target Treasure you control. You draw a card. Ability ability = new SimpleActivatedAbility( diff --git a/Mage.Sets/src/mage/cards/d/DiscipleOfBolas.java b/Mage.Sets/src/mage/cards/d/DiscipleOfBolas.java index 9add46c6857..83228895223 100644 --- a/Mage.Sets/src/mage/cards/d/DiscipleOfBolas.java +++ b/Mage.Sets/src/mage/cards/d/DiscipleOfBolas.java @@ -1,25 +1,23 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class DiscipleOfBolas extends CardImpl { @@ -65,21 +63,24 @@ class DiscipleOfBolasEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Target target = new TargetControlledCreaturePermanent(1, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, true); - target.setRequired(true); - if (target.canChoose(source.getControllerId(), source, game)) { - controller.chooseTarget(outcome, target, source, game); - Permanent sacrificed = game.getPermanent(target.getFirstTarget()); - if (sacrificed != null) { - sacrificed.sacrifice(source, game); - int power = sacrificed.getPower().getValue(); - controller.gainLife(power, game, source); - controller.drawCards(power, source, game); - } - } - return true; + if (controller == null) { + return false; } - return false; + SacrificeTargetCost cost = new SacrificeTargetCost(StaticFilters.FILTER_ANOTHER_CREATURE); + if (!cost.canPay(source, source, source.getControllerId(), game) + || !cost.pay(source, game, source, source.getControllerId(), true)) { + return false; + } + int power = cost + .getPermanents() + .stream() + .map(MageObject::getPower) + .mapToInt(MageInt::getValue) + .sum(); + if (power > 0) { + controller.gainLife(power, game, source); + controller.drawCards(power, source, game); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/d/DiseasedVermin.java b/Mage.Sets/src/mage/cards/d/DiseasedVermin.java index cc0d2f0ee1e..49f364fc910 100644 --- a/Mage.Sets/src/mage/cards/d/DiseasedVermin.java +++ b/Mage.Sets/src/mage/cards/d/DiseasedVermin.java @@ -1,19 +1,16 @@ package mage.cards.d; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.constants.SubType; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.WatcherScope; import mage.counters.CounterType; import mage.filter.FilterOpponent; @@ -21,17 +18,25 @@ import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPlayer; import mage.watchers.Watcher; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class DiseasedVermin extends CardImpl { + private static final FilterOpponent filter = new FilterOpponent("player previously dealt damage by {this}"); + + static { + filter.add(new DiseasedVerminPredicate()); + } + public DiseasedVermin(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); @@ -46,12 +51,11 @@ public final class DiseasedVermin extends CardImpl { false)); // At the beginning of your upkeep, Diseased Vermin deals X damage to target opponent previously dealt damage by it, where X is the number of infection counters on it. - Ability ability = new BeginningOfUpkeepTriggeredAbility( - new DiseasedVerminEffect() - ); + Ability ability = new BeginningOfUpkeepTriggeredAbility(new DamageTargetEffect(new CountersSourceCount(CounterType.INFECTION)) + .setText("{this} deals X damage to target opponent previously dealt damage by it, where X is the number of infection counters on it")); + ability.addTarget(new TargetPlayer(filter)); ability.addWatcher(new DiseasedVerminWatcher()); this.addAbility(ability); - } private DiseasedVermin(final DiseasedVermin card) { @@ -64,51 +68,6 @@ public final class DiseasedVermin extends CardImpl { } } -class DiseasedVerminEffect extends OneShotEffect { - - static final FilterOpponent filter = new FilterOpponent("player previously dealt damage by {this}"); - - static { - filter.add(new DiseasedVerminPredicate()); - } - - public DiseasedVerminEffect() { - super(Outcome.Benefit); - this.staticText = "{this} deals X damage to target opponent previously dealt damage by it, where X is the number of infection counters on it"; - } - - private DiseasedVerminEffect(final DiseasedVerminEffect effect) { - super(effect); - } - - @Override - public DiseasedVerminEffect copy() { - return new DiseasedVerminEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (sourcePermanent != null - && controller != null) { - TargetPlayer targetOpponent = new TargetPlayer(1, 1, false, filter); - if (targetOpponent.canChoose(controller.getId(), source, game) - && controller.choose(Outcome.Damage, targetOpponent, source, game)) { - Player opponent = game.getPlayer(targetOpponent.getFirstTarget()); - if (opponent != null - && sourcePermanent.getCounters(game).getCount(CounterType.INFECTION) > 0) { - opponent.damage( - sourcePermanent.getCounters(game).getCount(CounterType.INFECTION), - source.getSourceId(), source, game, false, true); - return true; - } - } - } - return false; - } -} - class DiseasedVerminPredicate implements ObjectSourcePlayerPredicate { @Override diff --git a/Mage.Sets/src/mage/cards/d/DispenseJustice.java b/Mage.Sets/src/mage/cards/d/DispenseJustice.java index 19870987397..700076f16fb 100644 --- a/Mage.Sets/src/mage/cards/d/DispenseJustice.java +++ b/Mage.Sets/src/mage/cards/d/DispenseJustice.java @@ -7,7 +7,6 @@ import mage.abilities.effects.common.SacrificeEffect; import mage.abilities.hint.common.MetalcraftHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Outcome; import mage.filter.common.FilterAttackingCreature; @@ -44,7 +43,7 @@ public final class DispenseJustice extends CardImpl { class DispenseJusticeEffect extends OneShotEffect { - private static final String effectText = "Target player sacrifices an attacking creature.\r\n\r\n" + private static final String effectText = "Target player sacrifices an attacking creature.
" + "Metalcraft — That player sacrifices two attacking creatures instead if you control three or more artifacts"; private static final FilterAttackingCreature filter = new FilterAttackingCreature(); diff --git a/Mage.Sets/src/mage/cards/d/Displace.java b/Mage.Sets/src/mage/cards/d/Displace.java index fe45adc664d..00715cdc183 100644 --- a/Mage.Sets/src/mage/cards/d/Displace.java +++ b/Mage.Sets/src/mage/cards/d/Displace.java @@ -4,7 +4,6 @@ import mage.abilities.effects.common.ExileThenReturnTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.StaticFilters; import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; @@ -18,8 +17,8 @@ public final class Displace extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}"); // Exile up to two target creatures you control, then return those cards to the battlefield under their owner's control. - this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, 2, StaticFilters.FILTER_CONTROLLED_CREATURES, false)); this.getSpellAbility().addEffect(new ExileThenReturnTargetEffect(false, true)); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, 2)); } private Displace(final Displace card) { diff --git a/Mage.Sets/src/mage/cards/d/DisruptingScepter.java b/Mage.Sets/src/mage/cards/d/DisruptingScepter.java index c4543772094..b69953b1046 100644 --- a/Mage.Sets/src/mage/cards/d/DisruptingScepter.java +++ b/Mage.Sets/src/mage/cards/d/DisruptingScepter.java @@ -4,13 +4,11 @@ import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.discard.DiscardTargetEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.target.TargetPlayer; import java.util.UUID; @@ -24,10 +22,11 @@ public final class DisruptingScepter extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // {3}, {T}: Target player discards a card. Activate this ability only during your turn. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new DiscardTargetEffect(1), new ManaCostsImpl<>("{3}"), MyTurnCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DiscardTargetEffect(1), new GenericManaCost(3), MyTurnCondition.instance + ); ability.addTarget(new TargetPlayer()); ability.addCost(new TapSourceCost()); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DisruptiveStormbrood.java b/Mage.Sets/src/mage/cards/d/DisruptiveStormbrood.java index 382d66191e4..fb459b5a2b7 100644 --- a/Mage.Sets/src/mage/cards/d/DisruptiveStormbrood.java +++ b/Mage.Sets/src/mage/cards/d/DisruptiveStormbrood.java @@ -49,7 +49,7 @@ public final class DisruptiveStormbrood extends OmenCard { // Destroy target creature with power 3 or less. Effect spellEffect = new DestroyTargetEffect(); this.getSpellCard().getSpellAbility().addEffect(spellEffect); - this.getSpellCard().getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellCard().getSpellAbility().addTarget(new TargetPermanent(filter)); this.finalizeOmen(); } diff --git a/Mage.Sets/src/mage/cards/d/DissensionInTheRanks.java b/Mage.Sets/src/mage/cards/d/DissensionInTheRanks.java index 5c3567832f9..0aea464bfd5 100644 --- a/Mage.Sets/src/mage/cards/d/DissensionInTheRanks.java +++ b/Mage.Sets/src/mage/cards/d/DissensionInTheRanks.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.effects.common.FightTargetsEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -9,35 +7,31 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.other.AnotherTargetPredicate; import mage.filter.predicate.permanent.BlockingPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class DissensionInTheRanks extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("blocking creature"); + private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another target blocking creature"); static { filter.add(BlockingPredicate.instance); + filter2.add(new AnotherTargetPredicate(2)); + filter2.add(BlockingPredicate.instance); } public DissensionInTheRanks(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}{R}"); // Target blocking creature fights another target blocking creature. this.getSpellAbility().addEffect(new FightTargetsEffect(false)); - TargetCreaturePermanent target = new TargetCreaturePermanent(1, 1, filter, false); - target.setTargetTag(1); - this.getSpellAbility().addTarget(target); - - FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another target blocking creature"); - filter2.add(new AnotherTargetPredicate(2)); - filter2.add(BlockingPredicate.instance); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter2); - target2.setTargetTag(2); - this.getSpellAbility().addTarget(target2); + this.getSpellAbility().addTarget(new TargetPermanent(filter).setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanent(filter2).setTargetTag(2)); } private DissensionInTheRanks(final DissensionInTheRanks card) { diff --git a/Mage.Sets/src/mage/cards/d/DistinguishedConjurer.java b/Mage.Sets/src/mage/cards/d/DistinguishedConjurer.java index 3054e46f84f..8f8c8f9b45d 100644 --- a/Mage.Sets/src/mage/cards/d/DistinguishedConjurer.java +++ b/Mage.Sets/src/mage/cards/d/DistinguishedConjurer.java @@ -15,7 +15,7 @@ import mage.constants.SubType; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -45,7 +45,7 @@ public final class DistinguishedConjurer extends CardImpl { // {4}{W}, {T}: Exile another target creature you control, then return it to the battlefield under its owner’s control. Ability ability = new SimpleActivatedAbility(new ExileThenReturnTargetEffect(false, false), new ManaCostsImpl<>("{4}{W}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DiveBomber.java b/Mage.Sets/src/mage/cards/d/DiveBomber.java index a0e9813d5dd..b03c80744ef 100644 --- a/Mage.Sets/src/mage/cards/d/DiveBomber.java +++ b/Mage.Sets/src/mage/cards/d/DiveBomber.java @@ -15,6 +15,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterAttackingOrBlockingCreature; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -35,7 +36,7 @@ public final class DiveBomber extends CardImpl { // {tap}, Sacrifice Dive Bomber: Dive Bomber deals 2 damage to target attacking or blocking creature. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2, "it"), new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(new FilterAttackingOrBlockingCreature())); + ability.addTarget(new TargetPermanent(new FilterAttackingOrBlockingCreature())); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DivebomberGriffin.java b/Mage.Sets/src/mage/cards/d/DivebomberGriffin.java index 843b097a2f6..f5c4909ab4f 100644 --- a/Mage.Sets/src/mage/cards/d/DivebomberGriffin.java +++ b/Mage.Sets/src/mage/cards/d/DivebomberGriffin.java @@ -15,6 +15,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterAttackingOrBlockingCreature; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -34,7 +35,7 @@ public final class DivebomberGriffin extends CardImpl { // {tap}, Sacrifice Divebomber Griffin: Divebomber Griffin deals 3 damage to target attacking or blocking creature. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(3, "it"), new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(new FilterAttackingOrBlockingCreature())); + ability.addTarget(new TargetPermanent(new FilterAttackingOrBlockingCreature())); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DivergentTransformations.java b/Mage.Sets/src/mage/cards/d/DivergentTransformations.java index 6ffb47fbddf..93adbb3d663 100644 --- a/Mage.Sets/src/mage/cards/d/DivergentTransformations.java +++ b/Mage.Sets/src/mage/cards/d/DivergentTransformations.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.*; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -15,8 +13,9 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import java.util.*; + /** - * * @author LevelX2 */ public final class DivergentTransformations extends CardImpl { @@ -26,6 +25,7 @@ public final class DivergentTransformations extends CardImpl { // Undaunted this.addAbility(new UndauntedAbility()); + // Exile two target creatures. For each of those creatures, its controller reveals cards from the top of their library until they reveal a creature card, puts that card onto the battlefield, then shuffles the rest into their library. this.getSpellAbility().addEffect(new DivergentTransformationsEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent(2)); diff --git a/Mage.Sets/src/mage/cards/d/DiversionaryTactics.java b/Mage.Sets/src/mage/cards/d/DiversionaryTactics.java index 3cf25dae0ff..a988dfc5ef3 100644 --- a/Mage.Sets/src/mage/cards/d/DiversionaryTactics.java +++ b/Mage.Sets/src/mage/cards/d/DiversionaryTactics.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapTargetCost; @@ -9,30 +7,28 @@ import mage.abilities.effects.common.TapTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.filter.StaticFilters; +import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * @author Loki */ public final class DiversionaryTactics extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); - - static { - filter.add(TappedPredicate.UNTAPPED); - } - public DiversionaryTactics(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); - Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new TapTargetCost(new TargetControlledCreaturePermanent(2, 2, filter, false))); + Ability ability = new SimpleActivatedAbility( + new TapTargetEffect(), + new TapTargetCost( + new TargetControlledPermanent(2, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES) + ) + ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); - } private DiversionaryTactics(final DiversionaryTactics card) { diff --git a/Mage.Sets/src/mage/cards/d/DivineResilience.java b/Mage.Sets/src/mage/cards/d/DivineResilience.java index 58b3d0b1272..9c7cd13dd52 100644 --- a/Mage.Sets/src/mage/cards/d/DivineResilience.java +++ b/Mage.Sets/src/mage/cards/d/DivineResilience.java @@ -7,21 +7,18 @@ import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.StaticFilters; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.targetadjustment.ConditionalTargetAdjuster; import java.util.UUID; /** - * * @author ciaccona007 */ public final class DivineResilience extends CardImpl { public DivineResilience(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); - // Kicker {2}{W} this.addAbility(new KickerAbility("{2}{W}")); @@ -34,7 +31,7 @@ public final class DivineResilience extends CardImpl { this.getSpellAbility().setTargetAdjuster(new ConditionalTargetAdjuster( KickedCondition.ONCE, new TargetControlledCreaturePermanent(), - new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, StaticFilters.FILTER_CONTROLLED_CREATURES, false) + new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE) )); } diff --git a/Mage.Sets/src/mage/cards/d/DivineVerdict.java b/Mage.Sets/src/mage/cards/d/DivineVerdict.java index 4671f1054c1..1f40296ebc4 100644 --- a/Mage.Sets/src/mage/cards/d/DivineVerdict.java +++ b/Mage.Sets/src/mage/cards/d/DivineVerdict.java @@ -7,6 +7,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterAttackingOrBlockingCreature; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -19,7 +20,7 @@ public final class DivineVerdict extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{W}"); // Destroy target attacking or blocking creature. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterAttackingOrBlockingCreature())); + this.getSpellAbility().addTarget(new TargetPermanent(new FilterAttackingOrBlockingCreature())); this.getSpellAbility().addEffect(new DestroyTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/d/DizzyingGaze.java b/Mage.Sets/src/mage/cards/d/DizzyingGaze.java index 104cbca60a1..6a8e61e8df0 100644 --- a/Mage.Sets/src/mage/cards/d/DizzyingGaze.java +++ b/Mage.Sets/src/mage/cards/d/DizzyingGaze.java @@ -50,7 +50,7 @@ public final class DizzyingGaze extends CardImpl { // {R}: Enchanted creature deals 1 damage to target creature with flying. Ability ability2 = new SimpleActivatedAbility(new DamageTargetEffect(1), new ManaCostsImpl<>("{R}")); - ability2.addTarget(new TargetCreaturePermanent(filter)); + ability2.addTarget(new TargetPermanent(filter)); this.addAbility(new SimpleStaticAbility( new GainAbilityAttachedEffect( ability2, diff --git a/Mage.Sets/src/mage/cards/d/DjinnOfInfiniteDeceits.java b/Mage.Sets/src/mage/cards/d/DjinnOfInfiniteDeceits.java index 204e8a8bf80..1bab6cf6e2e 100644 --- a/Mage.Sets/src/mage/cards/d/DjinnOfInfiniteDeceits.java +++ b/Mage.Sets/src/mage/cards/d/DjinnOfInfiniteDeceits.java @@ -1,10 +1,9 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.IsPhaseCondition; import mage.abilities.costs.common.TapSourceCost; @@ -15,22 +14,25 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class DjinnOfInfiniteDeceits extends CardImpl { - private static final String rule = "Exchange control of two target nonlegendary creatures"; private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonlegendary creature"); + static { filter.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); } + private static final Condition condition = new InvertCondition(new IsPhaseCondition(TurnPhase.COMBAT)); + public DjinnOfInfiniteDeceits(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}"); this.subtype.add(SubType.DJINN); this.power = new MageInt(2); @@ -38,13 +40,12 @@ public final class DjinnOfInfiniteDeceits extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); + // {tap}: Exchange control of two target nonlegendary creatures. You can't activate this ability during combat. - Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new ExchangeControlTargetEffect(Duration.EndOfGame, rule), - new TapSourceCost(), - new InvertCondition(new IsPhaseCondition(TurnPhase.COMBAT))); - ability.addTarget(new TargetCreaturePermanent(2,2, filter, false)); + Ability ability = new ActivateIfConditionActivatedAbility(new ExchangeControlTargetEffect( + Duration.EndOfGame, "exchange control of two target nonlegendary creatures" + ), new TapSourceCost(), condition); + ability.addTarget(new TargetPermanent(2, filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DoOrDie.java b/Mage.Sets/src/mage/cards/d/DoOrDie.java index 0b95336936b..3eb90a3df48 100644 --- a/Mage.Sets/src/mage/cards/d/DoOrDie.java +++ b/Mage.Sets/src/mage/cards/d/DoOrDie.java @@ -12,21 +12,20 @@ import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.TargetPlayer; -import mage.target.common.TargetCreaturePermanent; import java.util.ArrayList; import java.util.List; import java.util.UUID; /** - * * @author fireshoes */ public final class DoOrDie extends CardImpl { public DoOrDie(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); // Separate all creatures target player controls into two piles. Destroy all creatures in the pile of that player's choice. They can't be regenerated. this.getSpellAbility().addEffect(new DoOrDieEffect()); @@ -68,7 +67,7 @@ class DoOrDieEffect extends OneShotEffect { } FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures to put in the first pile"); filter.add(new ControllerIdPredicate(targetPlayer.getId())); - TargetCreaturePermanent creatures = new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, true); + TargetPermanent creatures = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); List pile1 = new ArrayList<>(); if (player.choose(Outcome.Neutral, creatures, source, game)) { List targets = creatures.getTargets(); diff --git a/Mage.Sets/src/mage/cards/d/DoggedHunter.java b/Mage.Sets/src/mage/cards/d/DoggedHunter.java index bed092c443d..57204e79ed1 100644 --- a/Mage.Sets/src/mage/cards/d/DoggedHunter.java +++ b/Mage.Sets/src/mage/cards/d/DoggedHunter.java @@ -14,6 +14,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TokenPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class DoggedHunter extends CardImpl { // {tap}: Destroy target creature token. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/Domestication.java b/Mage.Sets/src/mage/cards/d/Domestication.java index c3cf849cf4e..dec065881ae 100644 --- a/Mage.Sets/src/mage/cards/d/Domestication.java +++ b/Mage.Sets/src/mage/cards/d/Domestication.java @@ -1,52 +1,48 @@ - package mage.cards.d; -import java.util.UUID; +import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.continuous.ControlEnchantedEffect; import mage.abilities.keyword.EnchantAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.Optional; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class Domestication extends CardImpl { public Domestication(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}"); this.subtype.add(SubType.AURA); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.GainControl)); - Ability ability = new EnchantAbility(auraTarget); - this.addAbility(ability); - + this.addAbility(new EnchantAbility(auraTarget)); + // You control enchanted creature. this.addAbility(new SimpleStaticAbility(new ControlEnchantedEffect())); - + // At the beginning of your end step, if enchanted creature's power is 4 or greater, sacrifice Domestication. - TriggeredAbility ability2 = new BeginningOfEndStepTriggeredAbility(new SacrificeSourceEffect()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability2, new DomesticationCondition(), "At the beginning of your end step, if enchanted creature's power is 4 or greater, sacrifice {this}")); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new SacrificeSourceEffect()).withInterveningIf(DomesticationCondition.instance)); } private Domestication(final Domestication card) { @@ -59,19 +55,23 @@ public final class Domestication extends CardImpl { } } -class DomesticationCondition implements Condition { - +enum DomesticationCondition implements Condition { + instance; + @Override public boolean apply(Game game, Ability source) { - Permanent enchantment = game.getPermanent(source.getSourceId()); - if (enchantment != null) { - Permanent enchanted = game.getPermanent(enchantment.getAttachedTo()); - if (enchanted != null) { - if (enchanted.getPower().getValue() >= 4) { - return true; - } - } - } - return false; + return Optional + .ofNullable(source.getSourcePermanentIfItStillExists(game)) + .map(Permanent::getAttachedTo) + .map(game::getPermanent) + .map(MageObject::getPower) + .map(MageInt::getValue) + .filter(x -> x >= 4) + .isPresent(); + } + + @Override + public String toString() { + return "enchanted creature's power is 4 or greater"; } } diff --git a/Mage.Sets/src/mage/cards/d/Dominate.java b/Mage.Sets/src/mage/cards/d/Dominate.java index b8b10c2bf99..7f7559415b8 100644 --- a/Mage.Sets/src/mage/cards/d/Dominate.java +++ b/Mage.Sets/src/mage/cards/d/Dominate.java @@ -7,6 +7,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.XManaValueTargetAdjuster; @@ -22,7 +23,7 @@ public final class Dominate extends CardImpl { // Gain control of target creature with converted mana cost X or less. this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.Custom, true)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature with mana value X or less"))); + this.getSpellAbility().addTarget(new TargetPermanent(new FilterCreaturePermanent("creature with mana value X or less"))); this.getSpellAbility().setTargetAdjuster(new XManaValueTargetAdjuster(ComparisonType.OR_LESS)); } diff --git a/Mage.Sets/src/mage/cards/d/DominatingVampire.java b/Mage.Sets/src/mage/cards/d/DominatingVampire.java index 08825f5dafd..c32d45efb8d 100644 --- a/Mage.Sets/src/mage/cards/d/DominatingVampire.java +++ b/Mage.Sets/src/mage/cards/d/DominatingVampire.java @@ -19,6 +19,7 @@ import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -46,7 +47,7 @@ public final class DominatingVampire extends CardImpl { Ability ability = new EntersBattlefieldTriggeredAbility(new GainControlTargetEffect(Duration.EndOfTurn)); ability.addEffect(new UntapTargetEffect().setText("Untap that creature")); ability.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn, "It gains haste until end of turn")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DominatorDrone.java b/Mage.Sets/src/mage/cards/d/DominatorDrone.java index a75ef4545d9..5e0e3ce950a 100644 --- a/Mage.Sets/src/mage/cards/d/DominatorDrone.java +++ b/Mage.Sets/src/mage/cards/d/DominatorDrone.java @@ -2,10 +2,9 @@ package mage.cards.d; import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.abilities.keyword.DevoidAbility; import mage.abilities.keyword.IngestAbility; @@ -13,25 +12,27 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.mageobject.ColorlessPredicate; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.ColorlessPredicate; import java.util.UUID; /** - * * @author LevelX2 */ public final class DominatorDrone extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another colorless creature"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("you control another colorless creature"); static { filter.add(AnotherPredicate.instance); filter.add(ColorlessPredicate.instance); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + public DominatorDrone(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.ELDRAZI); @@ -46,12 +47,7 @@ public final class DominatorDrone extends CardImpl { this.addAbility(new IngestAbility()); // When Dominator Drone enters the battlefield, if you control another colorless creature, each opponent loses 2 life. - TriggeredAbility triggeredAbility = new EntersBattlefieldTriggeredAbility(new LoseLifeOpponentsEffect(2)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - triggeredAbility, - new PermanentsOnTheBattlefieldCondition(filter), - "When {this} enters, if you control another colorless creature, each opponent loses 2 life.")); - + this.addAbility(new EntersBattlefieldTriggeredAbility(new LoseLifeOpponentsEffect(2)).withInterveningIf(condition)); } private DominatorDrone(final DominatorDrone card) { diff --git a/Mage.Sets/src/mage/cards/d/Domineer.java b/Mage.Sets/src/mage/cards/d/Domineer.java index e41877951dc..56343d37c6a 100644 --- a/Mage.Sets/src/mage/cards/d/Domineer.java +++ b/Mage.Sets/src/mage/cards/d/Domineer.java @@ -34,7 +34,7 @@ public final class Domineer extends CardImpl { this.subtype.add(SubType.AURA); // Enchant artifact creature - TargetPermanent auraTarget = new TargetCreaturePermanent(filter); + TargetPermanent auraTarget = new TargetPermanent(filter); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.GainControl)); Ability ability = new EnchantAbility(auraTarget); diff --git a/Mage.Sets/src/mage/cards/d/DomineeringWill.java b/Mage.Sets/src/mage/cards/d/DomineeringWill.java index 50e0a160ae4..f003a3215e4 100644 --- a/Mage.Sets/src/mage/cards/d/DomineeringWill.java +++ b/Mage.Sets/src/mage/cards/d/DomineeringWill.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; @@ -20,12 +18,13 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.AttackingPredicate; import mage.game.Game; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.TargetPlayer; -import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.SecondTargetPointer; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class DomineeringWill extends CardImpl { @@ -37,13 +36,12 @@ public final class DomineeringWill extends CardImpl { } public DomineeringWill(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}"); // Target player gains control of up to three target nonattacking creatures until end of turn. Untap those creatures. They block this turn if able. this.getSpellAbility().addEffect(new DomineeringWillEffect()); this.getSpellAbility().addTarget(new TargetPlayer()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 3, filter, false)); - + this.getSpellAbility().addTarget(new TargetPermanent(0, 3, filter)); } private DomineeringWill(final DomineeringWill card) { diff --git a/Mage.Sets/src/mage/cards/d/DomriRade.java b/Mage.Sets/src/mage/cards/d/DomriRade.java index 5e1f5f38d5c..004167705ec 100644 --- a/Mage.Sets/src/mage/cards/d/DomriRade.java +++ b/Mage.Sets/src/mage/cards/d/DomriRade.java @@ -11,15 +11,16 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.CardsImpl; import mage.constants.*; -import mage.filter.StaticFilters; import mage.game.Game; import mage.game.command.emblems.DomriRadeEmblem; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2; + /** * @author LevelX2 */ @@ -36,15 +37,10 @@ public final class DomriRade extends CardImpl { this.addAbility(new LoyaltyAbility(new DomriRadeEffect1(), 1)); // -2: Target creature you control fights another target creature. - LoyaltyAbility ability2 = new LoyaltyAbility(new FightTargetsEffect(false), -2); - TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(); - target.setTargetTag(1); - ability2.addTarget(target); - - TargetCreaturePermanent target2 = new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2); - target2.setTargetTag(2); - ability2.addTarget(target2); - this.addAbility(ability2); + LoyaltyAbility ability = new LoyaltyAbility(new FightTargetsEffect(false), -2); + ability.addTarget(new TargetControlledCreaturePermanent().setTargetTag(1)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_CREATURE_TARGET_2).setTargetTag(2)); + this.addAbility(ability); // -7: You get an emblem with "Creatures you control have double strike, trample, hexproof and haste." this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new DomriRadeEmblem()), -7)); diff --git a/Mage.Sets/src/mage/cards/d/DomrisNodorog.java b/Mage.Sets/src/mage/cards/d/DomrisNodorog.java index 2c289dd233a..61c39fd1411 100644 --- a/Mage.Sets/src/mage/cards/d/DomrisNodorog.java +++ b/Mage.Sets/src/mage/cards/d/DomrisNodorog.java @@ -18,7 +18,7 @@ import java.util.UUID; */ public final class DomrisNodorog extends CardImpl { - private static final FilterCard filter = new FilterCard("card named Domri, City Smasher"); + private static final FilterCard filter = new FilterCard("a card named Domri, City Smasher"); static { filter.add(new NamePredicate("Domri, City Smasher")); diff --git a/Mage.Sets/src/mage/cards/d/DongZhouTheTyrant.java b/Mage.Sets/src/mage/cards/d/DongZhouTheTyrant.java index c54bc1bc11f..01648c0600c 100644 --- a/Mage.Sets/src/mage/cards/d/DongZhouTheTyrant.java +++ b/Mage.Sets/src/mage/cards/d/DongZhouTheTyrant.java @@ -11,10 +11,13 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * @author fireshoes */ @@ -30,7 +33,7 @@ public final class DongZhouTheTyrant extends CardImpl { // When Dong Zhou, the Tyrant enters the battlefield, target creature an opponent controls deals damage equal to its power to that player. Ability ability = new EntersBattlefieldTriggeredAbility(new DongZhouTheTyrantEffect(), false); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DoomBlade.java b/Mage.Sets/src/mage/cards/d/DoomBlade.java index e406967e20d..1cd2e858779 100644 --- a/Mage.Sets/src/mage/cards/d/DoomBlade.java +++ b/Mage.Sets/src/mage/cards/d/DoomBlade.java @@ -6,8 +6,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author LokiX @@ -17,7 +20,7 @@ public final class DoomBlade extends CardImpl { public DoomBlade(UUID ownerId, CardSetInfo setInfo){ super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}"); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/d/DoomsdayExcruciator.java b/Mage.Sets/src/mage/cards/d/DoomsdayExcruciator.java index 4b3ac468b2a..8df0ed6ae2b 100644 --- a/Mage.Sets/src/mage/cards/d/DoomsdayExcruciator.java +++ b/Mage.Sets/src/mage/cards/d/DoomsdayExcruciator.java @@ -2,18 +2,20 @@ package mage.cards.d; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.cards.CardsImpl; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; import mage.game.Game; import mage.players.Player; @@ -35,16 +37,10 @@ public final class DoomsdayExcruciator extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Doomsday Excruciator enters, if it was cast, each player exiles all but the bottom six cards of their library face down. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DoomsdayExcruciatorEffect()), - CastFromEverywhereSourceCondition.instance, "When {this} enters, if it was cast, " + - "each player exiles all but the bottom six cards of their library face down." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DoomsdayExcruciatorEffect()).withInterveningIf(CastFromEverywhereSourceCondition.instance)); // At the beginning of your upkeep, draw a card. - this.addAbility(new BeginningOfUpkeepTriggeredAbility( - new DrawCardSourceControllerEffect(1) - )); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DrawCardSourceControllerEffect(1))); } private DoomsdayExcruciator(final DoomsdayExcruciator card) { @@ -61,6 +57,7 @@ class DoomsdayExcruciatorEffect extends OneShotEffect { DoomsdayExcruciatorEffect() { super(Outcome.Benefit); + staticText = "each player exiles all but the bottom six cards of their library face down"; } private DoomsdayExcruciatorEffect(final DoomsdayExcruciatorEffect effect) { diff --git a/Mage.Sets/src/mage/cards/d/Downsize.java b/Mage.Sets/src/mage/cards/d/Downsize.java index 197021b8205..96c802234f5 100644 --- a/Mage.Sets/src/mage/cards/d/Downsize.java +++ b/Mage.Sets/src/mage/cards/d/Downsize.java @@ -9,10 +9,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author LevelX2 */ @@ -22,7 +25,7 @@ public final class Downsize extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); // Target creature you don't control gets -4/-0 until end of turn. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.getSpellAbility().addEffect(new BoostTargetEffect(-4, 0, Duration.EndOfTurn)); // Overload {2}{U} (You may cast this spell for its overload cost. If you do, change its text by replacing all instances of "target" with "each.") diff --git a/Mage.Sets/src/mage/cards/d/DrEggman.java b/Mage.Sets/src/mage/cards/d/DrEggman.java new file mode 100644 index 00000000000..50dd35f2378 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DrEggman.java @@ -0,0 +1,93 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.FaceVillainousChoiceOpponentsEffect; +import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.FaceVillainousChoice; +import mage.choices.VillainousChoice; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DrEggman extends CardImpl { + + private static final FaceVillainousChoice choice = new FaceVillainousChoice( + Outcome.Discard, new DrEggmanFirstChoice(), new DrEggmanSecondChoice() + ); + + public DrEggman(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{B}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SCIENTIST); + this.power = new MageInt(3); + this.toughness = new MageInt(6); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // At the beginning of your end step, draw a card. Then each opponent faces a villainous choice -- That player discards a card, or you may put a Construct, Robot, or Vehicle card from your hand onto the battlefield. + Ability ability = new BeginningOfEndStepTriggeredAbility(new DrawCardSourceControllerEffect(1)); + ability.addEffect(new FaceVillainousChoiceOpponentsEffect(choice).concatBy("Then")); + this.addAbility(ability); + } + + private DrEggman(final DrEggman card) { + super(card); + } + + @Override + public DrEggman copy() { + return new DrEggman(this); + } +} + +class DrEggmanFirstChoice extends VillainousChoice { + DrEggmanFirstChoice() { + super("That player discards a card", "Discard a card"); + } + + @Override + public boolean doChoice(Player player, Game game, Ability source) { + return !player.discard(1, false, false, source, game).isEmpty(); + } +} + +class DrEggmanSecondChoice extends VillainousChoice { + private static final FilterCard filter = new FilterCard("Construct, Robot, or Vehicle card"); + + static { + filter.add(Predicates.or( + SubType.CONSTRUCT.getPredicate(), + SubType.ROBOT.getPredicate(), + SubType.VEHICLE.getPredicate() + )); + } + + DrEggmanSecondChoice() { + super("you may put a Construct, Robot, or Vehicle card from your hand onto the battlefield", + "{controller} may put a Construct, Robot, or Vehicle card from their hand onto the battlefield"); + } + + @Override + public boolean doChoice(Player player, Game game, Ability source) { + return new PutCardFromHandOntoBattlefieldEffect(filter).apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DragonGrip.java b/Mage.Sets/src/mage/cards/d/DragonGrip.java index 3cf21d87ea0..135ff97830f 100644 --- a/Mage.Sets/src/mage/cards/d/DragonGrip.java +++ b/Mage.Sets/src/mage/cards/d/DragonGrip.java @@ -34,8 +34,7 @@ public final class DragonGrip extends CardImpl { AsThoughEffect effect = new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame); this.addAbility(new SimpleStaticAbility(Zone.ALL, new ConditionalAsThoughEffect(effect, FerociousCondition.instance).setText("Ferocious — If you control a creature with power 4 or greater, " - + "you may cast Dragon Grip as though it had flash")) - .addHint(FerociousHint.instance)); + + "you may cast this spell as though it had flash")).addHint(FerociousHint.instance)); // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); diff --git a/Mage.Sets/src/mage/cards/d/DragonScarredBear.java b/Mage.Sets/src/mage/cards/d/DragonScarredBear.java index 116d6ad24df..8c842f767e3 100644 --- a/Mage.Sets/src/mage/cards/d/DragonScarredBear.java +++ b/Mage.Sets/src/mage/cards/d/DragonScarredBear.java @@ -1,9 +1,6 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.FormidableCondition; import mage.abilities.costs.mana.ManaCostsImpl; @@ -13,28 +10,24 @@ import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class DragonScarredBear extends CardImpl { public DragonScarredBear(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.subtype.add(SubType.BEAR); this.power = new MageInt(3); this.toughness = new MageInt(2); // Formidable — {1}{G}: Regenerate Dragon-Scarred Bear. Activate this only if creatures you control have total power 8 or greater. - Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new RegenerateSourceEffect(), - new ManaCostsImpl<>("{1}{G}"), - FormidableCondition.instance); - ability.setAbilityWord(AbilityWord.FORMIDABLE); - this.addAbility(ability); + this.addAbility(new ActivateIfConditionActivatedAbility( + new RegenerateSourceEffect(), new ManaCostsImpl<>("{1}{G}"), FormidableCondition.instance + ).setAbilityWord(AbilityWord.FORMIDABLE)); } private DragonScarredBear(final DragonScarredBear card) { diff --git a/Mage.Sets/src/mage/cards/d/DragonTempest.java b/Mage.Sets/src/mage/cards/d/DragonTempest.java index fa9ce3d15a6..bc1be2dfc26 100644 --- a/Mage.Sets/src/mage/cards/d/DragonTempest.java +++ b/Mage.Sets/src/mage/cards/d/DragonTempest.java @@ -1,8 +1,7 @@ package mage.cards.d; import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; -import mage.abilities.effects.Effect; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.FlyingAbility; @@ -10,8 +9,9 @@ import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledPermanent; -import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.game.Game; import mage.game.permanent.Permanent; @@ -25,31 +25,27 @@ import java.util.UUID; */ public final class DragonTempest extends CardImpl { - private static final FilterCreaturePermanent filterFlying = new FilterCreaturePermanent("a creature with flying"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("a creature you control with flying"); + private static final FilterPermanent filter2 = new FilterControlledPermanent(SubType.DRAGON, "a Dragon you control"); static { - filterFlying.add(new AbilityPredicate(FlyingAbility.class)); + filter.add(new AbilityPredicate(FlyingAbility.class)); } public DragonTempest(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); // Whenever a creature with flying you control enters, it gains haste until the end of turn. - Effect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); - effect.setText("it gains haste until end of turn"); - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, effect, filterFlying, false, SetTargetPointer.PERMANENT)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + Zone.BATTLEFIELD, new GainAbilityTargetEffect(HasteAbility.getInstance()) + .setText("it gains haste until end of turn"), + filter, false, SetTargetPointer.PERMANENT + )); // Whenever a Dragon you control enters, it deals X damage to any target, where X is the number of Dragons you control. - Ability ability = new EntersBattlefieldControlledTriggeredAbility( - Zone.BATTLEFIELD, - new DragonTempestDamageEffect(), - new FilterCreaturePermanent(SubType.DRAGON, "a Dragon"), - false, - SetTargetPointer.NONE - ); + Ability ability = new EntersBattlefieldAllTriggeredAbility(new DragonTempestDamageEffect(), filter2); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); - } private DragonTempest(final DragonTempest card) { diff --git a/Mage.Sets/src/mage/cards/d/DragonWhisperer.java b/Mage.Sets/src/mage/cards/d/DragonWhisperer.java index a747b2246f4..84cf4f1273b 100644 --- a/Mage.Sets/src/mage/cards/d/DragonWhisperer.java +++ b/Mage.Sets/src/mage/cards/d/DragonWhisperer.java @@ -1,9 +1,6 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.FormidableCondition; @@ -16,42 +13,38 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; import mage.game.permanent.token.DragonToken; +import java.util.UUID; + /** - * * @author fireshoes */ public final class DragonWhisperer extends CardImpl { public DragonWhisperer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{R}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SHAMAN); this.power = new MageInt(2); this.toughness = new MageInt(2); // {R}: Dragon Whisperer gains flying until end of turn. - this.addAbility(new SimpleActivatedAbility( - new GainAbilitySourceEffect(FlyingAbility.getInstance(), - Duration.EndOfTurn), new ManaCostsImpl<>("{R}"))); - + this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl<>("{R}"))); + // {1}{R}: Dragon Whisperer get +1/+0 until end of turn this.addAbility(new SimpleActivatedAbility( - new BoostSourceEffect(1, 0, Duration.EndOfTurn), - new ManaCostsImpl<>("{1}{R}"))); - + new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl<>("{1}{R}") + )); + // — {4}{R}{R}: Create a 4/4 red Dragon creature token with flying. Activate this ability only if creatures you control have total power 8 or greater. - Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new CreateTokenEffect(new DragonToken()), - new ManaCostsImpl<>("{4}{R}{R}"), - FormidableCondition.instance); - ability.setAbilityWord(AbilityWord.FORMIDABLE); - this.addAbility(ability); + this.addAbility(new ActivateIfConditionActivatedAbility( + new CreateTokenEffect(new DragonToken()), new ManaCostsImpl<>("{4}{R}{R}"), FormidableCondition.instance + ).setAbilityWord(AbilityWord.FORMIDABLE)); } private DragonWhisperer(final DragonWhisperer card) { diff --git a/Mage.Sets/src/mage/cards/d/DragonloftIdol.java b/Mage.Sets/src/mage/cards/d/DragonloftIdol.java index 805fe54d118..1ce9f55bc99 100644 --- a/Mage.Sets/src/mage/cards/d/DragonloftIdol.java +++ b/Mage.Sets/src/mage/cards/d/DragonloftIdol.java @@ -1,7 +1,6 @@ package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -14,9 +13,14 @@ import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; +import java.util.UUID; + /** * * @author LevelX2 @@ -38,9 +42,9 @@ public final class DragonloftIdol extends CardImpl { // As long as you control a Dragon, Dragonloft Idol gets +1/+1 and has flying and trample. - Effect effect = new ConditionalContinuousEffect(new BoostSourceEffect(1,1, Duration.WhileOnBattlefield), + Effect effect = new ConditionalContinuousEffect(new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), new PermanentsOnTheBattlefieldCondition(filter), - "As long as you control a Dragon, Dragonloft Idol gets +1/+1"); + "As long as you control a Dragon, {this} gets +1/+1"); Ability ability = new SimpleStaticAbility(effect); effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance()), new PermanentsOnTheBattlefieldCondition(filter), diff --git a/Mage.Sets/src/mage/cards/d/DragonmasterOutcast.java b/Mage.Sets/src/mage/cards/d/DragonmasterOutcast.java index 493688e506c..1fc135b7409 100644 --- a/Mage.Sets/src/mage/cards/d/DragonmasterOutcast.java +++ b/Mage.Sets/src/mage/cards/d/DragonmasterOutcast.java @@ -1,38 +1,30 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.hint.ValueHint; +import mage.abilities.hint.common.LandsYouControlHint; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; -import mage.filter.FilterPermanent; -import mage.filter.StaticFilters; +import mage.constants.SubType; +import mage.filter.common.FilterLandPermanent; import mage.game.permanent.token.DragonToken2; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class DragonmasterOutcast extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("land"); - - static { - filter.add(CardType.LAND.getPredicate()); - } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(new FilterLandPermanent("you control six or more lands"), ComparisonType.MORE_THAN, 5); public DragonmasterOutcast(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SHAMAN); @@ -40,11 +32,8 @@ public final class DragonmasterOutcast extends CardImpl { this.toughness = new MageInt(1); // At the beginning of your upkeep, if you control six or more lands, create a 5/5 red Dragon creature token with flying. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new DragonToken2(), 1)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - ability, new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 5), - "At the beginning of your upkeep, if you control six or more lands, create a 5/5 red Dragon creature token with flying." - ).addHint(new ValueHint("Lands you control", new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND)))); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new DragonToken2(), 1)) + .withInterveningIf(condition).addHint(LandsYouControlHint.instance)); } private DragonmasterOutcast(final DragonmasterOutcast card) { diff --git a/Mage.Sets/src/mage/cards/d/DrainingWhelk.java b/Mage.Sets/src/mage/cards/d/DrainingWhelk.java index fa73344bb77..f5b8454e477 100644 --- a/Mage.Sets/src/mage/cards/d/DrainingWhelk.java +++ b/Mage.Sets/src/mage/cards/d/DrainingWhelk.java @@ -1,7 +1,6 @@ package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -18,6 +17,8 @@ import mage.game.Game; import mage.game.stack.Spell; import mage.target.TargetSpell; +import java.util.UUID; + /** * * @author emerald000 @@ -57,7 +58,7 @@ class DrainingWhelkEffect extends CounterTargetEffect { DrainingWhelkEffect() { super(); - staticText = "counter target spell. Put X +1/+1 counters on Draining Whelk, where X is that spell's mana value"; + staticText = "counter target spell. Put X +1/+1 counters on {this}, where X is that spell's mana value"; } private DrainingWhelkEffect(final DrainingWhelkEffect effect) { diff --git a/Mage.Sets/src/mage/cards/d/DreadCacodemon.java b/Mage.Sets/src/mage/cards/d/DreadCacodemon.java index 77e9eb5d708..89279bb0a58 100644 --- a/Mage.Sets/src/mage/cards/d/DreadCacodemon.java +++ b/Mage.Sets/src/mage/cards/d/DreadCacodemon.java @@ -1,11 +1,9 @@ package mage.cards.d; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromHandSourcePermanentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.effects.common.TapAllEffect; import mage.cards.CardImpl; @@ -15,23 +13,26 @@ import mage.constants.SubType; import mage.filter.StaticFilters; import mage.watchers.common.CastFromHandWatcher; +import java.util.UUID; + /** * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class DreadCacodemon extends CardImpl { - public DreadCacodemon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{7}{B}{B}{B}"); + public DreadCacodemon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{7}{B}{B}{B}"); this.subtype.add(SubType.DEMON); this.power = new MageInt(8); this.toughness = new MageInt(8); // When Dread Cacodemon enters the battlefield, // if you cast it from your hand, destroy all creatures your opponents control, then tap all other creatures you control. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES)); - ability.addEffect(new TapAllEffect(StaticFilters.FILTER_OTHER_CONTROLLED_CREATURES)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, CastFromHandSourcePermanentCondition.instance, - "When {this} enters, if you cast it from your hand, destroy all creatures your opponents control, then tap all other creatures you control."), new CastFromHandWatcher()); + Ability ability = new EntersBattlefieldTriggeredAbility( + new DestroyAllEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES) + ).withInterveningIf(CastFromHandSourcePermanentCondition.instance); + ability.addEffect(new TapAllEffect(StaticFilters.FILTER_OTHER_CONTROLLED_CREATURES).concatBy(", then")); + this.addAbility(ability, new CastFromHandWatcher()); } private DreadCacodemon(final DreadCacodemon card) { diff --git a/Mage.Sets/src/mage/cards/d/DreadWanderer.java b/Mage.Sets/src/mage/cards/d/DreadWanderer.java index 892f355ce9a..b6d521ebb53 100644 --- a/Mage.Sets/src/mage/cards/d/DreadWanderer.java +++ b/Mage.Sets/src/mage/cards/d/DreadWanderer.java @@ -1,11 +1,10 @@ package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.condition.common.HeckbentCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -14,8 +13,9 @@ import mage.constants.SubType; import mage.constants.TimingRule; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author fireshoes */ public final class DreadWanderer extends CardImpl { @@ -33,17 +33,10 @@ public final class DreadWanderer extends CardImpl { // {2}{B}: Return Dread Wanderer from your graveyard to the battlefield. // Activate this ability only any time you could cast a sorcery and only if you have one or fewer cards in hand. - ConditionalActivatedAbility ability = new ConditionalActivatedAbility( - Zone.GRAVEYARD, - new ReturnSourceFromGraveyardToBattlefieldEffect(), - new ManaCostsImpl<>("{2}{B}"), - HeckbentCondition.instance, - "{2}{B}: Return {this} from your graveyard to the battlefield. " - + "Activate only as a sorcery " - + "and only if you have one or fewer cards in hand." - ); - ability.setTiming(TimingRule.SORCERY); - addAbility(ability); + this.addAbility(new ActivateIfConditionActivatedAbility( + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(), + new ManaCostsImpl<>("{2}{B}"), HeckbentCondition.instance + ).setTiming(TimingRule.SORCERY)); } private DreadWanderer(final DreadWanderer card) { diff --git a/Mage.Sets/src/mage/cards/d/DreadlightMonstrosity.java b/Mage.Sets/src/mage/cards/d/DreadlightMonstrosity.java index b4cdbe27ed4..b39e5a84055 100644 --- a/Mage.Sets/src/mage/cards/d/DreadlightMonstrosity.java +++ b/Mage.Sets/src/mage/cards/d/DreadlightMonstrosity.java @@ -14,7 +14,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.game.Game; import java.util.Collection; @@ -25,10 +24,6 @@ import java.util.UUID; */ public final class DreadlightMonstrosity extends CardImpl { - private static final Hint hint = new ConditionHint( - DreadlightMonstrosityCondition.instance, "You own a card in exile" - ); - public DreadlightMonstrosity(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}"); @@ -42,9 +37,9 @@ public final class DreadlightMonstrosity extends CardImpl { // {3}{U}{U}: Dreadlight Monstrosity can't be blocked this turn. Activate only if you own a card in exile. this.addAbility(new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new CantBeBlockedSourceEffect(Duration.EndOfTurn), + new CantBeBlockedSourceEffect(Duration.EndOfTurn), new ManaCostsImpl<>("{3}{U}{U}"), DreadlightMonstrosityCondition.instance - ).addHint(hint)); + ).addHint(DreadlightMonstrosityCondition.getHint())); } private DreadlightMonstrosity(final DreadlightMonstrosity card) { @@ -59,6 +54,11 @@ public final class DreadlightMonstrosity extends CardImpl { enum DreadlightMonstrosityCondition implements Condition { instance; + private static final Hint hint = new ConditionHint(instance); + + public static Hint getHint() { + return hint; + } @Override public boolean apply(Game game, Ability source) { @@ -75,4 +75,4 @@ enum DreadlightMonstrosityCondition implements Condition { public String toString() { return "you own a card in exile"; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/d/DreamEater.java b/Mage.Sets/src/mage/cards/d/DreamEater.java index 5c728566480..6ad226cde45 100644 --- a/Mage.Sets/src/mage/cards/d/DreamEater.java +++ b/Mage.Sets/src/mage/cards/d/DreamEater.java @@ -5,6 +5,7 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.effects.keyword.SurveilEffect; import mage.abilities.keyword.FlashAbility; @@ -42,8 +43,9 @@ public final class DreamEater extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Dream Eater enters the battlefield, surveil 4. When you do, you may return target nonland permanent an opponent controls to its owner's hand. - Ability ability = new EntersBattlefieldTriggeredAbility(new SurveilEffect(4)); + Ability ability = new EntersBattlefieldTriggeredAbility(new SurveilEffect(4, false)); ability.addEffect(new DreamEaterEffect()); + ability.addEffect(new InfoEffect("(To surveil 4, look at the top four cards of your library, then put any number of them into your graveyard and the rest on top of your library in any order.)")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DreamTides.java b/Mage.Sets/src/mage/cards/d/DreamTides.java index 72ba7428972..bf72a5e91b0 100644 --- a/Mage.Sets/src/mage/cards/d/DreamTides.java +++ b/Mage.Sets/src/mage/cards/d/DreamTides.java @@ -2,14 +2,17 @@ package mage.cards.d; import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.Cost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DontUntapInControllersUntapStepAllEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; @@ -19,7 +22,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.util.ManaUtil; import java.util.UUID; @@ -74,25 +77,25 @@ class DreamTidesEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (player != null && sourcePermanent != null) { - int countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).size(); - while (player.canRespond() && countBattlefield > 0 && player.chooseUse(Outcome.AIDontUseIt, "Pay {2} and untap a tapped nongreen creature under your control?", source, game)) { - Target tappedCreatureTarget = new TargetControlledCreaturePermanent(1, 1, filter, true); - if (player.choose(Outcome.Detriment, tappedCreatureTarget, source, game)) { - Cost cost = ManaUtil.createManaCost(2, false); - Permanent tappedCreature = game.getPermanent(tappedCreatureTarget.getFirstTarget()); - - if (cost.pay(source, game, source, player.getId(), false)) { - tappedCreature.untap(game); - } - } - countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).size(); - } - return true; + if (player == null || sourcePermanent == null) { + return false; } - return false; + int countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).size(); + while (player.canRespond() && countBattlefield > 0 && player.chooseUse(Outcome.AIDontUseIt, "Pay {2} and untap a tapped nongreen creature under your control?", source, game)) { + Target tappedCreatureTarget = new TargetPermanent(filter); + tappedCreatureTarget.withNotTarget(true); + if (player.choose(Outcome.Detriment, tappedCreatureTarget, source, game)) { + Cost cost = ManaUtil.createManaCost(2, false); + Permanent tappedCreature = game.getPermanent(tappedCreatureTarget.getFirstTarget()); + + if (cost.pay(source, game, source, player.getId(), false)) { + tappedCreature.untap(game); + } + } + countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).size(); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/d/DreamcallerSiren.java b/Mage.Sets/src/mage/cards/d/DreamcallerSiren.java index a0ff63c9091..826b2565f47 100644 --- a/Mage.Sets/src/mage/cards/d/DreamcallerSiren.java +++ b/Mage.Sets/src/mage/cards/d/DreamcallerSiren.java @@ -1,13 +1,12 @@ package mage.cards.d; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.CanBlockOnlyFlyingAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.FlyingAbility; @@ -15,25 +14,26 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.common.TargetNonlandPermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class DreamcallerSiren extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another Pirate"); + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.PIRATE, "you control another Pirate"); static { - filter.add(SubType.PIRATE.getPredicate()); filter.add(AnotherPredicate.instance); - filter.add(TargetController.YOU.getControllerPredicate()); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + public DreamcallerSiren(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); @@ -52,11 +52,9 @@ public final class DreamcallerSiren extends CardImpl { this.addAbility(new CanBlockOnlyFlyingAbility()); // When Dreamcaller Siren enters the battlefield, if you control another Pirate, tap up to two nonland permanents. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); + Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()).withInterveningIf(condition); ability.addTarget(new TargetNonlandPermanent(0, 2, false)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, - new PermanentsOnTheBattlefieldCondition(filter), - "when {this} enters, if you control another Pirate, tap up to two target nonland permanents.")); + this.addAbility(ability); } private DreamcallerSiren(final DreamcallerSiren card) { diff --git a/Mage.Sets/src/mage/cards/d/DreampodDruid.java b/Mage.Sets/src/mage/cards/d/DreampodDruid.java index f11aafc15a0..5735738308b 100644 --- a/Mage.Sets/src/mage/cards/d/DreampodDruid.java +++ b/Mage.Sets/src/mage/cards/d/DreampodDruid.java @@ -1,12 +1,10 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.EnchantedSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -14,12 +12,15 @@ import mage.constants.SubType; import mage.constants.TargetController; import mage.game.permanent.token.SaprolingToken; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class DreampodDruid extends CardImpl { + private static final Condition condition = new EnchantedSourceCondition(); + public DreampodDruid(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.HUMAN); @@ -29,10 +30,9 @@ public final class DreampodDruid extends CardImpl { this.toughness = new MageInt(2); // At the beginning of each upkeep, if Dreampod Druid is enchanted, create a 1/1 green Saproling creature token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(TargetController.ANY, new CreateTokenEffect(new SaprolingToken(), 1), false), - new EnchantedSourceCondition(), - "At the beginning of each upkeep, if Dreampod Druid is enchanted, create a 1/1 green Saproling creature token.")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.ANY, new CreateTokenEffect(new SaprolingToken(), 1), false + ).withInterveningIf(condition)); } private DreampodDruid(final DreampodDruid card) { diff --git a/Mage.Sets/src/mage/cards/d/DregsOfSorrow.java b/Mage.Sets/src/mage/cards/d/DregsOfSorrow.java index 55c1aeb8995..f48a9fbd379 100644 --- a/Mage.Sets/src/mage/cards/d/DregsOfSorrow.java +++ b/Mage.Sets/src/mage/cards/d/DregsOfSorrow.java @@ -7,11 +7,14 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.XTargetsCountAdjuster; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES_NON_BLACK; + /** * @author LevelX2 */ @@ -23,7 +26,7 @@ public final class DregsOfSorrow extends CardImpl { // Destroy X target nonblack creatures. Draw X cards. this.getSpellAbility().addEffect(new DestroyTargetEffect("Destroy X target nonblack creatures")); this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(GetXValue.instance)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURES_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURES_NON_BLACK)); this.getSpellAbility().setTargetAdjuster(new XTargetsCountAdjuster()); } diff --git a/Mage.Sets/src/mage/cards/d/DressDown.java b/Mage.Sets/src/mage/cards/d/DressDown.java index cba8de87977..990cd029159 100644 --- a/Mage.Sets/src/mage/cards/d/DressDown.java +++ b/Mage.Sets/src/mage/cards/d/DressDown.java @@ -1,23 +1,22 @@ package mage.cards.d; -import java.util.UUID; - import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.continuous.LoseAllAbilitiesAllEffect; import mage.abilities.keyword.FlashAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.TargetController; import mage.filter.StaticFilters; -import mage.game.events.GameEvent; + +import java.util.UUID; /** - * * @author weirddan455 */ public final class DressDown extends CardImpl { @@ -32,12 +31,13 @@ public final class DressDown extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1))); // Creatures lose all abilities. - this.addAbility(new SimpleStaticAbility(new LoseAllAbilitiesAllEffect(StaticFilters.FILTER_PERMANENT_CREATURES, Duration.WhileOnBattlefield))); + this.addAbility(new SimpleStaticAbility(new LoseAllAbilitiesAllEffect( + StaticFilters.FILTER_PERMANENT_CREATURES, Duration.WhileOnBattlefield + ))); // At the beginning of the end step, sacrifice Dress Down. - this.addAbility(new OnEventTriggeredAbility( - GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", - true, new SacrificeSourceEffect() + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.NEXT, new SacrificeSourceEffect(), false )); } diff --git a/Mage.Sets/src/mage/cards/d/DrizztDoUrden.java b/Mage.Sets/src/mage/cards/d/DrizztDoUrden.java index ec84d0ca805..fc6d6657afc 100644 --- a/Mage.Sets/src/mage/cards/d/DrizztDoUrden.java +++ b/Mage.Sets/src/mage/cards/d/DrizztDoUrden.java @@ -6,7 +6,6 @@ import mage.abilities.Ability; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.DoubleStrikeAbility; @@ -45,11 +44,7 @@ public final class DrizztDoUrden extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GuenhwyvarToken()))); // Whenever a creature dies, if it had power greater than Drizzt's power, put a number of +1/+1 counters on Drizzt equal to the difference. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new DiesCreatureTriggeredAbility(new DrizztDoUrdenEffect(), false), - DrizztDoUrdenCondition.instance, "Whenever a creature dies, if it had power greater " + - "than {this}'s power, put a number of +1/+1 counters on {this} equal to the difference." - )); + this.addAbility(new DiesCreatureTriggeredAbility(new DrizztDoUrdenEffect(), false).withInterveningIf(DrizztDoUrdenCondition.instance)); } private DrizztDoUrden(final DrizztDoUrden card) { @@ -76,12 +71,18 @@ enum DrizztDoUrdenCondition implements Condition { .filter(x -> sourcePermanent.getPower().getValue() < x) .isPresent(); } + + @Override + public String toString() { + return "it had power greater than {this}'s power"; + } } class DrizztDoUrdenEffect extends OneShotEffect { DrizztDoUrdenEffect() { super(Outcome.Benefit); + staticText = "put a number of +1/+1 counters on {this} equal to the difference"; } private DrizztDoUrdenEffect(final DrizztDoUrdenEffect effect) { diff --git a/Mage.Sets/src/mage/cards/d/DromokaDunecaster.java b/Mage.Sets/src/mage/cards/d/DromokaDunecaster.java index 95038c35611..865042b51f0 100644 --- a/Mage.Sets/src/mage/cards/d/DromokaDunecaster.java +++ b/Mage.Sets/src/mage/cards/d/DromokaDunecaster.java @@ -16,6 +16,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class DromokaDunecaster extends CardImpl { // {1}{W}, {T}: Tap target creature without flying. SimpleActivatedAbility ability = new SimpleActivatedAbility(new TapTargetEffect(), new ManaCostsImpl<>("{1}{W}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DromokasCommand.java b/Mage.Sets/src/mage/cards/d/DromokasCommand.java index dc7a823495e..bae49454683 100644 --- a/Mage.Sets/src/mage/cards/d/DromokasCommand.java +++ b/Mage.Sets/src/mage/cards/d/DromokasCommand.java @@ -15,6 +15,7 @@ import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterEnchantmentPermanent; import mage.filter.common.FilterInstantOrSorcerySpell; +import mage.target.TargetPermanent; import mage.target.TargetPlayer; import mage.target.TargetSpell; import mage.target.common.TargetControlledCreaturePermanent; @@ -22,6 +23,8 @@ import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author jeffwadsworth */ @@ -53,7 +56,7 @@ public final class DromokasCommand extends CardImpl { effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); effect.setText("Put a +1/+1 counter on target creature"); mode = new Mode(effect); - mode.addTarget(new TargetCreaturePermanent(filterCreature)); + mode.addTarget(new TargetPermanent(filterCreature)); this.getSpellAbility().getModes().addMode(mode); // or Target creature you control fights target creature you don't control. @@ -61,7 +64,7 @@ public final class DromokasCommand extends CardImpl { effect.setText("Target creature you control fights target creature you don't control"); mode = new Mode(effect); mode.addTarget(new TargetControlledCreaturePermanent()); - mode.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + mode.addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/d/DroolingGroodion.java b/Mage.Sets/src/mage/cards/d/DroolingGroodion.java index 69eb9f6df0e..aeddf9fa34f 100644 --- a/Mage.Sets/src/mage/cards/d/DroolingGroodion.java +++ b/Mage.Sets/src/mage/cards/d/DroolingGroodion.java @@ -1,6 +1,5 @@ package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -12,12 +11,15 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.SecondTargetPointer; +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2; + /** - * * @author LevelX2 */ public final class DroolingGroodion extends CardImpl { @@ -31,19 +33,10 @@ public final class DroolingGroodion extends CardImpl { // {2}{B}{G}, Sacrifice a creature: Target creature gets +2/+2 until end of turn. Another target creature gets -2/-2 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(2, 2), new ManaCostsImpl<>("{2}{B}{G}")); - ability.addEffect(new BoostTargetEffect(-2, -2).setTargetPointer(new SecondTargetPointer())); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE)); - - TargetCreaturePermanent target = new TargetCreaturePermanent(); - target.setTargetTag(1); - target.withChooseHint("gets +2/+2"); - ability.addTarget(target); - - target = new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2); - target.setTargetTag(2); - target.withChooseHint("gets -2/-2"); - ability.addTarget(target); - + ability.addEffect(new BoostTargetEffect(-2, -2).setTargetPointer(new SecondTargetPointer())); + ability.addTarget(new TargetCreaturePermanent().setTargetTag(1).withChooseHint("gets +2/+2")); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_CREATURE_TARGET_2).setTargetTag(2).withChooseHint("gets -2/-2")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DropkickBomber.java b/Mage.Sets/src/mage/cards/d/DropkickBomber.java index 9d9a949ec8e..13086554ec7 100644 --- a/Mage.Sets/src/mage/cards/d/DropkickBomber.java +++ b/Mage.Sets/src/mage/cards/d/DropkickBomber.java @@ -15,16 +15,14 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; /** - * * @author ciaccona007 */ public final class DropkickBomber extends CardImpl { @@ -41,7 +39,7 @@ public final class DropkickBomber extends CardImpl { public DropkickBomber(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); - + this.subtype.add(SubType.GOBLIN); this.subtype.add(SubType.WARRIOR); this.power = new MageInt(2); @@ -67,7 +65,7 @@ public final class DropkickBomber extends CardImpl { Duration.EndOfTurn ).setText("and \"When this creature deals combat damage, sacrifice it.\"") ); - ability.addTarget(new TargetControlledCreaturePermanent(filter2)); + ability.addTarget(new TargetPermanent(filter2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DrownerOfTruth.java b/Mage.Sets/src/mage/cards/d/DrownerOfTruth.java index fd085e352f7..8aa6ac54644 100644 --- a/Mage.Sets/src/mage/cards/d/DrownerOfTruth.java +++ b/Mage.Sets/src/mage/cards/d/DrownerOfTruth.java @@ -1,10 +1,8 @@ package mage.cards.d; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.condition.common.ManaWasSpentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CastSourceTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.DevoidAbility; @@ -38,12 +36,8 @@ public final class DrownerOfTruth extends ModalDoubleFacedCard { this.getLeftHalfCard().addAbility(new DevoidAbility(this.getLeftHalfCard().getColor())); // When you cast this spell, if {C} was spent to cast it, create two 0/1 colorless Eldrazi Spawn creature tokens with "Sacrifice this creature: Add {C}." - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new CastSourceTriggeredAbility(new CreateTokenEffect(new EldraziSpawnToken(), 2)), - ManaWasSpentCondition.COLORLESS, - "When you cast this spell, if {C} was spent to cast it, " - + "create two 0/1 colorless Eldrazi Spawn creature tokens with \"Sacrifice this creature: Add {C}.\""); - this.getLeftHalfCard().addAbility(ability); + this.getLeftHalfCard().addAbility(new CastSourceTriggeredAbility(new CreateTokenEffect(new EldraziSpawnToken(), 2)) + .withInterveningIf(ManaWasSpentCondition.COLORLESS)); // 2. // Drowned Jungle diff --git a/Mage.Sets/src/mage/cards/d/DrunauCorpseTrawler.java b/Mage.Sets/src/mage/cards/d/DrunauCorpseTrawler.java index fa3b97a66e3..827cd6e99ae 100644 --- a/Mage.Sets/src/mage/cards/d/DrunauCorpseTrawler.java +++ b/Mage.Sets/src/mage/cards/d/DrunauCorpseTrawler.java @@ -18,8 +18,11 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.game.permanent.token.ZombieToken; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.constants.SubType.ZOMBIE; + /** * * @author LevelX2 @@ -37,7 +40,7 @@ public final class DrunauCorpseTrawler extends CardImpl { // {2}{B}: Target Zombie gains deathtouch until end of turn. Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(DeathtouchAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{2}{B}")); - ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent(SubType.ZOMBIE, "Zombie"))); + ability.addTarget(new TargetPermanent(new FilterCreaturePermanent(ZOMBIE, "Zombie"))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DuelForDominance.java b/Mage.Sets/src/mage/cards/d/DuelForDominance.java index b7c8409769c..f72fbc629bf 100644 --- a/Mage.Sets/src/mage/cards/d/DuelForDominance.java +++ b/Mage.Sets/src/mage/cards/d/DuelForDominance.java @@ -11,11 +11,14 @@ import mage.constants.AbilityWord; import mage.constants.CardType; import mage.counters.CounterType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author xenohedron */ @@ -26,7 +29,7 @@ public final class DuelForDominance extends CardImpl { // Coven — Choose target creature you control and target creature you don't control. this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); // If you control three or more creatures with different powers, put a +1/+1 counter on the chosen creature you control. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new AddCountersTargetEffect(CounterType.P1P1.createInstance()), diff --git a/Mage.Sets/src/mage/cards/d/DuelcraftTrainer.java b/Mage.Sets/src/mage/cards/d/DuelcraftTrainer.java index bd4a5bdfc7e..b71fac635c4 100644 --- a/Mage.Sets/src/mage/cards/d/DuelcraftTrainer.java +++ b/Mage.Sets/src/mage/cards/d/DuelcraftTrainer.java @@ -2,16 +2,18 @@ package mage.cards.d; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.common.CovenCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.hint.common.CovenHint; import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; @@ -33,13 +35,9 @@ public final class DuelcraftTrainer extends CardImpl { this.addAbility(FirstStrikeAbility.getInstance()); // Coven — At the beginning of combat on your turn, if you control three or more creatures with different powers, target creature you control gains double strike until end of turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility(new GainAbilityTargetEffect( - DoubleStrikeAbility.getInstance(), Duration.EndOfTurn - )), CovenCondition.instance, "At the beginning " + - "of combat on your turn, if you control three or more creatures with different powers, " + - "target creature you control gains double strike until end of turn." - ); + Ability ability = new BeginningOfCombatTriggeredAbility( + new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn) + ).withInterveningIf(CovenCondition.instance); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability.addHint(CovenHint.instance).setAbilityWord(AbilityWord.COVEN)); } diff --git a/Mage.Sets/src/mage/cards/d/DuelistsHeritage.java b/Mage.Sets/src/mage/cards/d/DuelistsHeritage.java index b8ae9f11e06..47ccd3f0f27 100644 --- a/Mage.Sets/src/mage/cards/d/DuelistsHeritage.java +++ b/Mage.Sets/src/mage/cards/d/DuelistsHeritage.java @@ -14,6 +14,7 @@ import mage.constants.Zone; import mage.filter.common.FilterAttackingCreature; import mage.game.Game; import mage.game.events.GameEvent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -33,7 +34,7 @@ public final class DuelistsHeritage extends CardImpl { effect.setOutcome(Outcome.Benefit); Ability ability = new DuelistsHeritageTriggeredAbility( Zone.BATTLEFIELD, effect); - ability.addTarget(new TargetCreaturePermanent(new FilterAttackingCreature())); + ability.addTarget(new TargetPermanent(new FilterAttackingCreature())); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DuergarHedgeMage.java b/Mage.Sets/src/mage/cards/d/DuergarHedgeMage.java index b2623d28cb8..9cfae0bab85 100644 --- a/Mage.Sets/src/mage/cards/d/DuergarHedgeMage.java +++ b/Mage.Sets/src/mage/cards/d/DuergarHedgeMage.java @@ -1,40 +1,38 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.filter.common.FilterLandPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.target.common.TargetArtifactPermanent; import mage.target.common.TargetEnchantmentPermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class DuergarHedgeMage extends CardImpl { - private static final FilterLandPermanent filter = new FilterLandPermanent("a Mountain"); - private static final FilterLandPermanent filter2 = new FilterLandPermanent("a Plains"); - - static { - filter.add(SubType.MOUNTAIN.getPredicate()); - filter2.add(SubType.PLAINS.getPredicate()); - } - private static final String rule1 = "When {this} enters, if you control two or more Mountains, you may destroy target artifact."; - private static final String rule2 = "When {this} enters, if you control two or more Plains, you may destroy target enchantment."; + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.MOUNTAIN, "you control two or more Mountains"), + ComparisonType.MORE_THAN, 1 + ); + private static final Condition condition2 = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.PLAINS, "you control two or more Plains"), + ComparisonType.MORE_THAN, 1 + ); public DuergarHedgeMage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R/W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R/W}"); this.subtype.add(SubType.DWARF); this.subtype.add(SubType.SHAMAN); @@ -42,15 +40,14 @@ public final class DuergarHedgeMage extends CardImpl { this.toughness = new MageInt(2); // When Duergar Hedge-Mage enters the battlefield, if you control two or more Mountains, you may destroy target artifact. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), true), new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1), rule1); + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), true).withInterveningIf(condition); ability.addTarget(new TargetArtifactPermanent()); this.addAbility(ability); // When Duergar Hedge-Mage enters the battlefield, if you control two or more Plains, you may destroy target enchantment. - Ability ability2 = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), true), new PermanentsOnTheBattlefieldCondition(filter2, ComparisonType.MORE_THAN, 1), rule2); - ability2.addTarget(new TargetEnchantmentPermanent()); - this.addAbility(ability2); - + ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), true).withInterveningIf(condition2); + ability.addTarget(new TargetEnchantmentPermanent()); + this.addAbility(ability); } private DuergarHedgeMage(final DuergarHedgeMage card) { diff --git a/Mage.Sets/src/mage/cards/d/DugganPrivateDetective.java b/Mage.Sets/src/mage/cards/d/DugganPrivateDetective.java index f2f19b21ccf..b61a987a088 100644 --- a/Mage.Sets/src/mage/cards/d/DugganPrivateDetective.java +++ b/Mage.Sets/src/mage/cards/d/DugganPrivateDetective.java @@ -17,10 +17,13 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * @author Cguy7777 */ @@ -49,7 +52,7 @@ public final class DugganPrivateDetective extends CardImpl { new ManaCostsImpl<>("{1}{G}"), TimingRule.INSTANT); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); ability.withFlavorWord("The Most Important Punch in History"); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/Duneblast.java b/Mage.Sets/src/mage/cards/d/Duneblast.java index 606fdd89e55..618331f9450 100644 --- a/Mage.Sets/src/mage/cards/d/Duneblast.java +++ b/Mage.Sets/src/mage/cards/d/Duneblast.java @@ -1,8 +1,5 @@ - package mage.cards.d; -import java.util.Objects; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -10,26 +7,24 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Duneblast extends CardImpl { public Duneblast(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{W}{B}{G}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{W}{B}{G}"); // Choose up to one creature. Destroy the rest. this.getSpellAbility().addEffect(new DuneblastEffect()); - } private Duneblast(final Duneblast card) { @@ -61,20 +56,22 @@ class DuneblastEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Target target = new TargetCreaturePermanent(0,1,new FilterCreaturePermanent("creature to keep"), true); - target.setRequired(true); - Permanent creatureToKeep = null; - if (controller.choose(outcome, target, source, game)) { - creatureToKeep = game.getPermanent(target.getFirstTarget()); - } - for(Permanent creature: game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURES, source.getControllerId(), source, game)) { - if (!Objects.equals(creature, creatureToKeep)) { - creature.destroy(source, game, false); - } - } - return true; + if (controller == null) { + return false; } - return false; + Target target = new TargetCreaturePermanent(0, 1); + target.withNotTarget(true); + target.withChooseHint("to keep"); + target.setRequired(true); + controller.choose(outcome, target, source, game); + Permanent creatureToKeep = game.getPermanent(target.getFirstTarget()); + for (Permanent creature : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_PERMANENT_CREATURES, source.getControllerId(), source, game + )) { + if (!creature.equals(creatureToKeep)) { + creature.destroy(source, game, false); + } + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/d/DunedainRangers.java b/Mage.Sets/src/mage/cards/d/DunedainRangers.java index 2495393c8ec..aab17f5e857 100644 --- a/Mage.Sets/src/mage/cards/d/DunedainRangers.java +++ b/Mage.Sets/src/mage/cards/d/DunedainRangers.java @@ -4,11 +4,9 @@ import mage.MageInt; import mage.abilities.common.LandfallAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.keyword.TheRingTemptsYouEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; @@ -23,15 +21,13 @@ import java.util.UUID; */ public final class DunedainRangers extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent(); + private static final FilterPermanent filter = new FilterControlledPermanent("you don't control a Ring-bearer"); static { filter.add(RingBearerPredicate.instance); } - private static final Condition condition = new PermanentsOnTheBattlefieldCondition( - filter, ComparisonType.EQUAL_TO, 0 - ); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0); public DunedainRangers(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); @@ -42,11 +38,7 @@ public final class DunedainRangers extends CardImpl { this.toughness = new MageInt(4); // Landfall -- Whenever a land you control enters, if you don't control a Ring-bearer, the Ring tempts you. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new LandfallAbility(new TheRingTemptsYouEffect()), - condition, "Whenever a land you control enters, " + - "if you don't control a Ring-bearer, the Ring tempts you." - ).setAbilityWord(AbilityWord.LANDFALL)); + this.addAbility(new LandfallAbility(new TheRingTemptsYouEffect()).withInterveningIf(condition)); } private DunedainRangers(final DunedainRangers card) { diff --git a/Mage.Sets/src/mage/cards/d/DuneriderOutlaw.java b/Mage.Sets/src/mage/cards/d/DuneriderOutlaw.java index 90fcebdf8d6..15038f66b52 100644 --- a/Mage.Sets/src/mage/cards/d/DuneriderOutlaw.java +++ b/Mage.Sets/src/mage/cards/d/DuneriderOutlaw.java @@ -1,32 +1,28 @@ package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; -import mage.abilities.TriggeredAbility; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.condition.common.DealtDamageToAnOpponent; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.ProtectionAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.TargetController; import mage.counters.CounterType; -import mage.game.events.GameEvent; + +import java.util.UUID; /** - * * @author LevelX */ public final class DuneriderOutlaw extends CardImpl { - private static final String ruleText = "At the beginning of each end step, if {this} dealt damage to an opponent this turn, put a +1/+1 counter on it."; - public DuneriderOutlaw(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.REBEL); this.subtype.add(SubType.ROGUE); @@ -37,9 +33,14 @@ public final class DuneriderOutlaw extends CardImpl { // Protection from green this.addAbility(ProtectionAbility.from(ObjectColor.GREEN)); + // At the beginning of each end step, if Dunerider Outlaw dealt damage to an opponent this turn, put a +1/+1 counter on it. - TriggeredAbility triggered = new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of each end step", true, new AddCountersSourceEffect(CounterType.P1P1.createInstance())); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(triggered, new DealtDamageToAnOpponent(), ruleText)); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.ANY, + new AddCountersSourceEffect(CounterType.P1P1.createInstance()) + .setText("put a +1/+1 counter on it"), + false, DealtDamageToAnOpponent.instance + )); } private DuneriderOutlaw(final DuneriderOutlaw card) { diff --git a/Mage.Sets/src/mage/cards/d/DungeonDescent.java b/Mage.Sets/src/mage/cards/d/DungeonDescent.java index 265a5dde952..0598a7bd3c4 100644 --- a/Mage.Sets/src/mage/cards/d/DungeonDescent.java +++ b/Mage.Sets/src/mage/cards/d/DungeonDescent.java @@ -1,7 +1,5 @@ package mage.cards.d; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldTappedAbility; @@ -17,10 +15,10 @@ import mage.constants.CardType; import mage.constants.SuperType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author weirddan455 */ public final class DungeonDescent extends CardImpl { @@ -45,7 +43,7 @@ public final class DungeonDescent extends CardImpl { // {4}, {T}, Tap an untapped legendary creature you control: Venture into the dungeon. Activate only as a sorcery. Ability ability = new ActivateAsSorceryActivatedAbility(new VentureIntoTheDungeonEffect(), new GenericManaCost(4)); ability.addCost(new TapSourceCost()); - ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(filter))); + ability.addCost(new TapTargetCost(filter)); ability.addHint(CurrentDungeonHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DungeonGeists.java b/Mage.Sets/src/mage/cards/d/DungeonGeists.java index f15cecd6eb5..166a2ceecfd 100644 --- a/Mage.Sets/src/mage/cards/d/DungeonGeists.java +++ b/Mage.Sets/src/mage/cards/d/DungeonGeists.java @@ -17,10 +17,13 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * @author BetaSteward */ @@ -38,7 +41,7 @@ public final class DungeonGeists extends CardImpl { // When Dungeon Geists enters the battlefield, tap target creature an opponent controls. That creature doesn't untap during its controller's untap step for as long as you control Dungeon Geists. Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect(), false); ability.addEffect(new DontUntapInControllersUntapStepTargetEffect(Duration.WhileControlled)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/Duplicant.java b/Mage.Sets/src/mage/cards/d/Duplicant.java index 96ba6d2ea3a..560300b7464 100644 --- a/Mage.Sets/src/mage/cards/d/Duplicant.java +++ b/Mage.Sets/src/mage/cards/d/Duplicant.java @@ -16,6 +16,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.List; @@ -41,7 +42,7 @@ public final class Duplicant extends CardImpl { // Imprint - When Duplicant enters the battlefield, you may exile target nontoken creature. Ability ability = new EntersBattlefieldTriggeredAbility(new DuplicantExileTargetEffect(), true); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); ability.setAbilityWord(AbilityWord.IMPRINT); this.addAbility(ability); // As long as the exiled card is a creature card, Duplicant has that card's power, toughness, and creature types. It's still a Shapeshifter. diff --git a/Mage.Sets/src/mage/cards/d/DuskborneSkymarcher.java b/Mage.Sets/src/mage/cards/d/DuskborneSkymarcher.java index b8a3861e1ee..64243cd4b41 100644 --- a/Mage.Sets/src/mage/cards/d/DuskborneSkymarcher.java +++ b/Mage.Sets/src/mage/cards/d/DuskborneSkymarcher.java @@ -17,6 +17,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -45,7 +46,7 @@ public final class DuskborneSkymarcher extends CardImpl { // {W}, {T}: Target attacking vampire gets +1/+1 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(1, 1, Duration.EndOfTurn), new ManaCostsImpl<>("{W}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DwarvenArmory.java b/Mage.Sets/src/mage/cards/d/DwarvenArmory.java index 91ea7cf64ef..3fa047b3291 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenArmory.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenArmory.java @@ -1,38 +1,38 @@ package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.PhaseStep; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class DwarvenArmory extends CardImpl { + private static final Condition condition = new IsStepCondition(PhaseStep.UPKEEP, false); + public DwarvenArmory(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}{R}"); // {2}, Sacrifice a land: Put a +2/+2 counter on target creature. Activate this ability only during any upkeep step. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, + Ability ability = new ActivateIfConditionActivatedAbility( new AddCountersTargetEffect(CounterType.P2P2.createInstance()), - new ManaCostsImpl<>("{2}"), - new IsStepCondition(PhaseStep.UPKEEP, false), - null); + new ManaCostsImpl<>("{2}"), condition + ); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_LAND)); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/d/DwarvenCatapult.java b/Mage.Sets/src/mage/cards/d/DwarvenCatapult.java index d08553454ab..221b456587b 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenCatapult.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenCatapult.java @@ -17,13 +17,12 @@ import mage.util.CardUtil; import java.util.UUID; /** - * * @author MarcoMarin */ public final class DwarvenCatapult extends CardImpl { public DwarvenCatapult(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{R}"); // Dwarven Catapult deals X damage divided evenly, rounded down, among all creatures target opponent controls. this.getSpellAbility().addTarget(new TargetOpponent()); @@ -55,10 +54,11 @@ class DwarvenCatapultEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int howMany = game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURES, source.getFirstTarget(), game).size(); - int amount = CardUtil.getSourceCostsTag(game, source, "X", 0)/howMany; - - DamageAllControlledTargetEffect dmgEffect = new DamageAllControlledTargetEffect(amount, new FilterCreaturePermanent()); - return dmgEffect.apply(game, source); + if (howMany > 0) { + int amount = CardUtil.getSourceCostsTag(game, source, "X", 0) / howMany; + return new DamageAllControlledTargetEffect(amount, new FilterCreaturePermanent()).apply(game, source); + } + return false; } @Override diff --git a/Mage.Sets/src/mage/cards/d/DwarvenDemolitionTeam.java b/Mage.Sets/src/mage/cards/d/DwarvenDemolitionTeam.java index 7149e308f38..dfb90ce8d07 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenDemolitionTeam.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenDemolitionTeam.java @@ -13,6 +13,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -36,7 +37,7 @@ public final class DwarvenDemolitionTeam extends CardImpl { // {tap}: Destroy target Wall. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DwarvenLieutenant.java b/Mage.Sets/src/mage/cards/d/DwarvenLieutenant.java index a4e401f1476..528f70cf541 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenLieutenant.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenLieutenant.java @@ -14,6 +14,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class DwarvenLieutenant extends CardImpl { // {1}{R}: Target Dwarf creature gets +1/+0 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl<>("{1}{R}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DwarvenNomad.java b/Mage.Sets/src/mage/cards/d/DwarvenNomad.java index 0a007e756b5..b6297ca12c5 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenNomad.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenNomad.java @@ -15,6 +15,7 @@ import mage.constants.ComparisonType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class DwarvenNomad extends CardImpl { // {T}: Target creature with power 2 or less can't be blocked this turn. Ability ability = new SimpleActivatedAbility(new CantBeBlockedTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DwarvenPony.java b/Mage.Sets/src/mage/cards/d/DwarvenPony.java index 0c8537dc7ae..01dd5ad79ce 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenPony.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenPony.java @@ -16,6 +16,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class DwarvenPony extends CardImpl { Ability ability = new SimpleActivatedAbility( new GainAbilityTargetEffect(new MountainwalkAbility(false), Duration.EndOfTurn), new ManaCostsImpl<>("{1}{R}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DwarvenSeaClan.java b/Mage.Sets/src/mage/cards/d/DwarvenSeaClan.java index fa3a13b4df6..6cafeb67f3c 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenSeaClan.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenSeaClan.java @@ -1,33 +1,32 @@ package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.DamageTargetEffect; -import mage.constants.PhaseStep; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; +import mage.constants.PhaseStep; +import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterAttackingOrBlockingCreature; import mage.filter.predicate.permanent.ControllerControlsIslandPredicate; import mage.game.Game; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author noahg */ public final class DwarvenSeaClan extends CardImpl { - private static final FilterAttackingOrBlockingCreature filter = new FilterAttackingOrBlockingCreature(); + private static final FilterPermanent filter = new FilterAttackingOrBlockingCreature("attacking or blocking creature whose controller controls an Island"); static { filter.add(ControllerControlsIslandPredicate.instance); @@ -35,19 +34,18 @@ public final class DwarvenSeaClan extends CardImpl { public DwarvenSeaClan(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); - + this.subtype.add(SubType.DWARF); this.power = new MageInt(1); this.toughness = new MageInt(1); // {tap}: Choose target attacking or blocking creature whose controller controls an Island. Dwarven Sea Clan deals 2 damage to that creature at end of combat. Activate this ability only before the end of combat step. - Effect effect = new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(new DamageTargetEffect(2, true, "that creature"))); - effect.setText("Choose target attacking or blocking creature whose controller controls an Island. Dwarven Sea Clan deals 2 damage to that creature at end of combat."); Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - effect, - new TapSourceCost(), - BeforeEndCombatCondition.getInstance() + new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility( + new DamageTargetEffect(2, true, "that creature") + )).setText("Choose target attacking or blocking creature whose controller controls an Island. " + + "{this} deals 2 damage to that creature at end of combat."), + new TapSourceCost(), BeforeEndCombatCondition.getInstance() ); ability.addTarget(new TargetPermanent(filter)); addAbility(ability); @@ -73,7 +71,7 @@ class BeforeEndCombatCondition implements Condition { @Override public boolean apply(Game game, Ability source) { PhaseStep phaseStep = game.getTurnStepType(); - if(phaseStep.getIndex() < PhaseStep.END_COMBAT.getIndex()) { + if (phaseStep.getIndex() < PhaseStep.END_COMBAT.getIndex()) { return true; } return false; diff --git a/Mage.Sets/src/mage/cards/d/DwarvenWarriors.java b/Mage.Sets/src/mage/cards/d/DwarvenWarriors.java index 5bc2d1b8b6a..2deb081afea 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenWarriors.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenWarriors.java @@ -15,6 +15,7 @@ import mage.constants.ComparisonType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class DwarvenWarriors extends CardImpl { // {T}: Target creature with power 2 or less can't be blocked this turn. Ability ability = new SimpleActivatedAbility(new CantBeBlockedTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DwarvenWeaponsmith.java b/Mage.Sets/src/mage/cards/d/DwarvenWeaponsmith.java index c511bc5951b..a175e97aa23 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenWeaponsmith.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenWeaponsmith.java @@ -1,42 +1,39 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.PhaseStep; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledArtifactPermanent; -import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LoneFox */ public final class DwarvenWeaponsmith extends CardImpl { public DwarvenWeaponsmith(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); this.subtype.add(SubType.DWARF); this.subtype.add(SubType.ARTIFICER); this.power = new MageInt(1); this.toughness = new MageInt(1); // {tap}, Sacrifice an artifact: Put a +1/+1 counter on target creature. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), - new TapSourceCost(), new IsStepCondition(PhaseStep.UPKEEP)); + Ability ability = new ActivateIfConditionActivatedAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), + new TapSourceCost(), IsStepCondition.getMyUpkeep() + ); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_ARTIFACT)); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/d/DwynensElite.java b/Mage.Sets/src/mage/cards/d/DwynensElite.java index 0e030e313fe..d837c7f1eec 100644 --- a/Mage.Sets/src/mage/cards/d/DwynensElite.java +++ b/Mage.Sets/src/mage/cards/d/DwynensElite.java @@ -1,15 +1,15 @@ package mage.cards.d; import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.permanent.token.ElfWarriorToken; @@ -21,13 +21,14 @@ import java.util.UUID; */ public final class DwynensElite extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("another Elf"); + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.ELF, "you control another Elf"); static { filter.add(AnotherPredicate.instance); - filter.add(SubType.ELF.getPredicate()); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + public DwynensElite(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.ELF); @@ -36,11 +37,7 @@ public final class DwynensElite extends CardImpl { this.toughness = new MageInt(2); // When this creature enters, if you control another Elf, create a 1/1 green Elf Warrior creature token. - TriggeredAbility triggeredAbility = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ElfWarriorToken())); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - triggeredAbility, - new PermanentsOnTheBattlefieldCondition(filter), - "When this creature enters, if you control another Elf, create a 1/1 green Elf Warrior creature token.")); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ElfWarriorToken())).withInterveningIf(condition)); } private DwynensElite(final DwynensElite card) { diff --git a/Mage.Sets/src/mage/cards/e/EDELonesomeEyebot.java b/Mage.Sets/src/mage/cards/e/EDELonesomeEyebot.java index b98a5f729ea..fa0c05fd665 100644 --- a/Mage.Sets/src/mage/cards/e/EDELonesomeEyebot.java +++ b/Mage.Sets/src/mage/cards/e/EDELonesomeEyebot.java @@ -1,7 +1,5 @@ package mage.cards.e; -import java.util.UUID; - import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; @@ -9,24 +7,25 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.IntPlusDynamicValue; import mage.abilities.dynamicvalue.common.CountersSourceCount; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.constants.SubType; -import mage.constants.SuperType; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** * @author Cguy7777 */ @@ -45,12 +44,10 @@ public final class EDELonesomeEyebot extends CardImpl { // ED-E My Love -- Whenever you attack, if the number of attacking creatures is greater than the number of quest counters on // ED-E, Lonesome Eyebot, put a quest counter on it. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksWithCreaturesTriggeredAbility(new AddCountersSourceEffect(CounterType.QUEST.createInstance()), 1), - EDELonesomeEyebotCondition.instance, - "Whenever you attack, if the number of attacking creatures is " + - "greater than the number of quest counters on {this}, put a quest counter on it." - ).withFlavorWord("ED-E My Love")); + this.addAbility(new AttacksWithCreaturesTriggeredAbility( + new AddCountersSourceEffect(CounterType.QUEST.createInstance()) + .setText("put a quest counter on it"), 1 + ).withInterveningIf(EDELonesomeEyebotCondition.instance).withFlavorWord("ED-E My Love")); // {2}, Sacrifice ED-E: Draw a card, then draw an additional card for each quest counter on ED-E. Ability ability = new SimpleActivatedAbility( @@ -81,10 +78,12 @@ enum EDELonesomeEyebotCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Permanent permanent = source.getSourcePermanentIfItStillExists(game); - if (permanent == null) { - return false; - } + return permanent != null + && attackingCreatureCount.calculate(game, source, null) > permanent.getCounters(game).getCount(CounterType.QUEST); + } - return attackingCreatureCount.calculate(game, source, null) > permanent.getCounters(game).getCount(CounterType.QUEST); + @Override + public String toString() { + return "the number of attacking creatures is greater than the number of quest counters on {this}"; } } diff --git a/Mage.Sets/src/mage/cards/e/EagleOfDeliverance.java b/Mage.Sets/src/mage/cards/e/EagleOfDeliverance.java index 71c58d6f990..450ea1ab8cf 100644 --- a/Mage.Sets/src/mage/cards/e/EagleOfDeliverance.java +++ b/Mage.Sets/src/mage/cards/e/EagleOfDeliverance.java @@ -17,7 +17,7 @@ import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -41,7 +41,7 @@ public final class EagleOfDeliverance extends CardImpl { TriggeredAbility trigger = new EntersBattlefieldTriggeredAbility( new AddCountersTargetEffect(CounterType.INDESTRUCTIBLE.createInstance()) ); - trigger.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + trigger.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); trigger.addEffect(new EagleOfDeliveranceEffect()); this.addAbility(trigger); } @@ -80,4 +80,4 @@ class EagleOfDeliveranceEffect extends OneShotEffect { } return new DrawCardSourceControllerEffect(1).apply(game, source); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/e/Earthbind.java b/Mage.Sets/src/mage/cards/e/Earthbind.java index ccef1b4d6a5..2ed7479beac 100644 --- a/Mage.Sets/src/mage/cards/e/Earthbind.java +++ b/Mage.Sets/src/mage/cards/e/Earthbind.java @@ -1,7 +1,6 @@ package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.Effect; @@ -14,13 +13,15 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AttachmentType; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) @@ -60,7 +61,7 @@ class EarthbindEffect extends OneShotEffect { EarthbindEffect() { super(Outcome.Damage); - staticText = "if enchanted creature has flying, {this} deals 2 damage to that creature and Earthbind gains \"Enchanted creature loses flying.\""; + staticText = "if enchanted creature has flying, {this} deals 2 damage to that creature and {this} gains \"Enchanted creature loses flying.\""; } private EarthbindEffect(final EarthbindEffect effect) { diff --git a/Mage.Sets/src/mage/cards/e/Earthcraft.java b/Mage.Sets/src/mage/cards/e/Earthcraft.java index 730000169af..325992325aa 100644 --- a/Mage.Sets/src/mage/cards/e/Earthcraft.java +++ b/Mage.Sets/src/mage/cards/e/Earthcraft.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapTargetCost; @@ -10,24 +8,22 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SuperType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.permanent.TappedPredicate; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterLandPermanent; import mage.target.TargetPermanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; /** * @author Loki */ public final class Earthcraft extends CardImpl { - private static final FilterControlledCreaturePermanent filterCreature = new FilterControlledCreaturePermanent("untapped creature you control"); - private static final FilterControlledPermanent filterLand = new FilterControlledPermanent("basic land"); + private static final FilterPermanent filterLand = new FilterLandPermanent("basic land"); static { - filterCreature.add(TappedPredicate.UNTAPPED); - filterLand.add(CardType.LAND.getPredicate()); filterLand.add(SuperType.BASIC.getPredicate()); } @@ -35,7 +31,10 @@ public final class Earthcraft extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); // Tap an untapped creature you control: Untap target basic land. - Ability ability = new SimpleActivatedAbility(new UntapTargetEffect(), new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filterCreature, true))); + Ability ability = new SimpleActivatedAbility( + new UntapTargetEffect(), + new TapTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE)) + ); ability.addTarget(new TargetPermanent(filterLand)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/Earthlore.java b/Mage.Sets/src/mage/cards/e/Earthlore.java index 38750d5e969..27167959e23 100644 --- a/Mage.Sets/src/mage/cards/e/Earthlore.java +++ b/Mage.Sets/src/mage/cards/e/Earthlore.java @@ -1,11 +1,9 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.AttachedToMatchesFilterCondition; -import mage.abilities.costs.Cost; import mage.abilities.costs.common.TapAttachedCost; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; @@ -13,55 +11,48 @@ import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; -import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterBlockingCreature; -import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.target.TargetPermanent; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author L_J */ public final class Earthlore extends CardImpl { - private static final FilterControlledPermanent filterLand = new FilterControlledPermanent("land you control"); - - static { - filterLand.add(CardType.LAND.getPredicate()); - } - private static final FilterPermanent filterUntapped = new FilterPermanent("enchanted land is untapped"); - + static { filterUntapped.add(TappedPredicate.UNTAPPED); } + private static final Condition condition = new AttachedToMatchesFilterCondition(filterUntapped); + public Earthlore(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}"); this.subtype.add(SubType.AURA); // Enchant land you control - TargetPermanent auraTarget = new TargetControlledPermanent(filterLand); + TargetPermanent auraTarget = new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); - Ability ability = new EnchantAbility(auraTarget); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget)); // Tap enchanted land: Target blocking creature gets +1/+2 until end of turn. Activate this ability only if enchanted land is untapped. - Cost cost = new TapAttachedCost(); - cost.setText("Tap enchanted land"); - Ability ability2 = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new BoostTargetEffect(1, 2, Duration.EndOfTurn), cost, new AttachedToMatchesFilterCondition(filterUntapped)); - ability2.addTarget(new TargetCreaturePermanent(new FilterBlockingCreature("blocking creature"))); - this.addAbility(ability2); - + Ability ability = new ActivateIfConditionActivatedAbility( + new BoostTargetEffect(1, 2), + new TapAttachedCost().setText("Tap enchanted land"), condition + ); + ability.addTarget(new TargetPermanent(new FilterBlockingCreature("blocking creature"))); + this.addAbility(ability); } private Earthlore(final Earthlore card) { diff --git a/Mage.Sets/src/mage/cards/e/EarthshakerKhenra.java b/Mage.Sets/src/mage/cards/e/EarthshakerKhenra.java index 760114463da..144dfa9100c 100644 --- a/Mage.Sets/src/mage/cards/e/EarthshakerKhenra.java +++ b/Mage.Sets/src/mage/cards/e/EarthshakerKhenra.java @@ -19,6 +19,7 @@ import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -51,7 +52,7 @@ public final class EarthshakerKhenra extends CardImpl { .setText("target creature with power less than or equal " + "to {this}'s power can't block this turn") ); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Eternalize {4}{R}{R} diff --git a/Mage.Sets/src/mage/cards/e/EarwigSquad.java b/Mage.Sets/src/mage/cards/e/EarwigSquad.java index 5e4e6a2a4b5..2661f3a0605 100644 --- a/Mage.Sets/src/mage/cards/e/EarwigSquad.java +++ b/Mage.Sets/src/mage/cards/e/EarwigSquad.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.ProwlCostWasPaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.search.SearchLibraryAndExileTargetEffect; import mage.abilities.hint.common.ProwlCostWasPaidHint; import mage.abilities.keyword.ProwlAbility; @@ -33,16 +32,11 @@ public final class EarwigSquad extends CardImpl { this.addAbility(new ProwlAbility("{2}{B}")); // When Earwig Squad enters the battlefield, if its prowl cost was paid, search target opponent's library for three cards and exile them. Then that player shuffles their library. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility( - new SearchLibraryAndExileTargetEffect(3, true), false - ), ProwlCostWasPaidCondition.instance, "When {this} enters, " + - "if its prowl cost was paid, search target opponent's library for three cards " + - "and exile them. Then that player shuffles." - ); + Ability ability = new EntersBattlefieldTriggeredAbility( + new SearchLibraryAndExileTargetEffect(3, false), false + ).withInterveningIf(ProwlCostWasPaidCondition.instance); ability.addTarget(new TargetOpponent()); this.addAbility(ability.addHint(ProwlCostWasPaidHint.instance)); - } private EarwigSquad(final EarwigSquad card) { diff --git a/Mage.Sets/src/mage/cards/e/EasternPaladin.java b/Mage.Sets/src/mage/cards/e/EasternPaladin.java index 508336db108..101aa076962 100644 --- a/Mage.Sets/src/mage/cards/e/EasternPaladin.java +++ b/Mage.Sets/src/mage/cards/e/EasternPaladin.java @@ -18,6 +18,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -41,7 +42,7 @@ public final class EasternPaladin extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(3); Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{B}{B}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/EatenBySpiders.java b/Mage.Sets/src/mage/cards/e/EatenBySpiders.java index 3c22bfbd165..7dddb3e0b6b 100644 --- a/Mage.Sets/src/mage/cards/e/EatenBySpiders.java +++ b/Mage.Sets/src/mage/cards/e/EatenBySpiders.java @@ -15,6 +15,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -35,7 +36,7 @@ public final class EatenBySpiders extends CardImpl { // Destroy target creature with flying and all Equipment attached to that creature. this.getSpellAbility().addEffect(new EatenBySpidersEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private EatenBySpiders(final EatenBySpiders card) { diff --git a/Mage.Sets/src/mage/cards/e/EaterOfVirtue.java b/Mage.Sets/src/mage/cards/e/EaterOfVirtue.java index fdc8088aa17..2396ce6f30c 100644 --- a/Mage.Sets/src/mage/cards/e/EaterOfVirtue.java +++ b/Mage.Sets/src/mage/cards/e/EaterOfVirtue.java @@ -1,7 +1,5 @@ package mage.cards.e; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DiesAttachedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -9,38 +7,20 @@ import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; -import mage.abilities.keyword.DeathtouchAbility; -import mage.abilities.keyword.DoubleStrikeAbility; -import mage.abilities.keyword.EquipAbility; -import mage.abilities.keyword.FirstStrikeAbility; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.HexproofAbility; -import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.MenaceAbility; -import mage.abilities.keyword.ProtectionAbility; -import mage.abilities.keyword.ReachAbility; -import mage.abilities.keyword.TrampleAbility; -import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.keyword.*; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SetTargetPointer; -import mage.constants.SubLayer; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.game.ExileZone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.util.CardUtil; +import java.util.Set; +import java.util.UUID; + /** * @author jeffwadsworth */ @@ -112,7 +92,7 @@ class EaterOfVirtueGainAbilityAttachedEffect extends ContinuousEffectImpl { EaterOfVirtueGainAbilityAttachedEffect() { super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); - staticText = "As long as a card exiled with Eater of Virtue has flying, equipped creature has flying. The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, protection, reach, trample, and vigilance"; + staticText = "As long as a card exiled with {this} has flying, equipped creature has flying. The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, protection, reach, trample, and vigilance"; } private EaterOfVirtueGainAbilityAttachedEffect(final EaterOfVirtueGainAbilityAttachedEffect effect) { diff --git a/Mage.Sets/src/mage/cards/e/EbonPraetor.java b/Mage.Sets/src/mage/cards/e/EbonPraetor.java index 46fbd45637e..40c076b68fe 100644 --- a/Mage.Sets/src/mage/cards/e/EbonPraetor.java +++ b/Mage.Sets/src/mage/cards/e/EbonPraetor.java @@ -1,10 +1,7 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.Cost; @@ -14,16 +11,21 @@ import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class EbonPraetor extends CardImpl { @@ -45,8 +47,11 @@ public final class EbonPraetor extends CardImpl { this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.M2M2.createInstance()))); // Sacrifice a creature: Remove a -2/-2 counter from Ebon Praetor. If the sacrificed creature was a Thrull, put a +1/+0 counter on Ebon Praetor. Activate this ability only during your upkeep and only once each turn. - Ability ability = new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new RemoveCounterSourceEffect(CounterType.M2M2.createInstance()), - new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE), 1, new IsStepCondition(PhaseStep.UPKEEP)); + Ability ability = new LimitedTimesPerTurnActivatedAbility( + Zone.BATTLEFIELD, new RemoveCounterSourceEffect(CounterType.M2M2.createInstance()), + new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE), + 1, IsStepCondition.getMyUpkeep() + ); ability.addEffect(new EbonPraetorEffect()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/EbonyHorse.java b/Mage.Sets/src/mage/cards/e/EbonyHorse.java index 05bf3cea578..fbd8d8d8672 100644 --- a/Mage.Sets/src/mage/cards/e/EbonyHorse.java +++ b/Mage.Sets/src/mage/cards/e/EbonyHorse.java @@ -18,6 +18,7 @@ import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -44,7 +45,7 @@ public final class EbonyHorse extends CardImpl { effect = new PreventCombatDamageBySourceEffect(Duration.EndOfTurn); effect.setText("and dealt by that creature this turn"); ability.addEffect(effect); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/EccentricApprentice.java b/Mage.Sets/src/mage/cards/e/EccentricApprentice.java index ebd24d9c3e4..97625efcfb2 100644 --- a/Mage.Sets/src/mage/cards/e/EccentricApprentice.java +++ b/Mage.Sets/src/mage/cards/e/EccentricApprentice.java @@ -2,14 +2,13 @@ package mage.cards.e; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CompletedDungeonCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect; import mage.abilities.hint.common.CurrentDungeonHint; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -41,13 +40,8 @@ public final class EccentricApprentice extends CardImpl { .addHint(CurrentDungeonHint.instance)); // At the beginning of combat on your turn, if you've completed a dungeon, up to one target creature becomes a Bird with base power and toughness 1/1 and flying until end of turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - new EccentricApprenticeEffect() - ), CompletedDungeonCondition.instance, "At the beginning of combat on your turn, " + - "if you've completed a dungeon, up to one target creature becomes a Bird " + - "with base power and toughness 1/1 and flying until end of turn." - ).addHint(CompletedDungeonCondition.getHint()); + Ability ability = new BeginningOfCombatTriggeredAbility(new EccentricApprenticeEffect()) + .withInterveningIf(CompletedDungeonCondition.instance).addHint(CompletedDungeonCondition.getHint()); ability.addTarget(new TargetCreaturePermanent(0, 1)); this.addAbility(ability, new CompletedDungeonWatcher()); } @@ -66,6 +60,7 @@ class EccentricApprenticeEffect extends ContinuousEffectImpl { EccentricApprenticeEffect() { super(Duration.EndOfTurn, Outcome.Benefit); + staticText = "up to one target creature becomes a Bird with base power and toughness 1/1 and flying until end of turn"; } private EccentricApprenticeEffect(final EccentricApprenticeEffect effect) { diff --git a/Mage.Sets/src/mage/cards/e/EchoingAssault.java b/Mage.Sets/src/mage/cards/e/EchoingAssault.java new file mode 100644 index 00000000000..985ecd88d62 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EchoingAssault.java @@ -0,0 +1,107 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.common.AttacksPlayerWithCreaturesTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SetTargetPointer; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author notgreat + */ +public final class EchoingAssault extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("nontoken creature that's attacking that player"); + + static { + filter.add(TokenPredicate.FALSE); + filter.add(EchoingAssaultPredicate.instance); + } + + public EchoingAssault(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{R}"); + + + // Creature tokens you control have menace. + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + new MenaceAbility(false), Duration.WhileOnBattlefield, StaticFilters.FILTER_CREATURE_TOKENS + ))); + + // Whenever you attack a player, choose target nontoken creature that's attacking that player. Create a token that's a copy of that creature, except it's 1/1. The token enters tapped and attacking that player. Sacrifice it at the beginning of the next end step. + Ability ability = new AttacksPlayerWithCreaturesTriggeredAbility(new EchoingAssaultEffect(), SetTargetPointer.NONE); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private EchoingAssault(final EchoingAssault card) { + super(card); + } + + @Override + public EchoingAssault copy() { + return new EchoingAssault(this); + } +} + +enum EchoingAssaultPredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return CardUtil.getEffectValueFromAbility(input.getSource(), "playerAttacked", UUID.class) + .filter(uuid -> uuid.equals(game.getCombat().getDefenderId(input.getObject().getId()))) + .isPresent(); + } +} + +class EchoingAssaultEffect extends OneShotEffect { + + EchoingAssaultEffect() { + super(Outcome.Benefit); + staticText = "choose target nontoken creature that's attacking that player. Create a token that's a copy of that creature, except it's 1/1. The token enters tapped and attacking that player. Sacrifice it at the beginning of the next end step."; + } + + private EchoingAssaultEffect(final EchoingAssaultEffect effect) { + super(effect); + } + + @Override + public EchoingAssaultEffect copy() { + return new EchoingAssaultEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Object attackedPlayer = getValue("playerAttacked"); + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null || !(attackedPlayer instanceof UUID)) { + return false; + } + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(null, null, false, + 1, true, true, (UUID) attackedPlayer, 1, 1, false); + effect.setSavedPermanent(permanent); + effect.apply(game, source); + effect.sacrificeTokensCreatedAtNextEndStep(game, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/e/EddytrailHawk.java b/Mage.Sets/src/mage/cards/e/EddytrailHawk.java index 2fa949d573c..30078a71682 100644 --- a/Mage.Sets/src/mage/cards/e/EddytrailHawk.java +++ b/Mage.Sets/src/mage/cards/e/EddytrailHawk.java @@ -17,6 +17,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterAttackingCreature; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -43,7 +44,7 @@ public final class EddytrailHawk extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(2))); // Whenever Eddytrail Hawk attacks, you may pay {E}. If you do, another target attacking creature gains flying until end of turn. Ability ability = new AttacksTriggeredAbility(new DoIfCostPaid(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), new PayEnergyCost(1))); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/EdgarMarkov.java b/Mage.Sets/src/mage/cards/e/EdgarMarkov.java index 998b482e9fc..095286e69b7 100644 --- a/Mage.Sets/src/mage/cards/e/EdgarMarkov.java +++ b/Mage.Sets/src/mage/cards/e/EdgarMarkov.java @@ -2,11 +2,9 @@ package mage.cards.e; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.common.SourceOnBattlefieldOrCommandZoneCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.counter.AddCountersAllEffect; import mage.abilities.keyword.FirstStrikeAbility; @@ -44,15 +42,10 @@ public final class EdgarMarkov extends CardImpl { this.toughness = new MageInt(4); // Eminence - Whenever you cast another Vampire spell, if Edgar Markov is in the command zone or on the battlefield, create a 1/1 black Vampire creature token. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new SpellCastControllerTriggeredAbility( - Zone.ALL, new CreateTokenEffect(new EdgarMarkovToken()), - filter2, false, SetTargetPointer.NONE - ), - SourceOnBattlefieldOrCommandZoneCondition.instance, - "Whenever you cast another Vampire spell, if {this} is in the command zone or on the battlefield, create a 1/1 black Vampire creature token."); - ability.setAbilityWord(AbilityWord.EMINENCE); - this.addAbility(ability); + this.addAbility(new SpellCastControllerTriggeredAbility( + Zone.ALL, new CreateTokenEffect(new EdgarMarkovToken()), + filter2, false, SetTargetPointer.NONE + ).withInterveningIf(SourceOnBattlefieldOrCommandZoneCondition.instance).setAbilityWord(AbilityWord.EMINENCE)); // First strike this.addAbility(FirstStrikeAbility.getInstance()); diff --git a/Mage.Sets/src/mage/cards/e/EdificeOfAuthority.java b/Mage.Sets/src/mage/cards/e/EdificeOfAuthority.java index 2eb546cec93..03f08147896 100644 --- a/Mage.Sets/src/mage/cards/e/EdificeOfAuthority.java +++ b/Mage.Sets/src/mage/cards/e/EdificeOfAuthority.java @@ -7,7 +7,7 @@ import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.common.combat.CantAttackTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; @@ -40,7 +40,7 @@ public final class EdificeOfAuthority extends CardImpl { this.addAbility(ability); // {1}, {T}: Until your next turn, target creature can't attack or block and its activated abilities can't be activated. Activate this ability only if there are three or more brick counter on Edifice of Authority. - Ability ability2 = new ConditionalActivatedAbility(new EdificeOfAuthorityEffect(), new GenericManaCost(1), condition); + Ability ability2 = new ActivateIfConditionActivatedAbility(new EdificeOfAuthorityEffect(), new GenericManaCost(1), condition); ability2.addCost(new TapSourceCost()); ability2.addTarget(new TargetCreaturePermanent()); this.addAbility(ability2); diff --git a/Mage.Sets/src/mage/cards/e/EerieInterlude.java b/Mage.Sets/src/mage/cards/e/EerieInterlude.java index d4268449675..72d7698beb5 100644 --- a/Mage.Sets/src/mage/cards/e/EerieInterlude.java +++ b/Mage.Sets/src/mage/cards/e/EerieInterlude.java @@ -4,7 +4,6 @@ import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffe import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.StaticFilters; import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; @@ -15,12 +14,12 @@ import java.util.UUID; public final class EerieInterlude extends CardImpl { public EerieInterlude(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[] {CardType.INSTANT}, "{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); // Exile any number of target creatures you control. Return those cards to the // battlefield under their owner's control at the beginning of the next end step. this.getSpellAbility().addEffect(new ExileReturnBattlefieldNextEndStepTargetEffect()); - this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, StaticFilters.FILTER_CONTROLLED_CREATURES, false)); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE)); } private EerieInterlude(final EerieInterlude card) { diff --git a/Mage.Sets/src/mage/cards/e/EfreetWeaponmaster.java b/Mage.Sets/src/mage/cards/e/EfreetWeaponmaster.java index d166d5247b4..1f98778f5d2 100644 --- a/Mage.Sets/src/mage/cards/e/EfreetWeaponmaster.java +++ b/Mage.Sets/src/mage/cards/e/EfreetWeaponmaster.java @@ -13,7 +13,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -37,7 +37,7 @@ public final class EfreetWeaponmaster extends CardImpl { Ability ability = new EntersBattlefieldOrTurnedFaceUpTriggeredAbility( new BoostTargetEffect(3, 0, Duration.EndOfTurn) ); - ability.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); this.addAbility(ability); // Morph {2}{U}{R}{W} diff --git a/Mage.Sets/src/mage/cards/e/EladamriKorvecdal.java b/Mage.Sets/src/mage/cards/e/EladamriKorvecdal.java index 2a61a0911e4..cd24716ae5b 100644 --- a/Mage.Sets/src/mage/cards/e/EladamriKorvecdal.java +++ b/Mage.Sets/src/mage/cards/e/EladamriKorvecdal.java @@ -53,7 +53,7 @@ public final class EladamriKorvecdal extends CardImpl { // {G}, {T}, Tap two untapped creatures you control: Reveal a card from your hand or the top card of your library. If you reveal a creature card this way, put it onto the battlefield. Activate only during your turn. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new EladamriKorvecdalEffect(), new ManaCostsImpl<>("{G}"), MyTurnCondition.instance + new EladamriKorvecdalEffect(), new ManaCostsImpl<>("{G}"), MyTurnCondition.instance ); ability.addCost(new TapSourceCost()); ability.addCost(new TapTargetCost(new TargetControlledPermanent( @@ -163,4 +163,4 @@ class EladamriKorvecdalEffect extends OneShotEffect { } return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/e/EldraziDisplacer.java b/Mage.Sets/src/mage/cards/e/EldraziDisplacer.java index b2399147e84..b963eff65c4 100644 --- a/Mage.Sets/src/mage/cards/e/EldraziDisplacer.java +++ b/Mage.Sets/src/mage/cards/e/EldraziDisplacer.java @@ -12,10 +12,13 @@ import mage.constants.CardType; import mage.constants.PutCards; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * @author LevelX2 */ @@ -32,7 +35,7 @@ public final class EldraziDisplacer extends CardImpl { // {2}{C}: Exile another target creature, then return it to the battlefield tapped under its owner's control. Ability ability = new SimpleActivatedAbility(new ExileThenReturnTargetEffect(false, false, PutCards.BATTLEFIELD_TAPPED), new ManaCostsImpl<>("{2}{C}")); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/EldraziMimic.java b/Mage.Sets/src/mage/cards/e/EldraziMimic.java index 71ae0a5678f..380ef35460a 100644 --- a/Mage.Sets/src/mage/cards/e/EldraziMimic.java +++ b/Mage.Sets/src/mage/cards/e/EldraziMimic.java @@ -2,14 +2,15 @@ package mage.cards.e; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.SetBasePowerToughnessTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.ColorlessPredicate; import mage.game.Game; @@ -24,7 +25,7 @@ import java.util.UUID; */ public final class EldraziMimic extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another colorless creature"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("another colorless creature you control"); static { filter.add(AnotherPredicate.instance); @@ -39,7 +40,7 @@ public final class EldraziMimic extends CardImpl { // Whenever another colorless creature you control enters, you may have the base power and toughness of Eldrazi Mimic // become that creature's power and toughness until end of turn. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + this.addAbility(new EntersBattlefieldAllTriggeredAbility( Zone.BATTLEFIELD, new EldraziMimicEffect(), filter, true, SetTargetPointer.PERMANENT )); @@ -59,7 +60,7 @@ class EldraziMimicEffect extends OneShotEffect { EldraziMimicEffect() { super(Outcome.BoostCreature); - staticText = "you may have the base power and toughness of {this} become that creature's power and toughness until end of turn"; + staticText = "you may change {this}'s base power and toughness to that creature's power and toughness until end of turn"; } private EldraziMimicEffect(final EldraziMimicEffect effect) { diff --git a/Mage.Sets/src/mage/cards/e/EldraziObligator.java b/Mage.Sets/src/mage/cards/e/EldraziObligator.java index 9f96a410810..88e08b5d541 100644 --- a/Mage.Sets/src/mage/cards/e/EldraziObligator.java +++ b/Mage.Sets/src/mage/cards/e/EldraziObligator.java @@ -20,6 +20,7 @@ import mage.constants.SubType; import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -51,7 +52,7 @@ public final class EldraziObligator extends CardImpl { // When you cast Eldrazi Obligator, you may pay {1}{C}. If you do, gain control of target creature until end of turn. Untap that creature. It gains haste until end of turn. Ability ability = new CastSourceTriggeredAbility(costPaidEffect); - Target target = new TargetCreaturePermanent(new FilterCreaturePermanent()); + Target target = new TargetPermanent(new FilterCreaturePermanent()); ability.addTarget(target); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/Electrickery.java b/Mage.Sets/src/mage/cards/e/Electrickery.java index 06bd5c7d6a6..080f40aa755 100644 --- a/Mage.Sets/src/mage/cards/e/Electrickery.java +++ b/Mage.Sets/src/mage/cards/e/Electrickery.java @@ -8,10 +8,13 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author LevelX2 */ @@ -21,7 +24,7 @@ public final class Electrickery extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); // Electrickery deals 1 damage to target creature you don't control. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.getSpellAbility().addEffect(new DamageTargetEffect(1)); // Overload {1}{R} (You may cast this spell for its overload cost. If you do, change its text by replacing all instances of "target" with "each.") diff --git a/Mage.Sets/src/mage/cards/e/ElementalBond.java b/Mage.Sets/src/mage/cards/e/ElementalBond.java index 93b0d78975f..b4ecb0170b8 100644 --- a/Mage.Sets/src/mage/cards/e/ElementalBond.java +++ b/Mage.Sets/src/mage/cards/e/ElementalBond.java @@ -1,8 +1,6 @@ - package mage.cards.e; -import java.util.UUID; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -12,23 +10,24 @@ import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import java.util.UUID; + /** - * * @author emerald000 */ public final class ElementalBond extends CardImpl { - private static final FilterPermanent filter = new FilterControlledCreaturePermanent("a creature with power 3 or greater"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("a creature you control with power 3 or greater"); static { filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 2)); } public ElementalBond(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); // Whenever a creature with power 3 or greater you control enters, draw a card. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new DrawCardSourceControllerEffect(1), filter)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility(new DrawCardSourceControllerEffect(1), filter)); } private ElementalBond(final ElementalBond card) { diff --git a/Mage.Sets/src/mage/cards/e/EliteScaleguard.java b/Mage.Sets/src/mage/cards/e/EliteScaleguard.java index 3b871ebe303..bc4e861d5ae 100644 --- a/Mage.Sets/src/mage/cards/e/EliteScaleguard.java +++ b/Mage.Sets/src/mage/cards/e/EliteScaleguard.java @@ -1,6 +1,5 @@ package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksCreatureYouControlTriggeredAbility; @@ -16,10 +15,12 @@ import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.targetadjustment.TargetAdjuster; import mage.target.targetpointer.FirstTargetPointer; +import java.util.UUID; + /** * @author emerald000 */ @@ -41,7 +42,7 @@ public final class EliteScaleguard extends CardImpl { false, StaticFilters.FILTER_CONTROLLED_CREATURE_P1P1, true); - ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature defending player controls"))); + ability.addTarget(new TargetPermanent(new FilterCreaturePermanent("creature defending player controls"))); ability.setTargetAdjuster(EliteScaleguardTargetAdjuster.instance); this.addAbility(ability); } @@ -70,7 +71,6 @@ enum EliteScaleguardTargetAdjuster implements TargetAdjuster { } } ability.getTargets().clear(); - TargetCreaturePermanent target = new TargetCreaturePermanent(filterDefender); - ability.addTarget(target); + ability.addTarget(new TargetPermanent(filterDefender)); } } diff --git a/Mage.Sets/src/mage/cards/e/ElvenFortress.java b/Mage.Sets/src/mage/cards/e/ElvenFortress.java index 7b6c2a404aa..58447dbe001 100644 --- a/Mage.Sets/src/mage/cards/e/ElvenFortress.java +++ b/Mage.Sets/src/mage/cards/e/ElvenFortress.java @@ -12,6 +12,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterBlockingCreature; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -25,7 +26,7 @@ public final class ElvenFortress extends CardImpl { // {1}{G}: Target blocking creature gets +0/+1 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(0, 1, Duration.EndOfTurn), new ManaCostsImpl<>("{1}{G}")); - ability.addTarget(new TargetCreaturePermanent(new FilterBlockingCreature())); + ability.addTarget(new TargetPermanent(new FilterBlockingCreature())); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/ElvishArchivist.java b/Mage.Sets/src/mage/cards/e/ElvishArchivist.java index d8fa064aa98..381e69c7ddb 100644 --- a/Mage.Sets/src/mage/cards/e/ElvishArchivist.java +++ b/Mage.Sets/src/mage/cards/e/ElvishArchivist.java @@ -1,7 +1,7 @@ package mage.cards.e; import mage.MageInt; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; @@ -9,7 +9,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; -import mage.filter.StaticFilters; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.common.FilterControlledEnchantmentPermanent; import java.util.UUID; @@ -18,6 +20,9 @@ import java.util.UUID; */ public final class ElvishArchivist extends CardImpl { + private static final FilterPermanent filter = new FilterControlledArtifactPermanent("one or more artifacts you control"); + private static final FilterPermanent filter2 = new FilterControlledEnchantmentPermanent("one or more enchantments you control"); + public ElvishArchivist(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); @@ -27,18 +32,14 @@ public final class ElvishArchivist extends CardImpl { this.toughness = new MageInt(1); // Whenever one or more artifacts enter the battlefield under your control, put two +1/+1 counters on Elvish Archivist. This ability triggers only once each turn. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), - StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT - ).setTriggersLimitEachTurn(1) - .setTriggerPhrase("Whenever one or more artifacts enter the battlefield under your control, ")); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), filter + ).setTriggersLimitEachTurn(1)); // Whenever one or more enchantments enter the battlefield under your control, draw a card. This ability triggers only once each turn. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility( - new DrawCardSourceControllerEffect(1), - StaticFilters.FILTER_CONTROLLED_PERMANENT_ENCHANTMENT - ).setTriggersLimitEachTurn(1) - .setTriggerPhrase("Whenever one or more enchantments enter the battlefield under your control, ")); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new DrawCardSourceControllerEffect(1), filter2 + ).setTriggersLimitEachTurn(1)); } private ElvishArchivist(final ElvishArchivist card) { diff --git a/Mage.Sets/src/mage/cards/e/ElvishHydromancer.java b/Mage.Sets/src/mage/cards/e/ElvishHydromancer.java index 444264ff141..488b81b9412 100644 --- a/Mage.Sets/src/mage/cards/e/ElvishHydromancer.java +++ b/Mage.Sets/src/mage/cards/e/ElvishHydromancer.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; @@ -32,11 +31,7 @@ public final class ElvishHydromancer extends CardImpl { this.addAbility(new KickerAbility("{3}{U}")); // When Elvish Hydromancer enters the battlefield, if it was kicked, create a token that's a copy of target creature you control. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CreateTokenCopyTargetEffect()), - KickedCondition.ONCE, "When {this} enters, " + - "if it was kicked, create a token that's a copy of target creature you control." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new CreateTokenCopyTargetEffect()).withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/ElvishPathcutter.java b/Mage.Sets/src/mage/cards/e/ElvishPathcutter.java index e44dbfb0d4f..39e1b3d7201 100644 --- a/Mage.Sets/src/mage/cards/e/ElvishPathcutter.java +++ b/Mage.Sets/src/mage/cards/e/ElvishPathcutter.java @@ -15,6 +15,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class ElvishPathcutter extends CardImpl { // {2}{G}: Target Elf creature gains forestwalk until end of turn. Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(new ForestwalkAbility(false), Duration.EndOfTurn), new ManaCostsImpl<>("{2}{G}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/ElvishScout.java b/Mage.Sets/src/mage/cards/e/ElvishScout.java index 9c5a2d865b4..5528ae94f66 100644 --- a/Mage.Sets/src/mage/cards/e/ElvishScout.java +++ b/Mage.Sets/src/mage/cards/e/ElvishScout.java @@ -1,40 +1,38 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.PreventDamageByTargetEffect; import mage.abilities.effects.common.PreventDamageToTargetEffect; import mage.abilities.effects.common.UntapTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.AttackingPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LoneFox */ public final class ElvishScout extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("attacking creature you control"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("attacking creature you control"); static { filter.add(AttackingPredicate.instance); } public ElvishScout(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.SCOUT); this.power = new MageInt(1); @@ -43,13 +41,12 @@ public final class ElvishScout extends CardImpl { // {G}, {tap}: Untap target attacking creature you control. Prevent all combat damage that would be dealt to and dealt by it this turn. Ability ability = new SimpleActivatedAbility(new UntapTargetEffect(), new ManaCostsImpl<>("{G}")); ability.addCost(new TapSourceCost()); - Effect effect = new PreventDamageByTargetEffect(Duration.EndOfTurn, true); - effect.setText("Prevent all combat damage that would be dealt to"); - ability.addEffect(effect); - effect = new PreventDamageToTargetEffect(Duration.EndOfTurn, Integer.MAX_VALUE, true); - effect.setText("and dealt by it this turn"); - ability.addEffect(effect); - ability.addTarget(new TargetControlledCreaturePermanent(filter)); + ability.addEffect(new PreventDamageByTargetEffect(Duration.EndOfTurn, true) + .setText("Prevent all combat damage that would be dealt to")); + ability.addEffect(new PreventDamageToTargetEffect( + Duration.EndOfTurn, Integer.MAX_VALUE, true + ).setText("and dealt by it this turn")); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/ElvishSkysweeper.java b/Mage.Sets/src/mage/cards/e/ElvishSkysweeper.java index 9aff07445f5..be06a8f9757 100644 --- a/Mage.Sets/src/mage/cards/e/ElvishSkysweeper.java +++ b/Mage.Sets/src/mage/cards/e/ElvishSkysweeper.java @@ -17,6 +17,7 @@ import mage.constants.Zone; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; @@ -43,7 +44,7 @@ public final class ElvishSkysweeper extends CardImpl { // {4}{G}, Sacrifice a creature: Destroy target creature with flying. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{4}{G}")); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/ElvishWarmaster.java b/Mage.Sets/src/mage/cards/e/ElvishWarmaster.java index 4be24168211..ac8f1f5cd6b 100644 --- a/Mage.Sets/src/mage/cards/e/ElvishWarmaster.java +++ b/Mage.Sets/src/mage/cards/e/ElvishWarmaster.java @@ -2,7 +2,7 @@ package mage.cards.e; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.CreateTokenEffect; @@ -15,6 +15,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.permanent.token.ElfWarriorToken; @@ -26,7 +27,7 @@ import java.util.UUID; */ public final class ElvishWarmaster extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent(SubType.ELF, "one or more other Elves"); + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.ELF, "one or more other Elves you control"); private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent(SubType.ELF, "Elves"); static { @@ -42,7 +43,7 @@ public final class ElvishWarmaster extends CardImpl { this.toughness = new MageInt(2); // Whenever one or more other Elves you control enters, create a 1/1 green Elf Warrior creature token. This ability triggers only once each turn. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + this.addAbility(new EntersBattlefieldAllTriggeredAbility( new CreateTokenEffect(new ElfWarriorToken()), filter ).setTriggersLimitEachTurn(1)); diff --git a/Mage.Sets/src/mage/cards/e/EmberwildeAugur.java b/Mage.Sets/src/mage/cards/e/EmberwildeAugur.java index f4fd107c7d4..f922013091a 100644 --- a/Mage.Sets/src/mage/cards/e/EmberwildeAugur.java +++ b/Mage.Sets/src/mage/cards/e/EmberwildeAugur.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -12,12 +10,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.PhaseStep; -import mage.constants.Zone; import mage.target.common.TargetPlayerOrPlaneswalker; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class EmberwildeAugur extends CardImpl { @@ -32,10 +29,8 @@ public final class EmberwildeAugur extends CardImpl { // Sacrifice Emberwilde Augur: Emberwilde Augur deals 3 damage to target player. Activate this ability only during your upkeep. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new DamageTargetEffect(3, "it"), - new SacrificeSourceCost(), - new IsStepCondition(PhaseStep.UPKEEP)); + new SacrificeSourceCost(), IsStepCondition.getMyUpkeep()); ability.addTarget(new TargetPlayerOrPlaneswalker()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/EmbraceOblivion.java b/Mage.Sets/src/mage/cards/e/EmbraceOblivion.java new file mode 100644 index 00000000000..f0d32b67e15 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EmbraceOblivion.java @@ -0,0 +1,49 @@ +package mage.cards.e; + +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EmbraceOblivion extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("creature or Spacecraft"); + + static { + filter.add(Predicates.or( + CardType.CREATURE.getPredicate(), + SubType.SPACECRAFT.getPredicate() + )); + } + + public EmbraceOblivion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); + + // As an additional cost to cast this spell, sacrifice an artifact or creature. + this.getSpellAbility().addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE)); + + // Destroy target creature or Spacecraft. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + } + + private EmbraceOblivion(final EmbraceOblivion card) { + super(card); + } + + @Override + public EmbraceOblivion copy() { + return new EmbraceOblivion(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EmergencyEject.java b/Mage.Sets/src/mage/cards/e/EmergencyEject.java new file mode 100644 index 00000000000..4cd370e4dd7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EmergencyEject.java @@ -0,0 +1,35 @@ +package mage.cards.e; + +import mage.abilities.effects.common.CreateTokenControllerTargetEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.LanderToken; +import mage.target.common.TargetNonlandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EmergencyEject extends CardImpl { + + public EmergencyEject(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); + + // Destroy target nonland permanent. Its controller creates a Lander token. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addEffect(new CreateTokenControllerTargetEffect(new LanderToken())); + this.getSpellAbility().addTarget(new TargetNonlandPermanent()); + } + + private EmergencyEject(final EmergencyEject card) { + super(card); + } + + @Override + public EmergencyEject copy() { + return new EmergencyEject(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EmergentUltimatum.java b/Mage.Sets/src/mage/cards/e/EmergentUltimatum.java index e9f2af707bc..8a7830e7c05 100644 --- a/Mage.Sets/src/mage/cards/e/EmergentUltimatum.java +++ b/Mage.Sets/src/mage/cards/e/EmergentUltimatum.java @@ -79,6 +79,8 @@ class EmergentUltimatumEffect extends OneShotEffect { boolean searched = player.searchLibrary(targetCardInLibrary, source, game); Cards cards = new CardsImpl(targetCardInLibrary.getTargets()); player.moveCards(cards, Zone.EXILED, source, game); + game.processAction(); + cards.retainZone(Zone.EXILED, game); if (cards.isEmpty()) { if (searched) { player.shuffleLibrary(source, game); diff --git a/Mage.Sets/src/mage/cards/e/EmissaryEscort.java b/Mage.Sets/src/mage/cards/e/EmissaryEscort.java new file mode 100644 index 00000000000..5290d60cd92 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EmissaryEscort.java @@ -0,0 +1,44 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.GreatestAmongPermanentsValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EmissaryEscort extends CardImpl { + + public EmissaryEscort(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.ROBOT); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(0); + this.toughness = new MageInt(4); + + // This creature gets +X/+0 where X is the greatest mana value among other artifacts you control. + this.addAbility(new SimpleStaticAbility(new BoostSourceEffect( + GreatestAmongPermanentsValue.MANAVALUE_OTHER_CONTROLLED_ARTIFACTS, + StaticValue.get(0), Duration.WhileOnBattlefield + )).addHint(GreatestAmongPermanentsValue.MANAVALUE_OTHER_CONTROLLED_ARTIFACTS.getHint())); + } + + private EmissaryEscort(final EmissaryEscort card) { + super(card); + } + + @Override + public EmissaryEscort copy() { + return new EmissaryEscort(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EmissaryOfTheSleepless.java b/Mage.Sets/src/mage/cards/e/EmissaryOfTheSleepless.java index 5e0d08e6727..15883d31437 100644 --- a/Mage.Sets/src/mage/cards/e/EmissaryOfTheSleepless.java +++ b/Mage.Sets/src/mage/cards/e/EmissaryOfTheSleepless.java @@ -1,12 +1,8 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.MorbidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.common.MorbidHint; import mage.abilities.keyword.FlyingAbility; @@ -16,24 +12,25 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.game.permanent.token.SpiritWhiteToken; +import java.util.UUID; + /** - * * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class EmissaryOfTheSleepless extends CardImpl { public EmissaryOfTheSleepless(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); this.subtype.add(SubType.SPIRIT); this.power = new MageInt(2); this.toughness = new MageInt(4); // Flying this.addAbility(FlyingAbility.getInstance()); - + // When Emissary of the Sleepless enters the battlefield, if a creature died this turn, create a 1/1 white Spirit creature token with flying. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new SpiritWhiteToken())); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, MorbidCondition.instance, "When {this} enters, if a creature died this turn, create a 1/1 white Spirit creature token with flying.").addHint(MorbidHint.instance)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new SpiritWhiteToken())) + .withInterveningIf(MorbidCondition.instance).addHint(MorbidHint.instance)); } private EmissaryOfTheSleepless(final EmissaryOfTheSleepless card) { diff --git a/Mage.Sets/src/mage/cards/e/EmptyShrineKannushi.java b/Mage.Sets/src/mage/cards/e/EmptyShrineKannushi.java index 09bf4f22be0..fdb8e33b2ea 100644 --- a/Mage.Sets/src/mage/cards/e/EmptyShrineKannushi.java +++ b/Mage.Sets/src/mage/cards/e/EmptyShrineKannushi.java @@ -114,7 +114,7 @@ class EmptyShrineKannushiProtectionAbility extends ProtectionAbility { @Override public String getRule() { - return "Empty-Shrine Kannushi has protection from the colors of permanents you control."; + return "{this} has protection from the colors of permanents you control."; } } diff --git a/Mage.Sets/src/mage/cards/e/EncaseInIce.java b/Mage.Sets/src/mage/cards/e/EncaseInIce.java index 9dc67bbfc9c..200c3f5ebbc 100644 --- a/Mage.Sets/src/mage/cards/e/EncaseInIce.java +++ b/Mage.Sets/src/mage/cards/e/EncaseInIce.java @@ -44,7 +44,7 @@ public final class EncaseInIce extends CardImpl { this.addAbility(FlashAbility.getInstance()); // Enchant red or green creature - TargetPermanent auraTarget = new TargetCreaturePermanent(filter); + TargetPermanent auraTarget = new TargetPermanent(filter); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); this.addAbility(new EnchantAbility(auraTarget)); diff --git a/Mage.Sets/src/mage/cards/e/EndlessAtlas.java b/Mage.Sets/src/mage/cards/e/EndlessAtlas.java index 913fad07686..929ffa35b86 100644 --- a/Mage.Sets/src/mage/cards/e/EndlessAtlas.java +++ b/Mage.Sets/src/mage/cards/e/EndlessAtlas.java @@ -1,8 +1,5 @@ package mage.cards.e; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.Condition; @@ -12,13 +9,15 @@ import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class EndlessAtlas extends CardImpl { @@ -28,10 +27,8 @@ public final class EndlessAtlas extends CardImpl { // {2}, {T}: Draw a card. Activate this ability only if you control three or more lands with the same name. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), - new GenericManaCost(2), - new EndlessAtlasCondition() + new GenericManaCost(2), EndlessAtlasCondition.instance ); ability.addCost(new TapSourceCost()); this.addAbility(ability); @@ -47,7 +44,8 @@ public final class EndlessAtlas extends CardImpl { } } -class EndlessAtlasCondition implements Condition { +enum EndlessAtlasCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { diff --git a/Mage.Sets/src/mage/cards/e/EndlessRanksOfTheDead.java b/Mage.Sets/src/mage/cards/e/EndlessRanksOfTheDead.java index ed43c862c98..667e117aede 100644 --- a/Mage.Sets/src/mage/cards/e/EndlessRanksOfTheDead.java +++ b/Mage.Sets/src/mage/cards/e/EndlessRanksOfTheDead.java @@ -1,34 +1,34 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.game.Game; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.token.ZombieToken; +import java.util.UUID; + /** - * * @author BetaSteward */ public final class EndlessRanksOfTheDead extends CardImpl { public EndlessRanksOfTheDead(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); // At the beginning of your upkeep, create X 2/2 black Zombie creature tokens, // where X is half the number of Zombies you control, rounded down. - this.addAbility(new OnEventTriggeredAbility(EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", - new CreateTokenEffect(new ZombieToken(), new HalfZombiesCount()))); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new CreateTokenEffect(new ZombieToken(), HalfZombiesCount.instance) + )); } @@ -42,23 +42,19 @@ public final class EndlessRanksOfTheDead extends CardImpl { } } -class HalfZombiesCount implements DynamicValue { +enum HalfZombiesCount implements DynamicValue { + instance; - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - - static { - filter.add(SubType.ZOMBIE.getPredicate()); - } + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.ZOMBIE); @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - int amount = game.getBattlefield().countAll(filter, sourceAbility.getControllerId(), game) / 2; - return amount; + return game.getBattlefield().count(filter, sourceAbility.getControllerId(), sourceAbility, game) / 2; } @Override public HalfZombiesCount copy() { - return new HalfZombiesCount(); + return this; } @Override diff --git a/Mage.Sets/src/mage/cards/e/EnduringInnocence.java b/Mage.Sets/src/mage/cards/e/EnduringInnocence.java index a6a858d5355..0979d175c57 100644 --- a/Mage.Sets/src/mage/cards/e/EnduringInnocence.java +++ b/Mage.Sets/src/mage/cards/e/EnduringInnocence.java @@ -2,7 +2,7 @@ package mage.cards.e; import mage.MageInt; import mage.abilities.common.EnduringGlimmerTriggeredAbility; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.LifelinkAbility; import mage.cards.CardImpl; @@ -22,7 +22,7 @@ import java.util.UUID; */ public final class EnduringInnocence extends CardImpl { - private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("one or more other creatures you control with power 2 or less"); static { filter.add(AnotherPredicate.instance); @@ -41,10 +41,9 @@ public final class EnduringInnocence extends CardImpl { this.addAbility(LifelinkAbility.getInstance()); // Whenever one or more other creatures you control with power 2 or less enter, draw a card. This ability triggers only once each turn. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + this.addAbility(new EntersBattlefieldAllTriggeredAbility( new DrawCardSourceControllerEffect(1), filter - ).setTriggersLimitEachTurn(1) - .setTriggerPhrase("Whenever one or more other creatures you control with power 2 or less enter, ")); + ).setTriggersLimitEachTurn(1)); // When Enduring Innocence dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment. this.addAbility(new EnduringGlimmerTriggeredAbility()); diff --git a/Mage.Sets/src/mage/cards/e/EnduringVictory.java b/Mage.Sets/src/mage/cards/e/EnduringVictory.java index 9fb4f85bf2f..7a9b2ef1bf1 100644 --- a/Mage.Sets/src/mage/cards/e/EnduringVictory.java +++ b/Mage.Sets/src/mage/cards/e/EnduringVictory.java @@ -8,6 +8,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterAttackingOrBlockingCreature; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -20,7 +21,7 @@ public final class EnduringVictory extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{4}{W}"); // Destroy target attacking or blocking creature. Bolster 1. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterAttackingOrBlockingCreature())); + this.getSpellAbility().addTarget(new TargetPermanent(new FilterAttackingOrBlockingCreature())); this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addEffect(new BolsterEffect(1)); } diff --git a/Mage.Sets/src/mage/cards/e/EnergyTap.java b/Mage.Sets/src/mage/cards/e/EnergyTap.java index a1c89e44828..aa7f0c0d602 100644 --- a/Mage.Sets/src/mage/cards/e/EnergyTap.java +++ b/Mage.Sets/src/mage/cards/e/EnergyTap.java @@ -1,6 +1,5 @@ package mage.cards.e; -import java.util.UUID; import mage.Mana; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -13,10 +12,11 @@ import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author spjspj */ public final class EnergyTap extends CardImpl { @@ -31,7 +31,7 @@ public final class EnergyTap extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}"); // Tap target untapped creature you control. If you do, add an amount of {C} equal to that creature's converted mana cost. - this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new EnergyTapEffect()); } diff --git a/Mage.Sets/src/mage/cards/e/EnergyVortex.java b/Mage.Sets/src/mage/cards/e/EnergyVortex.java index 017a8a5e11a..daf465e579b 100644 --- a/Mage.Sets/src/mage/cards/e/EnergyVortex.java +++ b/Mage.Sets/src/mage/cards/e/EnergyVortex.java @@ -15,7 +15,9 @@ import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; @@ -49,12 +51,11 @@ public final class EnergyVortex extends CardImpl { // {X}: Put X vortex counters on Energy Vortex. Activate this ability only during your upkeep. this.addAbility(new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new AddCountersSourceEffect( CounterType.VORTEX.createInstance(), GetXValue.instance, true ), new ManaCostsImpl<>("{X}"), - new IsStepCondition(PhaseStep.UPKEEP) + IsStepCondition.getMyUpkeep() )); } diff --git a/Mage.Sets/src/mage/cards/e/EnslavedDwarf.java b/Mage.Sets/src/mage/cards/e/EnslavedDwarf.java index b24361a8199..8b7ac13fc2b 100644 --- a/Mage.Sets/src/mage/cards/e/EnslavedDwarf.java +++ b/Mage.Sets/src/mage/cards/e/EnslavedDwarf.java @@ -20,6 +20,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -48,7 +49,7 @@ public final class EnslavedDwarf extends CardImpl { effect = new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn); effect.setText("and gains first strike until end of turn"); ability.addEffect(effect); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/EntanglingVines.java b/Mage.Sets/src/mage/cards/e/EntanglingVines.java index 394f004d1bc..fa8ea12f57e 100644 --- a/Mage.Sets/src/mage/cards/e/EntanglingVines.java +++ b/Mage.Sets/src/mage/cards/e/EntanglingVines.java @@ -35,7 +35,7 @@ public final class EntanglingVines extends CardImpl { // Enchant tapped creature - TargetPermanent auraTarget = new TargetCreaturePermanent(filter); + TargetPermanent auraTarget = new TargetPermanent(filter); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); this.addAbility(new EnchantAbility(auraTarget)); diff --git a/Mage.Sets/src/mage/cards/e/EnthrallingVictor.java b/Mage.Sets/src/mage/cards/e/EnthrallingVictor.java index 8d091b1fc43..45428757d83 100644 --- a/Mage.Sets/src/mage/cards/e/EnthrallingVictor.java +++ b/Mage.Sets/src/mage/cards/e/EnthrallingVictor.java @@ -19,6 +19,7 @@ import mage.constants.Duration; import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; @@ -48,7 +49,7 @@ public final class EnthrallingVictor extends CardImpl { effect.setText("untap that creature"); ability.addEffect(effect); ability.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn, "it gains haste until end of turn")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/EntrancingMelody.java b/Mage.Sets/src/mage/cards/e/EntrancingMelody.java index ac81fb37a4e..2a71a9d366b 100644 --- a/Mage.Sets/src/mage/cards/e/EntrancingMelody.java +++ b/Mage.Sets/src/mage/cards/e/EntrancingMelody.java @@ -7,6 +7,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.XManaValueTargetAdjuster; @@ -24,7 +25,7 @@ public final class EntrancingMelody extends CardImpl { // Gain control of target creature with converted mana cost X. this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.Custom, true)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().setTargetAdjuster(new XManaValueTargetAdjuster()); } diff --git a/Mage.Sets/src/mage/cards/e/EomerOfTheRiddermark.java b/Mage.Sets/src/mage/cards/e/EomerOfTheRiddermark.java index e22562d33a1..45826738791 100644 --- a/Mage.Sets/src/mage/cards/e/EomerOfTheRiddermark.java +++ b/Mage.Sets/src/mage/cards/e/EomerOfTheRiddermark.java @@ -3,7 +3,6 @@ package mage.cards.e; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.ControlsCreatureGreatestPowerCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; @@ -40,12 +39,8 @@ public final class EomerOfTheRiddermark extends CardImpl { this.addAbility(HasteAbility.getInstance()); // Whenever Eomer of the Riddermark attacks, if you control a creature with the greatest power among creatures on the battlefield, create a 1/1 white Human Soldier creature token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new CreateTokenEffect(new HumanSoldierToken())), - ControlsCreatureGreatestPowerCondition.instance, "Whenever {this} attacks, " + - "if you control a creature with the greatest power among creatures on the battlefield, " + - "create a 1/1 white Human Soldier creature token." - ).addHint(hint)); + this.addAbility(new AttacksTriggeredAbility(new CreateTokenEffect(new HumanSoldierToken())) + .withInterveningIf(ControlsCreatureGreatestPowerCondition.instance).addHint(hint)); } private EomerOfTheRiddermark(final EomerOfTheRiddermark card) { diff --git a/Mage.Sets/src/mage/cards/e/EonFrolicker.java b/Mage.Sets/src/mage/cards/e/EonFrolicker.java index a042d7761eb..a11bccab173 100644 --- a/Mage.Sets/src/mage/cards/e/EonFrolicker.java +++ b/Mage.Sets/src/mage/cards/e/EonFrolicker.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityControllerEffect; @@ -43,12 +42,8 @@ public final class EonFrolicker extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Eon Frolicker enters the battlefield, if you cast it, target opponent takes an extra turn after this one. Until your next turn, you and planeswalkers you control gain protection from that player. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new EonFrolickerEffect()), - CastFromEverywhereSourceCondition.instance, "When {this} enters, " + - "if you cast it, target opponent takes an extra turn after this one. Until your next turn, " + - "you and planeswalkers you control gain protection from that player." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new EonFrolickerEffect()) + .withInterveningIf(CastFromEverywhereSourceCondition.instance); ability.addTarget(new TargetOpponent()); this.addAbility(ability); } @@ -67,6 +62,8 @@ class EonFrolickerEffect extends OneShotEffect { EonFrolickerEffect() { super(Outcome.Benefit); + staticText = "target opponent takes an extra turn after this one. Until your next turn, " + + "you and planeswalkers you control gain protection from that player"; } private EonFrolickerEffect(final EonFrolickerEffect effect) { diff --git a/Mage.Sets/src/mage/cards/e/EowynFearlessKnight.java b/Mage.Sets/src/mage/cards/e/EowynFearlessKnight.java index 007d1481630..2e9583ac6d6 100644 --- a/Mage.Sets/src/mage/cards/e/EowynFearlessKnight.java +++ b/Mage.Sets/src/mage/cards/e/EowynFearlessKnight.java @@ -76,6 +76,11 @@ enum EowynFearlessKnightPredicate implements ObjectSourcePlayerPredicate permanent.getPower().getValue() < input.getObject().getPower().getValue()).orElse(false); } + + @Override + public String toString() { + return "another Human entered the battlefield under your control this turn"; + } } class EowynFearlessKnightEffect extends OneShotEffect { diff --git a/Mage.Sets/src/mage/cards/e/EowynShieldmaiden.java b/Mage.Sets/src/mage/cards/e/EowynShieldmaiden.java index 1fc5e8bfb1b..a8a82a056ab 100644 --- a/Mage.Sets/src/mage/cards/e/EowynShieldmaiden.java +++ b/Mage.Sets/src/mage/cards/e/EowynShieldmaiden.java @@ -3,15 +3,13 @@ package mage.cards.e; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -25,16 +23,17 @@ import mage.watchers.Watcher; import java.util.*; /** - * * @author Susucr */ public final class EowynShieldmaiden extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent(SubType.HUMAN, "Humans"); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterPermanent(SubType.HUMAN, ""), ComparisonType.MORE_THAN, 5 + ); public EowynShieldmaiden(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{R}{W}"); - + this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.KNIGHT); @@ -48,27 +47,14 @@ public final class EowynShieldmaiden extends CardImpl { // if another Human entered the battlefield under your control this turn, // create two 2/2 red Human Knight creature tokens with trample and haste. // Then if you control six or more Humans, draw a card. - - TriggeredAbility triggeredAbility = new BeginningOfCombatTriggeredAbility( - Zone.BATTLEFIELD, - TargetController.YOU, new CreateTokenEffect(new HumanKnightToken(), 2), - false - ); - triggeredAbility.addEffect(new ConditionalOneShotEffect( - new DrawCardSourceControllerEffect(1), - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 5) + Ability ability = new BeginningOfCombatTriggeredAbility( + TargetController.YOU, new CreateTokenEffect(new HumanKnightToken(), 2), false + ).withInterveningIf(EowynShieldmaidenCondition.instance); + ability.addEffect(new ConditionalOneShotEffect( + new DrawCardSourceControllerEffect(1), condition, + "Then if you control six or more Humans, draw a card" )); - - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - triggeredAbility, - EowynShieldmaidenCondition.instance, - "At the beginning of combat on your turn, " - + "if another Human entered the battlefield " - + "under your control this turn, create two " - + "2/2 red Human Knight creature tokens with " - + "trample and haste. " - + "Then if you control six or more Humans, draw a card." - ), new EowynShieldmaidenWatcher()); + this.addAbility(ability, new EowynShieldmaidenWatcher()); } private EowynShieldmaiden(final EowynShieldmaiden card) { @@ -88,11 +74,16 @@ enum EowynShieldmaidenCondition implements Condition { public boolean apply(Game game, Ability source) { EowynShieldmaidenWatcher watcher = game.getState().getWatcher(EowynShieldmaidenWatcher.class); return watcher != null - && watcher.hasPlayerHadAnotherHumanEnterThisTurn( + && watcher.hasPlayerHadAnotherHumanEnterThisTurn( game, source.getSourcePermanentOrLKI(game), source.getControllerId()); } + + @Override + public String toString() { + return "another Human entered the battlefield under your control this turn"; + } } class EowynShieldmaidenWatcher extends Watcher { @@ -137,11 +128,11 @@ class EowynShieldmaidenWatcher extends Watcher { // we do use MageObjectReference for when eowyn is entering the battlefield // multiple time in the same turn (flickered for instance) MageObjectReference sourceMOR = sourcePermanent == null ? null - : new MageObjectReference(sourcePermanent.getId(), game); + : new MageObjectReference(sourcePermanent.getId(), game); Set setForThePlayer = this.humanEnterings.getOrDefault(playerId, new HashSet<>()); return setForThePlayer.stream().anyMatch( - humanMOR -> !(humanMOR.equals(sourceMOR)) + humanMOR -> !(humanMOR.equals(sourceMOR)) ); } } diff --git a/Mage.Sets/src/mage/cards/e/EpharaGodOfThePolis.java b/Mage.Sets/src/mage/cards/e/EpharaGodOfThePolis.java index 6ea8d040ed6..6febc28ba20 100644 --- a/Mage.Sets/src/mage/cards/e/EpharaGodOfThePolis.java +++ b/Mage.Sets/src/mage/cards/e/EpharaGodOfThePolis.java @@ -2,17 +2,19 @@ package mage.cards.e; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.DevotionCount; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.LoseCreatureTypeSourceEffect; import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.TargetController; import mage.game.Game; import mage.game.permanent.Permanent; import mage.watchers.common.PermanentsEnteredBattlefieldWatcher; @@ -40,13 +42,9 @@ public final class EpharaGodOfThePolis extends CardImpl { .addHint(DevotionCount.WU.getHint())); // At the beginning of each upkeep, if you had another creature enter the battlefield under your control last turn, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - Zone.BATTLEFIELD, TargetController.ANY, new DrawCardSourceControllerEffect(1), - false - ), EpharaGodOfThePolisCondition.instance, "At the beginning of each upkeep, " + - "if you had another creature enter the battlefield under your control last turn, draw a card." - ), new PermanentsEnteredBattlefieldWatcher()); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.ANY, new DrawCardSourceControllerEffect(1), false + ).withInterveningIf(EpharaGodOfThePolisCondition.instance), new PermanentsEnteredBattlefieldWatcher()); } private EpharaGodOfThePolis(final EpharaGodOfThePolis card) { @@ -71,4 +69,9 @@ enum EpharaGodOfThePolisCondition implements Condition { && watcher != null && watcher.anotherCreatureEnteredBattlefieldUnderPlayersControlLastTurn(sourcePermanent, game); } + + @Override + public String toString() { + return "you had another creature enter the battlefield under your control last turn"; + } } diff --git a/Mage.Sets/src/mage/cards/e/EpharasWarden.java b/Mage.Sets/src/mage/cards/e/EpharasWarden.java index 8a6e7db8638..c87b71857bf 100644 --- a/Mage.Sets/src/mage/cards/e/EpharasWarden.java +++ b/Mage.Sets/src/mage/cards/e/EpharasWarden.java @@ -16,6 +16,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class EpharasWarden extends CardImpl { // {T}: Tap target creature with power 3 or less. Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new TapSourceCost()); - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); ability.addTarget(target); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/EpicConfrontation.java b/Mage.Sets/src/mage/cards/e/EpicConfrontation.java index a4588b71687..788a6f57317 100644 --- a/Mage.Sets/src/mage/cards/e/EpicConfrontation.java +++ b/Mage.Sets/src/mage/cards/e/EpicConfrontation.java @@ -9,11 +9,14 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author fireshoes */ @@ -30,7 +33,7 @@ public final class EpicConfrontation extends CardImpl { "(Each deals damage equal to its power to the other.)"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - Target target = new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL); + Target target = new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL); this.getSpellAbility().addTarget(target); } diff --git a/Mage.Sets/src/mage/cards/e/EpicExperiment.java b/Mage.Sets/src/mage/cards/e/EpicExperiment.java index a3a596dcce7..7ad32fff925 100644 --- a/Mage.Sets/src/mage/cards/e/EpicExperiment.java +++ b/Mage.Sets/src/mage/cards/e/EpicExperiment.java @@ -67,6 +67,8 @@ class EpicExperimentEffect extends OneShotEffect { } Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, CardUtil.getSourceCostsTag(game, source, "X", 0))); controller.moveCards(cards, Zone.EXILED, source, game); + game.processAction(); + cards.retainZone(Zone.EXILED, game); FilterCard filter = new FilterInstantOrSorceryCard(); filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, CardUtil.getSourceCostsTag(game, source, "X", 0) + 1)); CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, filter); diff --git a/Mage.Sets/src/mage/cards/e/EpicStruggle.java b/Mage.Sets/src/mage/cards/e/EpicStruggle.java index de3aae322b9..7e0955917b0 100644 --- a/Mage.Sets/src/mage/cards/e/EpicStruggle.java +++ b/Mage.Sets/src/mage/cards/e/EpicStruggle.java @@ -1,34 +1,34 @@ - package mage.cards.e; -import java.util.UUID; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.WinGameSourceControllerEffect; -import mage.abilities.hint.ValueHint; +import mage.abilities.hint.common.CreaturesYouControlHint; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; -import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class EpicStruggle extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledCreaturePermanent("you control twenty or more creatures"), + ComparisonType.MORE_THAN, 19 + ); + public EpicStruggle(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{G}"); // At the beginning of your upkeep, if you control twenty or more creatures, you win the game. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect()), - new PermanentsOnTheBattlefieldCondition(StaticFilters.FILTER_CONTROLLED_CREATURE, ComparisonType.MORE_THAN, 19), - "At the beginning of your upkeep, if you control twenty or more creatures, you win the game." - ).addHint(new ValueHint("Creatures you control", new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_CREATURE)))); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect()) + .withInterveningIf(condition).addHint(CreaturesYouControlHint.instance)); } private EpicStruggle(final EpicStruggle card) { diff --git a/Mage.Sets/src/mage/cards/e/Eradicate.java b/Mage.Sets/src/mage/cards/e/Eradicate.java index 6f28647789a..6f078df9f2c 100644 --- a/Mage.Sets/src/mage/cards/e/Eradicate.java +++ b/Mage.Sets/src/mage/cards/e/Eradicate.java @@ -6,8 +6,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author LevelX2 @@ -19,7 +22,7 @@ public final class Eradicate extends CardImpl { // Exile target nonblack creature. Search its controller's graveyard, hand, and library for all cards // with the same name as that creature and exile them. Then that player shuffles their library. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.getSpellAbility().addEffect(new ExileTargetAndSearchGraveyardHandLibraryEffect(false, "its controller's","all cards with the same name as that creature")); } diff --git a/Mage.Sets/src/mage/cards/e/ErebossEmissary.java b/Mage.Sets/src/mage/cards/e/ErebossEmissary.java index a82cd83dfd6..3df3fec89b8 100644 --- a/Mage.Sets/src/mage/cards/e/ErebossEmissary.java +++ b/Mage.Sets/src/mage/cards/e/ErebossEmissary.java @@ -1,6 +1,5 @@ package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -15,10 +14,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.target.common.TargetCardInHand; +import java.util.UUID; + /** * * @author LevelX2 @@ -39,7 +39,7 @@ public final class ErebossEmissary extends CardImpl { new BoostEnchantedEffect(2, 2, Duration.EndOfTurn), new BoostSourceEffect(2, 2, Duration.EndOfTurn), new SourceHasSubtypeCondition(SubType.AURA), - "{this} gets +2/+2 until end of turn. If Erebos's Emissary is an Aura, enchanted creature gets +2/+2 until end of turn instead"), + "{this} gets +2/+2 until end of turn. If {this} is an Aura, enchanted creature gets +2/+2 until end of turn instead"), new DiscardTargetCost(new TargetCardInHand(StaticFilters.FILTER_CARD_CREATURE)))); // Enchanted creature gets +3/+3 diff --git a/Mage.Sets/src/mage/cards/e/ErgRaiders.java b/Mage.Sets/src/mage/cards/e/ErgRaiders.java index 9a3a486642a..8530d6fdf75 100644 --- a/Mage.Sets/src/mage/cards/e/ErgRaiders.java +++ b/Mage.Sets/src/mage/cards/e/ErgRaiders.java @@ -1,16 +1,13 @@ package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.AttackedThisTurnSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageControllerEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -18,13 +15,17 @@ import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author awjackson - * */ public final class ErgRaiders extends CardImpl { + private static final Condition condition = new InvertCondition( + AttackedThisTurnSourceCondition.instance, "{this} didn't attack this turn" + ); + public ErgRaiders(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); this.subtype.add(SubType.HUMAN, SubType.WARRIOR); @@ -32,16 +33,10 @@ public final class ErgRaiders extends CardImpl { this.toughness = new MageInt(3); // At the beginning of your end step, if Erg Raiders didn't attack this turn, Erg Raiders deals 2 damage to you unless it came under your control this turn. - Effect effect = new ConditionalOneShotEffect( - new DamageControllerEffect(2), - ErgRaidersCondition.instance, - "{this} deals 2 damage to you unless it came under your control this turn" - ); - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility(effect), - new InvertCondition(AttackedThisTurnSourceCondition.instance), - "At the beginning of your end step, if {this} didn't attack this turn, {this} deals 2 damage to you unless it came under your control this turn."); - this.addAbility(ability); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new ConditionalOneShotEffect( + new DamageControllerEffect(2), ErgRaidersCondition.instance, + "it deals 2 damage to you unless it came under your control this turn" + )).withInterveningIf(condition)); } private ErgRaiders(final ErgRaiders card) { diff --git a/Mage.Sets/src/mage/cards/e/ErhnamDjinn.java b/Mage.Sets/src/mage/cards/e/ErhnamDjinn.java index 6ce01e21cc9..fd4e4eb02e9 100644 --- a/Mage.Sets/src/mage/cards/e/ErhnamDjinn.java +++ b/Mage.Sets/src/mage/cards/e/ErhnamDjinn.java @@ -11,6 +11,7 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -39,7 +40,7 @@ public final class ErhnamDjinn extends CardImpl { GainAbilityTargetEffect effect = new GainAbilityTargetEffect(new ForestwalkAbility(false), Duration.UntilYourNextUpkeepStep, "target non-Wall creature an opponent controls gains forestwalk until your next upkeep"); Ability ability = new BeginningOfUpkeepTriggeredAbility(effect); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/Erithizon.java b/Mage.Sets/src/mage/cards/e/Erithizon.java index c06e46173a9..74035a4b6a3 100644 --- a/Mage.Sets/src/mage/cards/e/Erithizon.java +++ b/Mage.Sets/src/mage/cards/e/Erithizon.java @@ -12,6 +12,7 @@ import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.TargetAdjuster; @@ -32,7 +33,7 @@ public final class Erithizon extends CardImpl { // Whenever Erithizon attacks, put a +1/+1 counter on target creature of defending player's choice. Ability ability = new AttacksTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); ability.setTargetAdjuster(ErithizonAdjuster.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/ErrantDoomsayers.java b/Mage.Sets/src/mage/cards/e/ErrantDoomsayers.java index b4b98352cc1..a7781452dc7 100644 --- a/Mage.Sets/src/mage/cards/e/ErrantDoomsayers.java +++ b/Mage.Sets/src/mage/cards/e/ErrantDoomsayers.java @@ -16,6 +16,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ToughnessPredicate; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class ErrantDoomsayers extends CardImpl { // {tap}: Tap target creature with toughness 2 or less. Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new TapSourceCost()); - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); ability.addTarget(target); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/ErrantMinion.java b/Mage.Sets/src/mage/cards/e/ErrantMinion.java index f0f8a0d1f4b..850ad33d59a 100644 --- a/Mage.Sets/src/mage/cards/e/ErrantMinion.java +++ b/Mage.Sets/src/mage/cards/e/ErrantMinion.java @@ -58,7 +58,7 @@ class ErrantMinionEffect extends OneShotEffect { ErrantMinionEffect() { super(Outcome.Damage); - this.staticText = "that player may pay any amount of mana. Errant Minion deals 2 damage to that player. Prevent X of that damage, where X is the amount of mana that player paid this way"; + this.staticText = "that player may pay any amount of mana. {this} deals 2 damage to that player. Prevent X of that damage, where X is the amount of mana that player paid this way"; } private ErrantMinionEffect(final ErrantMinionEffect effect) { diff --git a/Mage.Sets/src/mage/cards/e/EscapeDetection.java b/Mage.Sets/src/mage/cards/e/EscapeDetection.java index ff81d39f7c4..b18be14ef75 100644 --- a/Mage.Sets/src/mage/cards/e/EscapeDetection.java +++ b/Mage.Sets/src/mage/cards/e/EscapeDetection.java @@ -1,13 +1,8 @@ package mage.cards.e; -import java.util.UUID; - import mage.ObjectColor; -import mage.abilities.Ability; -import mage.abilities.costs.Cost; import mage.abilities.costs.common.ReturnToHandChosenControlledPermanentCost; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.ReturnToHandChosenControlledPermanentEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.FreerunningAbility; import mage.cards.CardImpl; @@ -16,16 +11,17 @@ import mage.constants.CardType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.ColorPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author grimreap124 */ public final class EscapeDetection extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("blue creature you control"); + private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("blue creature you control"); static { filter.add(new ColorPredicate(ObjectColor.BLUE)); @@ -33,16 +29,14 @@ public final class EscapeDetection extends CardImpl { public EscapeDetection(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}{U}"); - // Freerunning--Return a blue creature you control to its owner's hand. - Cost cost = new ReturnToHandChosenControlledPermanentCost( - new TargetControlledCreaturePermanent(1, 1, filter, true)); - this.addAbility(new FreerunningAbility(cost)); + this.addAbility(new FreerunningAbility(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(filter)))); // Return target creature to its owner's hand. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } diff --git a/Mage.Sets/src/mage/cards/e/EscapeRoutes.java b/Mage.Sets/src/mage/cards/e/EscapeRoutes.java index 3e4636beb1d..23f30a75c3a 100644 --- a/Mage.Sets/src/mage/cards/e/EscapeRoutes.java +++ b/Mage.Sets/src/mage/cards/e/EscapeRoutes.java @@ -15,6 +15,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -35,7 +36,7 @@ public final class EscapeRoutes extends CardImpl { // {2}{U}: Return target white or black creature you control to its owner's hand. Ability ability = new SimpleActivatedAbility(new ReturnToHandTargetEffect(), new ManaCostsImpl<>("{2}{U}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/EsperSentinel.java b/Mage.Sets/src/mage/cards/e/EsperSentinel.java index 694961f5376..dd8228b7573 100644 --- a/Mage.Sets/src/mage/cards/e/EsperSentinel.java +++ b/Mage.Sets/src/mage/cards/e/EsperSentinel.java @@ -1,17 +1,16 @@ package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.costs.Cost; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.constants.Outcome; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; @@ -22,6 +21,8 @@ import mage.target.targetpointer.FixedTarget; import mage.util.ManaUtil; import mage.watchers.common.SpellsCastWatcher; +import java.util.UUID; + /** * * @author weirddan455 @@ -94,7 +95,7 @@ class EsperSentinelTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever an opponent casts their first noncreature spell each turn, draw a card unless that player pays {X}, where X is Esper Sentinel's power."; + return "Whenever an opponent casts their first noncreature spell each turn, draw a card unless that player pays {X}, where X is {this}'s power."; } } diff --git a/Mage.Sets/src/mage/cards/e/EssenceFracture.java b/Mage.Sets/src/mage/cards/e/EssenceFracture.java index 520d5342653..b7036199c89 100644 --- a/Mage.Sets/src/mage/cards/e/EssenceFracture.java +++ b/Mage.Sets/src/mage/cards/e/EssenceFracture.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.common.ReturnToHandTargetEffect; @@ -11,21 +9,22 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class EssenceFracture extends CardImpl { public EssenceFracture(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}{U}"); // Return two target creatures to their owners' hands. Effect effect = new ReturnToHandTargetEffect(); effect.setText("Return two target creatures to their owners' hands"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetCreaturePermanent(2)); - + // Cycling {2}{U} this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{2}{U}"))); } diff --git a/Mage.Sets/src/mage/cards/e/EtaliPrimalConqueror.java b/Mage.Sets/src/mage/cards/e/EtaliPrimalConqueror.java index 1a919e9d546..8330ea611f9 100644 --- a/Mage.Sets/src/mage/cards/e/EtaliPrimalConqueror.java +++ b/Mage.Sets/src/mage/cards/e/EtaliPrimalConqueror.java @@ -91,6 +91,8 @@ class EtaliPrimalConquerorEffect extends OneShotEffect { } } } + game.processAction(); + cards.retainZone(Zone.EXILED, game); CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, StaticFilters.FILTER_CARD); return true; } diff --git a/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java b/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java index f16e32a1b6c..c4997deae4a 100644 --- a/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java +++ b/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java @@ -29,8 +29,7 @@ public final class EtaliPrimalStorm extends CardImpl { this.power = new MageInt(6); this.toughness = new MageInt(6); - // Whenever Etali, Primal Storm attacks, exile the top card of each player's library, - // then you may cast any number of nonland cards exiled this way without paying their mana costs. + // Whenever Etali, Primal Storm attacks, exile the top card of each player's library, then you may cast any number of nonland cards exiled this way without paying their mana costs. this.addAbility(new AttacksTriggeredAbility(new EtaliPrimalStormEffect(), false)); } @@ -78,6 +77,8 @@ class EtaliPrimalStormEffect extends OneShotEffect { } } controller.moveCards(cards, Zone.EXILED, source, game); + game.processAction(); + cards.retainZone(Zone.EXILED, game); CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, filter); return true; } diff --git a/Mage.Sets/src/mage/cards/e/EternalDragon.java b/Mage.Sets/src/mage/cards/e/EternalDragon.java index 8ff895e6631..5b5b663e85a 100644 --- a/Mage.Sets/src/mage/cards/e/EternalDragon.java +++ b/Mage.Sets/src/mage/cards/e/EternalDragon.java @@ -1,31 +1,27 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; -import mage.abilities.effects.common.ReturnToHandSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.PlainscyclingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.PhaseStep; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author Loki */ public final class EternalDragon extends CardImpl { public EternalDragon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}{W}"); this.subtype.add(SubType.DRAGON); this.subtype.add(SubType.SPIRIT); @@ -36,13 +32,11 @@ public final class EternalDragon extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // {3}{W}{W}: Return Eternal Dragon from your graveyard to your hand. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility(Zone.GRAVEYARD, - new ReturnSourceFromGraveyardToHandEffect(), - new ManaCostsImpl<>("{3}{W}{W}"), - new IsStepCondition(PhaseStep.UPKEEP), - null - ); - this.addAbility(ability); + this.addAbility(new ActivateIfConditionActivatedAbility( + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), + new ManaCostsImpl<>("{3}{W}{W}"), IsStepCondition.getMyUpkeep() + )); + // PlainscyclingAbility {2} this.addAbility(new PlainscyclingAbility(new ManaCostsImpl<>("{2}"))); } diff --git a/Mage.Sets/src/mage/cards/e/EusocialEngineering.java b/Mage.Sets/src/mage/cards/e/EusocialEngineering.java new file mode 100644 index 00000000000..2b75aa5c333 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EusocialEngineering.java @@ -0,0 +1,36 @@ +package mage.cards.e; + +import mage.abilities.common.LandfallAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.WarpAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.RobotToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EusocialEngineering extends CardImpl { + + public EusocialEngineering(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}{G}"); + + // Landfall -- Whenever a land you control enters, create a 2/2 colorless Robot artifact creature token. + this.addAbility(new LandfallAbility(new CreateTokenEffect(new RobotToken()))); + + // Warp {1}{G} + this.addAbility(new WarpAbility(this, "{1}{G}")); + } + + private EusocialEngineering(final EusocialEngineering card) { + super(card); + } + + @Override + public EusocialEngineering copy() { + return new EusocialEngineering(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EvergloveCourier.java b/Mage.Sets/src/mage/cards/e/EvergloveCourier.java index 38456e9dcef..a8df4ec0d4f 100644 --- a/Mage.Sets/src/mage/cards/e/EvergloveCourier.java +++ b/Mage.Sets/src/mage/cards/e/EvergloveCourier.java @@ -20,6 +20,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -49,7 +50,7 @@ public final class EvergloveCourier extends CardImpl { ability.addEffect(new ConditionalContinuousEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.Custom), SourceTappedCondition.TAPPED,"and has trample for as long as {this} remains tapped")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/EverythingamajigB.java b/Mage.Sets/src/mage/cards/e/EverythingamajigB.java index 172c34ab2ad..c072b0ab592 100644 --- a/Mage.Sets/src/mage/cards/e/EverythingamajigB.java +++ b/Mage.Sets/src/mage/cards/e/EverythingamajigB.java @@ -1,15 +1,12 @@ - package mage.cards.e; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.HellbentCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect; @@ -17,14 +14,14 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.common.FilterPermanentCard; import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.card.ExpansionSetPredicate; +import mage.filter.predicate.mageobject.NamePredicate; + +import java.util.UUID; /** - * * @author Ketsuban */ public final class EverythingamajigB extends CardImpl { @@ -40,14 +37,16 @@ public final class EverythingamajigB extends CardImpl { } public EverythingamajigB(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{5}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); // Fool's Tome // 2, T: Draw a card. Activate this ability only if you have no cards in hand. - Ability ability1 = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new GenericManaCost(2), HellbentCondition.instance); + Ability ability1 = new ActivateIfConditionActivatedAbility( + new DrawCardSourceControllerEffect(1), new GenericManaCost(2), HellbentCondition.instance + ); ability1.addCost(new TapSourceCost()); this.addAbility(ability1); - + // Tower of Eons // 8, T: You gain 10 life. Ability ability2 = new SimpleActivatedAbility(new GainLifeEffect(10), new GenericManaCost(8)); diff --git a/Mage.Sets/src/mage/cards/e/EverythingamajigC.java b/Mage.Sets/src/mage/cards/e/EverythingamajigC.java index fc3f4adf73f..47531ecd7b5 100644 --- a/Mage.Sets/src/mage/cards/e/EverythingamajigC.java +++ b/Mage.Sets/src/mage/cards/e/EverythingamajigC.java @@ -41,11 +41,12 @@ public final class EverythingamajigC extends CardImpl { // Disrupting Scepter // 3, {T}: Target player discards a card. Activate this ability only during your turn. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new DiscardTargetEffect(1), new GenericManaCost(3), MyTurnCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DiscardTargetEffect(1), new GenericManaCost(3), MyTurnCondition.instance + ); ability.addTarget(new TargetPlayer()); ability.addCost(new TapSourceCost()); - ability.addHint(MyTurnHint.instance); - this.addAbility(ability); + this.addAbility(ability.addHint(MyTurnHint.instance)); // Chimeric Staff // X: Everythingamajig becomes an X/X Construct artifact creature until end of turn. diff --git a/Mage.Sets/src/mage/cards/e/EvilTwin.java b/Mage.Sets/src/mage/cards/e/EvilTwin.java index 0297e1150bc..21fa0417286 100644 --- a/Mage.Sets/src/mage/cards/e/EvilTwin.java +++ b/Mage.Sets/src/mage/cards/e/EvilTwin.java @@ -21,6 +21,7 @@ import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.util.CardUtil; import mage.util.functions.CopyApplier; @@ -68,7 +69,7 @@ class EvilTwinCopyApplier extends CopyApplier { public boolean apply(Game game, MageObject blueprint, Ability source, UUID copyToObjectId) { Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{U}{B}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); blueprint.getAbilities().add(ability); return true; } diff --git a/Mage.Sets/src/mage/cards/e/EvolutionaryEscalation.java b/Mage.Sets/src/mage/cards/e/EvolutionaryEscalation.java index 4ee0cf28ca4..6732ef8f741 100644 --- a/Mage.Sets/src/mage/cards/e/EvolutionaryEscalation.java +++ b/Mage.Sets/src/mage/cards/e/EvolutionaryEscalation.java @@ -15,9 +15,12 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author spjspj @@ -31,7 +34,7 @@ public final class EvolutionaryEscalation extends CardImpl { EvolutionaryEscalationEffect effect = new EvolutionaryEscalationEffect(); Ability ability = new BeginningOfUpkeepTriggeredAbility(effect); ability.addTarget(new TargetControlledCreaturePermanent()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/ExaltedSunborn.java b/Mage.Sets/src/mage/cards/e/ExaltedSunborn.java new file mode 100644 index 00000000000..8586a8973ca --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ExaltedSunborn.java @@ -0,0 +1,50 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.replacement.CreateTwiceThatManyTokensEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.WarpAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ExaltedSunborn extends CardImpl { + + public ExaltedSunborn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); + + this.subtype.add(SubType.ANGEL); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // If one or more tokens would be created under your control, twice that many of those tokens are created instead. + this.addAbility(new SimpleStaticAbility(new CreateTwiceThatManyTokensEffect())); + + // Warp {1}{W} + this.addAbility(new WarpAbility(this, "{1}{W}")); + } + + private ExaltedSunborn(final ExaltedSunborn card) { + super(card); + } + + @Override + public ExaltedSunborn copy() { + return new ExaltedSunborn(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/ExcaliburSwordOfEden.java b/Mage.Sets/src/mage/cards/e/ExcaliburSwordOfEden.java index 40a00e27ba1..a9e1f68ac46 100644 --- a/Mage.Sets/src/mage/cards/e/ExcaliburSwordOfEden.java +++ b/Mage.Sets/src/mage/cards/e/ExcaliburSwordOfEden.java @@ -1,7 +1,5 @@ package mage.cards.e; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; @@ -11,18 +9,17 @@ import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; import mage.abilities.keyword.EquipAbility; import mage.abilities.keyword.VigilanceAbility; -import mage.constants.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.filter.FilterPermanent; -import mage.filter.StaticFilters; +import mage.constants.*; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.HistoricPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author grimreap124 */ public final class ExcaliburSwordOfEden extends CardImpl { @@ -35,12 +32,12 @@ public final class ExcaliburSwordOfEden extends CardImpl { filterLegendary.add(SuperType.LEGENDARY.getPredicate()); historicFilter.add(HistoricPredicate.instance); } - + private static final TotalPermanentsManaValue xValue = new TotalPermanentsManaValue(historicFilter); public ExcaliburSwordOfEden(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{12}"); - + this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.EQUIPMENT); @@ -57,7 +54,7 @@ public final class ExcaliburSwordOfEden extends CardImpl { this.addAbility(ability); // Equip legendary creature {2} - this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2), new TargetControlledCreaturePermanent(filterLegendary), false)); + this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2), new TargetPermanent(filterLegendary), false)); } diff --git a/Mage.Sets/src/mage/cards/e/ExcavationElephant.java b/Mage.Sets/src/mage/cards/e/ExcavationElephant.java index 7006d1bb189..d21f4f50d3f 100644 --- a/Mage.Sets/src/mage/cards/e/ExcavationElephant.java +++ b/Mage.Sets/src/mage/cards/e/ExcavationElephant.java @@ -1,11 +1,10 @@ package mage.cards.e; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -32,13 +31,9 @@ public final class ExcavationElephant extends CardImpl { this.addAbility(new KickerAbility("{1}{W}")); // When Excavation Elephant enters the battlefield, if it was kicked, return target artifact card from your graveyard to your hand. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), false); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()).withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - ability, KickedCondition.ONCE, - "When {this} enters, if it was kicked, " - + "return target artifact card from your graveyard to your hand." - )); + this.addAbility(ability); } private ExcavationElephant(final ExcavationElephant card) { diff --git a/Mage.Sets/src/mage/cards/e/Excise.java b/Mage.Sets/src/mage/cards/e/Excise.java index 6835e169b00..a4f8f1981ed 100644 --- a/Mage.Sets/src/mage/cards/e/Excise.java +++ b/Mage.Sets/src/mage/cards/e/Excise.java @@ -10,6 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -27,7 +28,7 @@ public final class Excise extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{W}"); // Excise target nonwhite attacking creature unless its controller pays {X}. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DoUnlessTargetPlayerOrTargetsControllerPaysEffect(new ExileTargetEffect(), GetXValue.instance)); } diff --git a/Mage.Sets/src/mage/cards/e/ExclusionMage.java b/Mage.Sets/src/mage/cards/e/ExclusionMage.java index c1a4131f51f..00f1c8a2121 100644 --- a/Mage.Sets/src/mage/cards/e/ExclusionMage.java +++ b/Mage.Sets/src/mage/cards/e/ExclusionMage.java @@ -10,8 +10,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author TheElk801 @@ -28,7 +31,7 @@ public final class ExclusionMage extends CardImpl { // When Exclusion Mage enters the battlefield, return target creature an opponent controls to its owner's hand. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/Excoriate.java b/Mage.Sets/src/mage/cards/e/Excoriate.java index 38be8444c5e..edda09c0155 100644 --- a/Mage.Sets/src/mage/cards/e/Excoriate.java +++ b/Mage.Sets/src/mage/cards/e/Excoriate.java @@ -8,6 +8,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -28,7 +29,7 @@ public final class Excoriate extends CardImpl { // Exile target tapped creature. this.getSpellAbility().addEffect(new ExileTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private Excoriate(final Excoriate card) { diff --git a/Mage.Sets/src/mage/cards/e/Execute.java b/Mage.Sets/src/mage/cards/e/Execute.java index bf6d2c3b1f0..a5171e8da13 100644 --- a/Mage.Sets/src/mage/cards/e/Execute.java +++ b/Mage.Sets/src/mage/cards/e/Execute.java @@ -10,6 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -28,7 +29,7 @@ public final class Execute extends CardImpl { // Destroy target white creature. It can't be regenerated. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); diff --git a/Mage.Sets/src/mage/cards/e/ExecutionersCapsule.java b/Mage.Sets/src/mage/cards/e/ExecutionersCapsule.java index be66a2ff068..0294badd5aa 100644 --- a/Mage.Sets/src/mage/cards/e/ExecutionersCapsule.java +++ b/Mage.Sets/src/mage/cards/e/ExecutionersCapsule.java @@ -11,8 +11,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author North @@ -25,7 +28,7 @@ public final class ExecutionersCapsule extends CardImpl { SimpleActivatedAbility ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{1}{B}")); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + ability.addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/Exile.java b/Mage.Sets/src/mage/cards/e/Exile.java index 91802f519f4..ed76065c392 100644 --- a/Mage.Sets/src/mage/cards/e/Exile.java +++ b/Mage.Sets/src/mage/cards/e/Exile.java @@ -18,6 +18,7 @@ import mage.filter.predicate.permanent.AttackingPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class Exile extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{W}"); // Exile target nonwhite attacking creature. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new ExileTargetEffect()); // You gain life equal to its toughness. this.getSpellAbility().addEffect(new ExileEffect()); diff --git a/Mage.Sets/src/mage/cards/e/Exorcist.java b/Mage.Sets/src/mage/cards/e/Exorcist.java index be5ead24428..499e8010b48 100644 --- a/Mage.Sets/src/mage/cards/e/Exorcist.java +++ b/Mage.Sets/src/mage/cards/e/Exorcist.java @@ -16,6 +16,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -41,7 +42,7 @@ public final class Exorcist extends CardImpl { new DestroyTargetEffect(), new ManaCostsImpl<>("{1}{W}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/ExoticPets.java b/Mage.Sets/src/mage/cards/e/ExoticPets.java index 441ed8c7749..0c51f90744c 100644 --- a/Mage.Sets/src/mage/cards/e/ExoticPets.java +++ b/Mage.Sets/src/mage/cards/e/ExoticPets.java @@ -1,6 +1,5 @@ package mage.cards.e; -import mage.MageItem; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -10,8 +9,7 @@ import mage.constants.Outcome; import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.FishToken; @@ -102,11 +100,7 @@ class ExoticPetsEffect extends OneShotEffect { return true; } FilterPermanent filter = new FilterPermanent("creature"); - filter.add(Predicates.or(permanents - .stream() - .map(MageItem::getId) - .map(PermanentIdPredicate::new) - .collect(Collectors.toSet()))); + filter.add(new PermanentReferenceInCollectionPredicate(permanents, game)); TargetPermanent target = new TargetPermanent(filter); target.withNotTarget(true); for (CounterType counterType : counterTypes) { diff --git a/Mage.Sets/src/mage/cards/e/ExpelTheUnworthy.java b/Mage.Sets/src/mage/cards/e/ExpelTheUnworthy.java index c087d318889..5131200e499 100644 --- a/Mage.Sets/src/mage/cards/e/ExpelTheUnworthy.java +++ b/Mage.Sets/src/mage/cards/e/ExpelTheUnworthy.java @@ -16,11 +16,14 @@ import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.ConditionalTargetAdjuster; import java.util.UUID; +import static mage.abilities.condition.common.KickedCondition.ONCE; + /** * @author Susucr */ @@ -44,8 +47,8 @@ public final class ExpelTheUnworthy extends CardImpl { this.getSpellAbility().addEffect(new ExileTargetEffect().setText("Exile the chosen creature")); this.getSpellAbility().addEffect(new ExpelTheUnworthyEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().setTargetAdjuster(new ConditionalTargetAdjuster(KickedCondition.ONCE, - new TargetCreaturePermanent(filter), new TargetCreaturePermanent())); + this.getSpellAbility().setTargetAdjuster(new ConditionalTargetAdjuster(ONCE, + new TargetPermanent(filter), new TargetCreaturePermanent())); } private ExpelTheUnworthy(final ExpelTheUnworthy card) { diff --git a/Mage.Sets/src/mage/cards/e/ExpendableTroops.java b/Mage.Sets/src/mage/cards/e/ExpendableTroops.java index 4974710688c..d66072bba4e 100644 --- a/Mage.Sets/src/mage/cards/e/ExpendableTroops.java +++ b/Mage.Sets/src/mage/cards/e/ExpendableTroops.java @@ -14,6 +14,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterAttackingOrBlockingCreature; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -33,7 +34,7 @@ public final class ExpendableTroops extends CardImpl { // {tap}, Sacrifice Expendable Troops: Expendable Troops deals 2 damage to target attacking or blocking creature. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2, "it"), new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(new FilterAttackingOrBlockingCreature())); + ability.addTarget(new TargetPermanent(new FilterAttackingOrBlockingCreature())); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/ExposeTheCulprit.java b/Mage.Sets/src/mage/cards/e/ExposeTheCulprit.java index 067b28df715..db51939cf8d 100644 --- a/Mage.Sets/src/mage/cards/e/ExposeTheCulprit.java +++ b/Mage.Sets/src/mage/cards/e/ExposeTheCulprit.java @@ -46,7 +46,7 @@ public final class ExposeTheCulprit extends CardImpl { // * Turn target face-down creature face up. this.getSpellAbility().addEffect(new TurnFaceUpTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // * Exile any number of face-up creatures you control with disguise in a face-down pile, shuffle that pile, then cloak them. Mode mode = new Mode(new ExposeTheCulpritEffect()); diff --git a/Mage.Sets/src/mage/cards/e/Expunge.java b/Mage.Sets/src/mage/cards/e/Expunge.java index eb89c44253f..f63805c17f0 100644 --- a/Mage.Sets/src/mage/cards/e/Expunge.java +++ b/Mage.Sets/src/mage/cards/e/Expunge.java @@ -12,6 +12,7 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -32,7 +33,7 @@ public final class Expunge extends CardImpl { // Destroy target nonartifact, nonblack creature. It can't be regenerated. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); // Cycling {2} ({2}, Discard this card: Draw a card.) diff --git a/Mage.Sets/src/mage/cards/e/ExtricatorOfSin.java b/Mage.Sets/src/mage/cards/e/ExtricatorOfSin.java index 9187fc51e56..e52dc72a2a3 100644 --- a/Mage.Sets/src/mage/cards/e/ExtricatorOfSin.java +++ b/Mage.Sets/src/mage/cards/e/ExtricatorOfSin.java @@ -1,26 +1,26 @@ package mage.cards.e; -import java.util.UUID; - import mage.MageInt; -import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.TransformAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.permanent.token.EldraziHorrorToken; +import java.util.UUID; + /** * @author LevelX2 */ @@ -47,11 +47,9 @@ public final class ExtricatorOfSin extends CardImpl { // Delirium — At the beginning of your upkeep, if there are four or more card types among cards in your graveyard, transform Extricator of Sin. this.addAbility(new TransformAbility()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()), - DeliriumCondition.instance, - "Delirium — At the beginning of your upkeep, if there are four or more card types among cards in your graveyard, " - + " transform {this}.") + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()) + .withInterveningIf(DeliriumCondition.instance) + .setAbilityWord(AbilityWord.DELIRIUM) .addHint(CardTypesInGraveyardCount.YOU.getHint())); } diff --git a/Mage.Sets/src/mage/cards/e/EyeblightAssassin.java b/Mage.Sets/src/mage/cards/e/EyeblightAssassin.java index a4e9edb5c25..5c59e42ad94 100644 --- a/Mage.Sets/src/mage/cards/e/EyeblightAssassin.java +++ b/Mage.Sets/src/mage/cards/e/EyeblightAssassin.java @@ -12,8 +12,11 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Duration; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author fireshoes @@ -29,7 +32,7 @@ public final class EyeblightAssassin extends CardImpl { // When Eyeblight Assassin enters the battlefield, target creature an opponent controls gets -1/-1 until end of turn. Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-1,-1, Duration.EndOfTurn)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/EyeblightsEnding.java b/Mage.Sets/src/mage/cards/e/EyeblightsEnding.java index ce39d520ebe..d4917999126 100644 --- a/Mage.Sets/src/mage/cards/e/EyeblightsEnding.java +++ b/Mage.Sets/src/mage/cards/e/EyeblightsEnding.java @@ -9,6 +9,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -28,7 +29,7 @@ public final class EyeblightsEnding extends CardImpl { this.subtype.add(SubType.ELF); this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private EyeblightsEnding(final EyeblightsEnding card) { diff --git a/Mage.Sets/src/mage/cards/e/EzuriClawOfProgress.java b/Mage.Sets/src/mage/cards/e/EzuriClawOfProgress.java index f5905104315..dfd49b0ef2c 100644 --- a/Mage.Sets/src/mage/cards/e/EzuriClawOfProgress.java +++ b/Mage.Sets/src/mage/cards/e/EzuriClawOfProgress.java @@ -2,21 +2,21 @@ package mage.cards.e; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CountersControllerCount; import mage.abilities.effects.common.counter.AddCountersPlayersEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.PowerPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -25,15 +25,18 @@ import java.util.UUID; */ public final class EzuriClawOfProgress extends CardImpl { - final private static FilterControlledCreaturePermanent filter - = new FilterControlledCreaturePermanent("a creature with power 2 or less"); - final private static FilterControlledCreaturePermanent filter2 = new FilterControlledCreaturePermanent(); + final private static FilterPermanent filter + = new FilterControlledCreaturePermanent("a creature you control with power 2 or less"); + final private static FilterPermanent filter2 + = new FilterControlledCreaturePermanent("another target creature you control"); static { filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); filter2.add(AnotherPredicate.instance); } + private static final DynamicValue xValue = new CountersControllerCount(CounterType.EXPERIENCE); + public EzuriClawOfProgress(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); this.supertype.add(SuperType.LEGENDARY); @@ -44,13 +47,17 @@ public final class EzuriClawOfProgress extends CardImpl { this.toughness = new MageInt(3); // Whenever a creature with power 2 or less you control enters, you get an experience counter. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new AddCountersPlayersEffect( - CounterType.EXPERIENCE.createInstance(), TargetController.YOU - ), filter)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new AddCountersPlayersEffect(CounterType.EXPERIENCE.createInstance(), TargetController.YOU), filter + )); // At the beginning of combat on your turn, put X +1/+1 counters on another target creature you control, where X is the number of experience counters you have. - Ability ability = new BeginningOfCombatTriggeredAbility(new EzuriClawOfProgressEffect()); - ability.addTarget(new TargetControlledCreaturePermanent(filter2)); + Ability ability = new BeginningOfCombatTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance(), xValue) + .setText("put X +1/+1 counters on another target creature you control, " + + "where X is the number of experience counters you have") + ); + ability.addTarget(new TargetPermanent(filter2)); this.addAbility(ability); } @@ -63,34 +70,3 @@ public final class EzuriClawOfProgress extends CardImpl { return new EzuriClawOfProgress(this); } } - -class EzuriClawOfProgressEffect extends OneShotEffect { - - EzuriClawOfProgressEffect() { - super(Outcome.Benefit); - this.staticText = "put X +1/+1 counters on another target creature you control, where X is the number of experience counters you have"; - } - - private EzuriClawOfProgressEffect(final EzuriClawOfProgressEffect effect) { - super(effect); - } - - @Override - public EzuriClawOfProgressEffect copy() { - return new EzuriClawOfProgressEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (target != null) { - int amount = controller.getCountersCount(CounterType.EXPERIENCE); - target.addCounters(CounterType.P1P1.createInstance(amount), source.getControllerId(), source, game); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/f/FaeOffering.java b/Mage.Sets/src/mage/cards/f/FaeOffering.java index 9bde1f335e5..3b5afcea5ce 100644 --- a/Mage.Sets/src/mage/cards/f/FaeOffering.java +++ b/Mage.Sets/src/mage/cards/f/FaeOffering.java @@ -1,11 +1,10 @@ package mage.cards.f; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.Hint; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -31,13 +30,10 @@ public final class FaeOffering extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); // At the beginning of each end step, if you've cast both a creature spell and a noncreature spell this turn, create a Clue token, a Food token, and a Treasure token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - TargetController.ANY, new CreateTokenEffect(new ClueArtifactToken()).withAdditionalTokens(new FoodToken(), new TreasureToken()), - false - ), FaeOfferingCondition.instance, "At the beginning of each end step, " + - "if you've cast both a creature spell and a noncreature spell this turn, " + - "create a Clue token, a Food token, and a Treasure token." + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.ANY, new CreateTokenEffect(new ClueArtifactToken()) + .withAdditionalTokens(new FoodToken(), new TreasureToken()), + false, FaeOfferingCondition.instance ).addHint(FaeOfferingHint.instance)); } @@ -68,6 +64,11 @@ enum FaeOfferingCondition implements Condition { .distinct() .count() == 2; } + + @Override + public String toString() { + return "you've cast both a creature spell and a noncreature spell this turn"; + } } enum FaeOfferingHint implements Hint { diff --git a/Mage.Sets/src/mage/cards/f/FaerieMiscreant.java b/Mage.Sets/src/mage/cards/f/FaerieMiscreant.java index 420ad7e05e1..e94401382b3 100644 --- a/Mage.Sets/src/mage/cards/f/FaerieMiscreant.java +++ b/Mage.Sets/src/mage/cards/f/FaerieMiscreant.java @@ -4,17 +4,16 @@ import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.NamePredicate; import java.util.UUID; @@ -23,12 +22,12 @@ import java.util.UUID; */ public final class FaerieMiscreant extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("you control another creature named Faerie Miscreant"); static { filter.add(new NamePredicate("Faerie Miscreant")); filter.add(AnotherPredicate.instance); - filter.add(TargetController.YOU.getControllerPredicate()); } private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); @@ -44,12 +43,9 @@ public final class FaerieMiscreant extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Faerie Miscreant enters the battlefield, if you control another creature named Faerie Miscreant, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility( - new DrawCardSourceControllerEffect(1), false - ), condition, "When {this} enters, " + - "if you control another creature named Faerie Miscreant, draw a card." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new DrawCardSourceControllerEffect(1), false + ).withInterveningIf(condition)); } private FaerieMiscreant(final FaerieMiscreant card) { diff --git a/Mage.Sets/src/mage/cards/f/FairgroundsTrumpeter.java b/Mage.Sets/src/mage/cards/f/FairgroundsTrumpeter.java index 7af99a34ab5..1d76e291772 100644 --- a/Mage.Sets/src/mage/cards/f/FairgroundsTrumpeter.java +++ b/Mage.Sets/src/mage/cards/f/FairgroundsTrumpeter.java @@ -1,15 +1,10 @@ - package mage.cards.f; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -22,6 +17,10 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.watchers.Watcher; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** * @author spjspj */ @@ -34,11 +33,10 @@ public final class FairgroundsTrumpeter extends CardImpl { this.toughness = new MageInt(2); // At the beginning of each end step, if a +1/+1 counter was put on a permanent under your control this turn, put a +1/+1 counter on Fairgrounds Trumpeter. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new BeginningOfEndStepTriggeredAbility( - TargetController.ANY, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), - false), FairgroundsTrumpeterCondition.instance, - "At the beginning of each end step, if a +1/+1 counter was put on a permanent under your control this turn, put a +1/+1 counter on {this}."), - new FairgroundsTrumpeterWatcher()); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.ANY, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + false, FairgroundsTrumpeterCondition.instance + ), new FairgroundsTrumpeterWatcher()); } private FairgroundsTrumpeter(final FairgroundsTrumpeter card) { @@ -52,7 +50,6 @@ public final class FairgroundsTrumpeter extends CardImpl { } enum FairgroundsTrumpeterCondition implements Condition { - instance; @Override @@ -63,7 +60,7 @@ enum FairgroundsTrumpeterCondition implements Condition { @Override public String toString() { - return "if a +1/+1 counter was put on a permanent under your control this turn"; + return "a +1/+1 counter was put on a permanent under your control this turn"; } } @@ -97,5 +94,4 @@ class FairgroundsTrumpeterWatcher extends Watcher { public boolean p1p1AddedToPermanent(UUID playerId) { return players.contains(playerId); } - } diff --git a/Mage.Sets/src/mage/cards/f/FalkenrathPitFighter.java b/Mage.Sets/src/mage/cards/f/FalkenrathPitFighter.java index 00b329f6310..65ce6db2c6b 100644 --- a/Mage.Sets/src/mage/cards/f/FalkenrathPitFighter.java +++ b/Mage.Sets/src/mage/cards/f/FalkenrathPitFighter.java @@ -13,9 +13,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; -import mage.target.common.TargetControlledPermanent; import java.util.UUID; @@ -36,7 +34,7 @@ public final class FalkenrathPitFighter extends CardImpl { // {1}{R}, Discard a card, Sacrifice a Vampire: Draw two cards. Activate only if an opponent lost life this turn. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(2), + new DrawCardSourceControllerEffect(2), new ManaCostsImpl<>("{1}{R}"), OpponentsLostLifeCondition.instance ); ability.addCost(new DiscardCardCost()); diff --git a/Mage.Sets/src/mage/cards/f/FallOfTheFirstCivilization.java b/Mage.Sets/src/mage/cards/f/FallOfTheFirstCivilization.java index ca51988dc54..fd4a87acacb 100644 --- a/Mage.Sets/src/mage/cards/f/FallOfTheFirstCivilization.java +++ b/Mage.Sets/src/mage/cards/f/FallOfTheFirstCivilization.java @@ -19,7 +19,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; -import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetOpponent; import mage.util.CardUtil; @@ -46,7 +45,7 @@ public final class FallOfTheFirstCivilization extends CardImpl { sagaAbility.addChapterEffect( this, SagaChapter.CHAPTER_I, new Effects( - new DrawCardSourceControllerEffect(1).setText("you"), + new DrawCardSourceControllerEffect(2).setText("you"), new DrawCardTargetEffect(2).setText("and target opponent each draw two cards") ), new TargetOpponent() ); @@ -114,7 +113,7 @@ class FallOfTheFirstCivilizationEffect extends OneShotEffect { )); break; default: - TargetPermanent target = new TargetControlledCreaturePermanent(3); + TargetPermanent target = new TargetPermanent(3, StaticFilters.FILTER_CONTROLLED_PERMANENT_NON_LAND); target.withNotTarget(true); target.withChooseHint("to prevent being destroyed"); player.choose(outcome, target, source, game); diff --git a/Mage.Sets/src/mage/cards/f/FallOfTheHammer.java b/Mage.Sets/src/mage/cards/f/FallOfTheHammer.java index bbb08650196..0211ca6618b 100644 --- a/Mage.Sets/src/mage/cards/f/FallOfTheHammer.java +++ b/Mage.Sets/src/mage/cards/f/FallOfTheHammer.java @@ -1,52 +1,34 @@ - package mage.cards.f; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageWithPowerFromOneToAnotherTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.other.AnotherTargetPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; /** - * - * * As Fall of the Hammer tries to resolve, if only one of the targets is legal, * Fall of the Hammer will still resolve but will have no effect: If the first * target creature is illegal, it can't deal damage to anything. If the second * target creature is illegal, it can't be dealt damage. - * + *

* The amount of damage dealt is based on the first target creature's power as Fall of the Hammer resolves. - - + * * @author LevelX2 */ public final class FallOfTheHammer extends CardImpl { public FallOfTheHammer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{R}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); // Target creature you control deals damage equal to its power to another target creature. - this.getSpellAbility().addEffect(new FallOfTheHammerDamageEffect()); - TargetControlledCreaturePermanent target = - new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("Target creature: deals damage")); - target.setTargetTag(1); - this.getSpellAbility().addTarget(target); - - FilterCreaturePermanent filter = new FilterCreaturePermanent("Another creature: damage dealt to"); - filter.add(new AnotherTargetPredicate(2)); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter); - target2.setTargetTag(2); - this.getSpellAbility().addTarget(target2); + this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect()); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent().withChooseHint("to deal damage").setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2).withChooseHint("to receive damage").setTargetTag(2)); } private FallOfTheHammer(final FallOfTheHammer card) { @@ -58,34 +40,3 @@ public final class FallOfTheHammer extends CardImpl { return new FallOfTheHammer(this); } } - -class FallOfTheHammerDamageEffect extends OneShotEffect { - - FallOfTheHammerDamageEffect() { - super(Outcome.Damage); - this.staticText = "Target creature you control deals damage equal to its power to another target creature"; - } - - private FallOfTheHammerDamageEffect(final FallOfTheHammerDamageEffect effect) { - super(effect); - } - - @Override - public FallOfTheHammerDamageEffect copy() { - return new FallOfTheHammerDamageEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent ownCreature = game.getPermanent(source.getFirstTarget()); - if (ownCreature != null) { - int damage = ownCreature.getPower().getValue(); - Permanent targetCreature = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - if (targetCreature != null) { - targetCreature.damage(damage, ownCreature.getId(), source, game, false, true); - return true; - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/f/FallOfTheImpostor.java b/Mage.Sets/src/mage/cards/f/FallOfTheImpostor.java index 03896538e0a..b99c4a83d8e 100644 --- a/Mage.Sets/src/mage/cards/f/FallOfTheImpostor.java +++ b/Mage.Sets/src/mage/cards/f/FallOfTheImpostor.java @@ -1,16 +1,16 @@ package mage.cards.f; -import java.util.List; -import java.util.UUID; - +import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SagaAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.constants.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.*; import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; @@ -18,11 +18,14 @@ import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponent; +import java.util.List; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class FallOfTheImpostor extends CardImpl { @@ -77,33 +80,35 @@ class FallOfTheImpostorEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Player opponent = game.getPlayer(source.getFirstTarget()); - if (controller != null && opponent != null) { - List permanents = game.getBattlefield().getAllActivePermanents( - StaticFilters.FILTER_PERMANENT_CREATURE, opponent.getId(), game - ); - Integer maxPower = null; - for (Permanent permanent : permanents) { - if (permanent != null) { - int power = permanent.getPower().getValue(); - if (maxPower == null || power > maxPower) { - maxPower = power; - } - } - } - if (maxPower != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - filter.add(new ControllerIdPredicate(opponent.getId())); - filter.add(new PowerPredicate(ComparisonType.EQUAL_TO, maxPower)); - TargetCreaturePermanent target = new TargetCreaturePermanent(1, 1, filter, true); - controller.chooseTarget(outcome, target, source, game); - Permanent permanent = game.getPermanent(target.getFirstTarget()); - if (permanent != null) { - controller.moveCardsToExile(permanent, source, game, true, null, null); - return true; - } - } + Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (controller == null || opponent == null) { + return false; } - return false; + List permanents = game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, opponent.getId(), game + ); + Permanent permanent; + switch (permanents.size()) { + case 0: + return false; + case 1: + permanent = permanents.get(0); + break; + default: + int power = permanents + .stream() + .map(MageObject::getPower) + .mapToInt(MageInt::getValue) + .max() + .orElse(Integer.MIN_VALUE); + FilterPermanent filter = new FilterCreaturePermanent(); + filter.add(new ControllerIdPredicate(opponent.getId())); + filter.add(new PowerPredicate(ComparisonType.OR_GREATER, power)); + TargetPermanent target = new TargetPermanent(filter); + target.withNotTarget(true); + controller.chooseTarget(outcome, target, source, game); + permanent = game.getPermanent(target.getFirstTarget()); + } + return permanent != null && controller.moveCards(permanent, Zone.EXILED, source, game); } } diff --git a/Mage.Sets/src/mage/cards/f/FallingTimber.java b/Mage.Sets/src/mage/cards/f/FallingTimber.java index 388938cccfa..8871740caec 100644 --- a/Mage.Sets/src/mage/cards/f/FallingTimber.java +++ b/Mage.Sets/src/mage/cards/f/FallingTimber.java @@ -1,6 +1,5 @@ package mage.cards.f; -import mage.abilities.condition.common.KickedCondition; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.effects.Effect; import mage.abilities.effects.common.PreventDamageByTargetEffect; @@ -15,6 +14,8 @@ import mage.target.targetadjustment.ConditionalTargetAdjuster; import java.util.UUID; +import static mage.abilities.condition.common.KickedCondition.ONCE; + /** * @author LoneFox */ @@ -33,8 +34,7 @@ public final class FallingTimber extends CardImpl { "prevent all combat damage another target creature would deal this turn."); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().setTargetAdjuster(new ConditionalTargetAdjuster(KickedCondition.ONCE, - new TargetCreaturePermanent(2))); + this.getSpellAbility().setTargetAdjuster(new ConditionalTargetAdjuster(ONCE, new TargetCreaturePermanent(2))); } private FallingTimber(final FallingTimber card) { diff --git a/Mage.Sets/src/mage/cards/f/FamiliarsRuse.java b/Mage.Sets/src/mage/cards/f/FamiliarsRuse.java index 7a5bf7a937c..320219f4ee2 100644 --- a/Mage.Sets/src/mage/cards/f/FamiliarsRuse.java +++ b/Mage.Sets/src/mage/cards/f/FamiliarsRuse.java @@ -1,28 +1,26 @@ - package mage.cards.f; -import java.util.UUID; import mage.abilities.costs.common.ReturnToHandChosenControlledPermanentCost; import mage.abilities.effects.common.CounterTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.target.TargetSpell; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class FamiliarsRuse extends CardImpl { public FamiliarsRuse(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}{U}"); // As an additional cost to cast Familiar's Ruse, return a creature you control to its owner's hand. - this.getSpellAbility().addCost(new ReturnToHandChosenControlledPermanentCost( - new TargetControlledCreaturePermanent(1, 1, new FilterControlledCreaturePermanent("creature"), true))); + this.getSpellAbility().addCost(new ReturnToHandChosenControlledPermanentCost(new TargetControlledCreaturePermanent())); + // Counter target spell. this.getSpellAbility().addEffect(new CounterTargetEffect()); this.getSpellAbility().addTarget(new TargetSpell()); diff --git a/Mage.Sets/src/mage/cards/f/FamishedForagers.java b/Mage.Sets/src/mage/cards/f/FamishedForagers.java index 0caf83609e8..63a0547c5f1 100644 --- a/Mage.Sets/src/mage/cards/f/FamishedForagers.java +++ b/Mage.Sets/src/mage/cards/f/FamishedForagers.java @@ -8,7 +8,6 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.OpponentsLostLifeCondition; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.mana.BasicManaEffect; import mage.abilities.hint.common.OpponentsLostLifeHint; @@ -32,11 +31,8 @@ public final class FamishedForagers extends CardImpl { this.toughness = new MageInt(3); // When Famished Foragers enters the battlefield, if an opponent lost life this turn, add {R}{R}{R}. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new BasicManaEffect(Mana.RedMana(3))), - OpponentsLostLifeCondition.instance, "When {this} enters, " + - "if an opponent lost life this turn, add {R}{R}{R}." - ).addHint(OpponentsLostLifeHint.instance)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new BasicManaEffect(Mana.RedMana(3))) + .withInterveningIf(OpponentsLostLifeCondition.instance).addHint(OpponentsLostLifeHint.instance)); // {2}{R}, Discard a card: Draw a card. Ability ability = new SimpleActivatedAbility( diff --git a/Mage.Sets/src/mage/cards/f/FanaticOfXenagos.java b/Mage.Sets/src/mage/cards/f/FanaticOfXenagos.java index c46bc90550b..8644f5854a2 100644 --- a/Mage.Sets/src/mage/cards/f/FanaticOfXenagos.java +++ b/Mage.Sets/src/mage/cards/f/FanaticOfXenagos.java @@ -1,11 +1,9 @@ - package mage.cards.f; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.TributeNotPaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.HasteAbility; @@ -34,13 +32,18 @@ public final class FanaticOfXenagos extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); + // Tribute 1 this.addAbility(new TributeAbility(1)); + // When Fanatic of Xenagos enters the battlefield, if tribute wasn't paid, it gets +1/+1 and gains haste until end of turn. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn)); - ability.addEffect(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.EndOfTurn)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, TributeNotPaidCondition.instance, - "When {this} enters, if tribute wasn't paid, it gets +1/+1 and gains haste until end of turn.")); + Ability ability = new EntersBattlefieldTriggeredAbility( + new BoostSourceEffect(1, 1, Duration.EndOfTurn).setText("it gets +1/+1") + ).withInterveningIf(TributeNotPaidCondition.instance); + ability.addEffect(new GainAbilitySourceEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains haste until end of turn")); + this.addAbility(ability); } private FanaticOfXenagos(final FanaticOfXenagos card) { diff --git a/Mage.Sets/src/mage/cards/f/FangOfThePack.java b/Mage.Sets/src/mage/cards/f/FangOfThePack.java index 3f5c064dfba..9f7e2b608ef 100644 --- a/Mage.Sets/src/mage/cards/f/FangOfThePack.java +++ b/Mage.Sets/src/mage/cards/f/FangOfThePack.java @@ -1,21 +1,21 @@ package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.MeleeAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author Styxo */ public final class FangOfThePack extends CardImpl { @@ -32,7 +32,7 @@ public final class FangOfThePack extends CardImpl { // At the beginning of combat on your turn, another target creature you control gains melee until end of turn. Ability ability = new BeginningOfCombatTriggeredAbility(new GainAbilityTargetEffect(new MeleeAbility(), Duration.EndOfTurn)); - ability.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FangSkulkin.java b/Mage.Sets/src/mage/cards/f/FangSkulkin.java index 0ed4a8ead57..334fdf1b3cb 100644 --- a/Mage.Sets/src/mage/cards/f/FangSkulkin.java +++ b/Mage.Sets/src/mage/cards/f/FangSkulkin.java @@ -17,6 +17,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -36,7 +37,7 @@ public final class FangSkulkin extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(1); Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(WitherAbility.getInstance(), Duration.EndOfTurn), new GenericManaCost(2)); - ability.addTarget(new TargetCreaturePermanent(filterBlackCreature)); + ability.addTarget(new TargetPermanent(filterBlackCreature)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FaramirStewardOfGondor.java b/Mage.Sets/src/mage/cards/f/FaramirStewardOfGondor.java index 252036d6c90..5144ca7f5d8 100644 --- a/Mage.Sets/src/mage/cards/f/FaramirStewardOfGondor.java +++ b/Mage.Sets/src/mage/cards/f/FaramirStewardOfGondor.java @@ -1,12 +1,12 @@ package mage.cards.f; import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.condition.common.MonarchIsSourceControllerCondition; import mage.abilities.effects.common.BecomesMonarchSourceEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.common.MonarchHint; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -23,7 +23,7 @@ import java.util.UUID; public final class FaramirStewardOfGondor extends CardImpl { private static final FilterPermanent filter - = new FilterControlledCreaturePermanent("a legendary creature with mana value 4 or greater"); + = new FilterControlledCreaturePermanent("a legendary creature you control with mana value 4 or greater"); static { filter.add(SuperType.LEGENDARY.getPredicate()); @@ -40,7 +40,7 @@ public final class FaramirStewardOfGondor extends CardImpl { this.toughness = new MageInt(2); // Whenever a legendary creature with mana value 4 or greater you control enters, you become the monarch. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new BecomesMonarchSourceEffect(), filter).addHint(MonarchHint.instance)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility(new BecomesMonarchSourceEffect(), filter).addHint(MonarchHint.instance)); // At the beginning of your end step, if you're the monarch, create two 1/1 white Human Soldier creature tokens. this.addAbility(new BeginningOfEndStepTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/f/FarrelsMantle.java b/Mage.Sets/src/mage/cards/f/FarrelsMantle.java index 945e1488a63..596abc2e441 100644 --- a/Mage.Sets/src/mage/cards/f/FarrelsMantle.java +++ b/Mage.Sets/src/mage/cards/f/FarrelsMantle.java @@ -21,6 +21,7 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.DefineByTriggerTargetAdjuster; import java.util.UUID; @@ -58,6 +59,7 @@ class FarrelsMantleTriggeredAbility extends TriggeredAbilityImpl { FarrelsMantleTriggeredAbility() { super(Zone.BATTLEFIELD, null, false); + setTargetAdjuster(DefineByTriggerTargetAdjuster.instance); } private FarrelsMantleTriggeredAbility(final FarrelsMantleTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/f/FarsightMask.java b/Mage.Sets/src/mage/cards/f/FarsightMask.java index 16b3ee4835f..fe103a80d18 100644 --- a/Mage.Sets/src/mage/cards/f/FarsightMask.java +++ b/Mage.Sets/src/mage/cards/f/FarsightMask.java @@ -2,7 +2,6 @@ package mage.cards.f; import mage.abilities.common.SourceDealsDamageToYouTriggeredAbility; import mage.abilities.condition.common.SourceTappedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -15,15 +14,13 @@ import java.util.UUID; */ public final class FarsightMask extends CardImpl { - private static final String rule = "Whenever a source an opponent controls deals damage to you, if {this} is untapped, you may draw a card."; - public FarsightMask(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); // Whenever a source an opponent controls deals damage to you, if Farsight Mask is untapped, you may draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new SourceDealsDamageToYouTriggeredAbility( + this.addAbility(new SourceDealsDamageToYouTriggeredAbility( new DrawCardSourceControllerEffect(1), true - ), SourceTappedCondition.UNTAPPED, rule)); + ).withInterveningIf(SourceTappedCondition.UNTAPPED)); } private FarsightMask(final FarsightMask card) { diff --git a/Mage.Sets/src/mage/cards/f/FateTransfer.java b/Mage.Sets/src/mage/cards/f/FateTransfer.java index 358fcd3c1ed..1e5b0d36d0f 100644 --- a/Mage.Sets/src/mage/cards/f/FateTransfer.java +++ b/Mage.Sets/src/mage/cards/f/FateTransfer.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -9,36 +7,26 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.counters.Counter; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.other.AnotherTargetPredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class FateTransfer extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("target creature to move all counters from"); - private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another target creature to move all counters to"); - public FateTransfer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U/B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U/B}"); // Move all counters from target creature onto another target creature. this.getSpellAbility().addEffect(new FateTransferEffect()); - - TargetCreaturePermanent fromTarget = new TargetCreaturePermanent(filter); - fromTarget.setTargetTag(1); - this.getSpellAbility().addTarget(fromTarget); - - TargetCreaturePermanent toTarget = new TargetCreaturePermanent(filter2); - filter2.add(new AnotherTargetPredicate(2)); - toTarget.setTargetTag(2); - this.getSpellAbility().addTarget(toTarget); - + this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("to remove counters from").setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2).setTargetTag(2)); } private FateTransfer(final FateTransfer card) { diff --git a/Mage.Sets/src/mage/cards/f/FathomFleetCaptain.java b/Mage.Sets/src/mage/cards/f/FathomFleetCaptain.java index b90388e91cf..43ce66c3a56 100644 --- a/Mage.Sets/src/mage/cards/f/FathomFleetCaptain.java +++ b/Mage.Sets/src/mage/cards/f/FathomFleetCaptain.java @@ -1,12 +1,11 @@ package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.keyword.MenaceAbility; @@ -15,24 +14,27 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.permanent.token.PirateToken; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class FathomFleetCaptain extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("another nontoken Pirate"); + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.PIRATE, "you control another nontoken Pirate"); static { - filter.add(SubType.PIRATE.getPredicate()); filter.add(AnotherPredicate.instance); filter.add(TokenPredicate.FALSE); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + public FathomFleetCaptain(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); @@ -45,10 +47,9 @@ public final class FathomFleetCaptain extends CardImpl { this.addAbility(new MenaceAbility(false)); // Whenever Fathom Fleet Captain attacks, if you control another nontoken Pirate, you may pay {2}. If you do, creature a 2/2 black Pirate creature token with menace. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new PirateToken()), new GenericManaCost(2)), false), - new PermanentsOnTheBattlefieldCondition(filter), - "Whenever {this} attacks, if you control another nontoken Pirate, you may pay {2}. If you do, create a 2/2 black Pirate creature token with menace")); + this.addAbility(new AttacksTriggeredAbility( + new DoIfCostPaid(new CreateTokenEffect(new PirateToken()), new GenericManaCost(2)) + ).withInterveningIf(condition)); } private FathomFleetCaptain(final FathomFleetCaptain card) { diff --git a/Mage.Sets/src/mage/cards/f/FearOfAbduction.java b/Mage.Sets/src/mage/cards/f/FearOfAbduction.java index 72792029d78..6deb44b115d 100644 --- a/Mage.Sets/src/mage/cards/f/FearOfAbduction.java +++ b/Mage.Sets/src/mage/cards/f/FearOfAbduction.java @@ -21,10 +21,13 @@ import mage.filter.StaticFilters; import mage.game.ExileZone; import mage.game.Game; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; import mage.util.CardUtil; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * @author Cguy7777 */ @@ -46,7 +49,7 @@ public final class FearOfAbduction extends CardImpl { // When Fear of Abduction enters, exile target creature an opponent controls. Ability ability = new EntersBattlefieldTriggeredAbility(new FearOfAbductionExileEffect()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); // When Fear of Abduction leaves the battlefield, put each card exiled with it into its owner's hand. diff --git a/Mage.Sets/src/mage/cards/f/FearOfBurningAlive.java b/Mage.Sets/src/mage/cards/f/FearOfBurningAlive.java index 0f04e9a404f..a8eb54fb63c 100644 --- a/Mage.Sets/src/mage/cards/f/FearOfBurningAlive.java +++ b/Mage.Sets/src/mage/cards/f/FearOfBurningAlive.java @@ -1,8 +1,9 @@ package mage.cards.f; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SourceDealsNoncombatDamageToOpponentTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.dynamicvalue.common.SavedDamageValue; @@ -11,13 +12,9 @@ import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; -import mage.game.events.DamagedEvent; -import mage.game.events.GameEvent; import mage.target.TargetPermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; import java.util.UUID; @@ -39,7 +36,13 @@ public final class FearOfBurningAlive extends CardImpl { )); // Delirium -- Whenever a source you control deals noncombat damage to an opponent, if there are four or more card types among cards in your graveyard, Fear of Burning Alive deals that amount of damage to target creature that player controls. - this.addAbility(new FearOfBurningAliveTriggeredAbility()); + TriggeredAbility ability = new SourceDealsNoncombatDamageToOpponentTriggeredAbility(new DamageTargetEffect(SavedDamageValue.AMOUNT), SetTargetPointer.PLAYER); + ability.addTarget(new TargetPermanent(new FilterCreaturePermanent("creature that player controls"))); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); + ability.withInterveningIf(DeliriumCondition.instance); + ability.setAbilityWord(AbilityWord.DELIRIUM); + ability.addHint(CardTypesInGraveyardCount.YOU.getHint()); + this.addAbility(ability); } private FearOfBurningAlive(final FearOfBurningAlive card) { @@ -51,49 +54,3 @@ public final class FearOfBurningAlive extends CardImpl { return new FearOfBurningAlive(this); } } - -class FearOfBurningAliveTriggeredAbility extends TriggeredAbilityImpl { - - FearOfBurningAliveTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(SavedDamageValue.MANY) - .setText("{this} deals that amount of damage to target creature that player controls")); - this.setTriggerPhrase("Whenever a source you control deals noncombat damage to an opponent, " + - "if there are four or more card types among cards in your graveyard, "); - this.setAbilityWord(AbilityWord.DELIRIUM); - this.addHint(CardTypesInGraveyardCount.YOU.getHint()); - } - - private FearOfBurningAliveTriggeredAbility(final FearOfBurningAliveTriggeredAbility ability) { - super(ability); - } - - @Override - public FearOfBurningAliveTriggeredAbility copy() { - return new FearOfBurningAliveTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (((DamagedEvent) event).isCombatDamage() - || !isControlledBy(game.getControllerId(event.getSourceId())) - || !game.getOpponents(getControllerId()).contains(event.getTargetId())) { - return false; - } - this.getEffects().setValue("damage", event.getAmount()); - FilterPermanent filter = new FilterCreaturePermanent(); - filter.add(new ControllerIdPredicate(event.getTargetId())); - this.getTargets().clear(); - this.addTarget(new TargetPermanent(filter)); - return true; - } - - @Override - public boolean checkInterveningIfClause(Game game) { - return DeliriumCondition.instance.apply(game, this); - } -} diff --git a/Mage.Sets/src/mage/cards/f/FearOfMissingOut.java b/Mage.Sets/src/mage/cards/f/FearOfMissingOut.java index fc56747b5da..7dabdb2455e 100644 --- a/Mage.Sets/src/mage/cards/f/FearOfMissingOut.java +++ b/Mage.Sets/src/mage/cards/f/FearOfMissingOut.java @@ -5,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.common.AttacksFirstTimeTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.AdditionalCombatPhaseEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -13,6 +12,7 @@ import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.discard.DiscardControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; @@ -37,16 +37,10 @@ public final class FearOfMissingOut extends CardImpl { this.addAbility(ability); // Delirium -- Whenever Fear of Missing Out attacks for the first time each turn, if there are four or more card types among cards in your graveyard, untap target creature. After this phase, there is an additional combat phase. - ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksFirstTimeTriggeredAbility(new UntapTargetEffect(), false), - DeliriumCondition.instance, "Delirium — Whenever {this} attacks for the first time each turn, " - + "if there are four or more card types among cards in your graveyard, untap target creature. " - + "After this phase, there is an additional combat phase." - ); + ability = new AttacksFirstTimeTriggeredAbility(new UntapTargetEffect(), false).withInterveningIf(DeliriumCondition.instance); ability.addTarget(new TargetCreaturePermanent()); ability.addEffect(new AdditionalCombatPhaseEffect()); - ability.addHint(CardTypesInGraveyardCount.YOU.getHint()); - this.addAbility(ability); + this.addAbility(ability.setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); } private FearOfMissingOut(final FearOfMissingOut card) { diff --git a/Mage.Sets/src/mage/cards/f/FearOfTheDark.java b/Mage.Sets/src/mage/cards/f/FearOfTheDark.java index f316b1b50a2..f7af03b0178 100644 --- a/Mage.Sets/src/mage/cards/f/FearOfTheDark.java +++ b/Mage.Sets/src/mage/cards/f/FearOfTheDark.java @@ -5,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.MenaceAbility; @@ -26,7 +25,7 @@ import java.util.UUID; */ public final class FearOfTheDark extends CardImpl { - private static final FilterPermanent filter = new FilterCreaturePermanent(SubType.GLIMMER, ""); + private static final FilterPermanent filter = new FilterCreaturePermanent(SubType.GLIMMER, "defending player controls no Glimmer creatures"); static { filter.add(DefendingPlayerControlsSourceAttackingPredicate.instance); @@ -44,12 +43,12 @@ public final class FearOfTheDark extends CardImpl { this.toughness = new MageInt(5); // Whenever Fear of the Dark attacks, if defending player controls no Glimmer creatures, it gains menace and deathtouch until end of turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new GainAbilitySourceEffect(new MenaceAbility(), Duration.EndOfTurn)), - condition, "Whenever {this} attacks, if defending player controls no Glimmer " + - "creatures, it gains menace and deathtouch until end of turn." - ); - ability.addEffect(new GainAbilitySourceEffect(DeathtouchAbility.getInstance(), Duration.EndOfTurn)); + Ability ability = new AttacksTriggeredAbility(new GainAbilitySourceEffect( + new MenaceAbility(), Duration.EndOfTurn + ).setText("it gains menace")).withInterveningIf(condition); + ability.addEffect(new GainAbilitySourceEffect( + DeathtouchAbility.getInstance(), Duration.EndOfTurn + ).setText("and deathtouch until end of turn")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FeastOfDreams.java b/Mage.Sets/src/mage/cards/f/FeastOfDreams.java index 366b3cd190d..5ccda8f8ddb 100644 --- a/Mage.Sets/src/mage/cards/f/FeastOfDreams.java +++ b/Mage.Sets/src/mage/cards/f/FeastOfDreams.java @@ -9,6 +9,7 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.EnchantedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -32,7 +33,7 @@ public final class FeastOfDreams extends CardImpl { // Destroy target enchanted creature or enchantment creature. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private FeastOfDreams(final FeastOfDreams card) { diff --git a/Mage.Sets/src/mage/cards/f/FeastOfFlesh.java b/Mage.Sets/src/mage/cards/f/FeastOfFlesh.java index 51c979518c8..d0c3c6cdef6 100644 --- a/Mage.Sets/src/mage/cards/f/FeastOfFlesh.java +++ b/Mage.Sets/src/mage/cards/f/FeastOfFlesh.java @@ -1,7 +1,6 @@ package mage.cards.f; -import java.util.UUID; import mage.abilities.dynamicvalue.IntPlusDynamicValue; import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount; import mage.abilities.effects.Effect; @@ -14,8 +13,9 @@ import mage.filter.FilterCard; import mage.filter.predicate.mageobject.NamePredicate; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author L_J */ public final class FeastOfFlesh extends CardImpl { @@ -27,14 +27,14 @@ public final class FeastOfFlesh extends CardImpl { } public FeastOfFlesh(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); // Feast of Flesh deals X damage to target creature and you gain X life, where X is 1 plus the number of cards named Feast of Flesh in all graveyards. IntPlusDynamicValue value = new IntPlusDynamicValue(1, new CardsInAllGraveyardsCount(filter)); Effect effect1 = new DamageTargetEffect(value); - effect1.setText("Feast of Flesh deals X damage to target creature"); + effect1.setText("{this} deals X damage to target creature"); Effect effect2 = new GainLifeEffect(value); - effect2.setText("and you gain X life, where X is 1 plus the number of cards named {this} in all graveyards"); + effect2.setText("and you gain X life, where X is 1 plus the number of cards named Feast of Flesh in all graveyards"); this.getSpellAbility().addEffect(effect1); this.getSpellAbility().addEffect(effect2); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/f/FeastOnTheFallen.java b/Mage.Sets/src/mage/cards/f/FeastOnTheFallen.java index 01cd22fba5c..8a1c24b7920 100644 --- a/Mage.Sets/src/mage/cards/f/FeastOnTheFallen.java +++ b/Mage.Sets/src/mage/cards/f/FeastOnTheFallen.java @@ -1,12 +1,9 @@ - package mage.cards.f; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -16,23 +13,20 @@ import mage.game.Game; import mage.target.common.TargetControlledCreaturePermanent; import mage.watchers.common.PlayerLostLifeWatcher; +import java.util.UUID; + /** - * * @author emerald000 */ public final class FeastOnTheFallen extends CardImpl { public FeastOnTheFallen(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}"); // At the beginning of each upkeep, if an opponent lost life last turn, put a +1/+1 counter on target creature you control. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - TargetController.ANY, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), - false), - FeastOnTheFallenCondition.instance, - "At the beginning of each upkeep, if an opponent lost life last turn, put a +1/+1 counter on target creature you control."); + Ability ability = new BeginningOfUpkeepTriggeredAbility( + TargetController.ANY, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false + ).withInterveningIf(FeastOnTheFallenCondition.instance); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); } @@ -54,13 +48,16 @@ enum FeastOnTheFallenCondition implements Condition { @Override public boolean apply(Game game, Ability source) { PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class); - if (watcher != null) { - for (UUID opponentId : game.getOpponents(source.getControllerId())) { - if (watcher.getLifeLostLastTurn(opponentId) > 0) { - return true; - } - } - } - return false; + return watcher != null + && game + .getOpponents(source.getControllerId()) + .stream() + .mapToInt(watcher::getLifeLostLastTurn) + .anyMatch(x -> x > 0); + } + + @Override + public String toString() { + return "an opponent lost life last turn"; } } diff --git a/Mage.Sets/src/mage/cards/f/FeastOrFamine.java b/Mage.Sets/src/mage/cards/f/FeastOrFamine.java index 05aa80ebf49..89916b379b0 100644 --- a/Mage.Sets/src/mage/cards/f/FeastOrFamine.java +++ b/Mage.Sets/src/mage/cards/f/FeastOrFamine.java @@ -13,6 +13,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.permanent.token.ZombieToken; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -36,7 +37,7 @@ public final class FeastOrFamine extends CardImpl { // or destroy target nonartifact, nonblack creature and it can't be regenerated. Mode mode = new Mode(new DestroyTargetEffect(true)); - mode.addTarget(new TargetCreaturePermanent(filter)); + mode.addTarget(new TargetPermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FeastingTrollKing.java b/Mage.Sets/src/mage/cards/f/FeastingTrollKing.java index 8000de84d1c..29aa0be0ed2 100644 --- a/Mage.Sets/src/mage/cards/f/FeastingTrollKing.java +++ b/Mage.Sets/src/mage/cards/f/FeastingTrollKing.java @@ -6,7 +6,6 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromHandSourcePermanentCondition; import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; import mage.abilities.hint.common.MyTurnHint; @@ -19,7 +18,6 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; import mage.game.permanent.token.FoodToken; -import mage.target.common.TargetControlledPermanent; import mage.watchers.common.CastFromHandWatcher; import java.util.UUID; @@ -46,11 +44,8 @@ public final class FeastingTrollKing extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // When Feasting Troll King enters the battlefield, if you cast it from your hand, create three Food tokens. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new FoodToken(), 3)), - CastFromHandSourcePermanentCondition.instance, "When {this} enters, " + - "if you cast it from your hand, create three Food tokens." - ), new CastFromHandWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new FoodToken(), 3)) + .withInterveningIf(CastFromHandSourcePermanentCondition.instance), new CastFromHandWatcher()); // Sacrifice three Foods: Return Feasting Troll King from your graveyard to the battlefield. Activate this ability only during your turn. this.addAbility(new ActivateIfConditionActivatedAbility( diff --git a/Mage.Sets/src/mage/cards/f/FelhideSpiritbinder.java b/Mage.Sets/src/mage/cards/f/FelhideSpiritbinder.java index 7cdd4a7a6ca..b694442608c 100644 --- a/Mage.Sets/src/mage/cards/f/FelhideSpiritbinder.java +++ b/Mage.Sets/src/mage/cards/f/FelhideSpiritbinder.java @@ -20,9 +20,12 @@ import mage.constants.Outcome; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * * @author Quercitron @@ -39,7 +42,7 @@ public final class FelhideSpiritbinder extends CardImpl { // Inspired — Whenever Felhide Spiritbinder becomes untapped, you may pay {1}{R}. If you do, create a token that's a copy of another target creature except it's an enchantment in addition to its other types. It gains haste. Exile it at the beginning of the next end step. Ability ability = new InspiredAbility(new DoIfCostPaid(new FelhideSpiritbinderEffect(), new ManaCostsImpl<>("{1}{R}"), "Use effect of {this}?")); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FelineSovereign.java b/Mage.Sets/src/mage/cards/f/FelineSovereign.java index c682dac3761..399d4700c04 100644 --- a/Mage.Sets/src/mage/cards/f/FelineSovereign.java +++ b/Mage.Sets/src/mage/cards/f/FelineSovereign.java @@ -15,10 +15,8 @@ import mage.constants.*; import mage.filter.FilterCard; import mage.filter.common.FilterArtifactOrEnchantmentPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; -import mage.game.events.GameEvent; import mage.target.TargetPermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; import java.util.UUID; @@ -52,7 +50,10 @@ public final class FelineSovereign extends CardImpl { this.addAbility(ability); // Whenever one or more Cats you control deal combat damage to a player, destroy up to one target artifact or enchantment that player controls. - this.addAbility(new FelineSovereignTriggeredAbility()); + Ability ability2 = new OneOrMoreCombatDamagePlayerTriggeredAbility(new DestroyTargetEffect(), SetTargetPointer.PLAYER, filterCat, false); + ability2.addTarget(new TargetPermanent(0, 1, new FilterArtifactOrEnchantmentPermanent("artifact or enchantment that player controls"))); + ability2.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); + this.addAbility(ability2); } private FelineSovereign(final FelineSovereign card) { @@ -64,34 +65,3 @@ public final class FelineSovereign extends CardImpl { return new FelineSovereign(this); } } - -class FelineSovereignTriggeredAbility extends OneOrMoreCombatDamagePlayerTriggeredAbility { - - private static final FilterCreaturePermanent catFilter = new FilterCreaturePermanent(SubType.CAT, "Cats"); - - FelineSovereignTriggeredAbility() { - super(new DestroyTargetEffect().setText("destroy up to one target artifact or enchantment that player controls"), catFilter); - } - - private FelineSovereignTriggeredAbility(final FelineSovereignTriggeredAbility ability) { - super(ability); - } - - @Override - public FelineSovereignTriggeredAbility copy() { - return new FelineSovereignTriggeredAbility(this); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (!super.checkTrigger(event, game)) { - return false; - } - this.getTargets().clear(); - FilterArtifactOrEnchantmentPermanent filter = new FilterArtifactOrEnchantmentPermanent(); - filter.add(new ControllerIdPredicate(event.getTargetId())); - this.addTarget(new TargetPermanent(0, 1, filter, false)); - return true; - } - -} diff --git a/Mage.Sets/src/mage/cards/f/FemerefArchers.java b/Mage.Sets/src/mage/cards/f/FemerefArchers.java index 1bbe77a4ca2..404f855dee4 100644 --- a/Mage.Sets/src/mage/cards/f/FemerefArchers.java +++ b/Mage.Sets/src/mage/cards/f/FemerefArchers.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterAttackingCreature; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class FemerefArchers extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(4), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FeralContest.java b/Mage.Sets/src/mage/cards/f/FeralContest.java index 354c34eec8a..ad741759504 100644 --- a/Mage.Sets/src/mage/cards/f/FeralContest.java +++ b/Mage.Sets/src/mage/cards/f/FeralContest.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; @@ -10,36 +8,29 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.counters.CounterType; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.other.AnotherTargetPredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class FeralContest extends CardImpl { public FeralContest(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}"); // Put a +1/+1 counter on target creature you control. this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); - - TargetControlledCreaturePermanent target1 = new TargetControlledCreaturePermanent(); - target1.setTargetTag(1); - this.getSpellAbility().addTarget(target1); - + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent().setTargetTag(1)); + // Another target creature blocks it this turn if able. this.getSpellAbility().addEffect(new FeralContestEffect()); - FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature (must block this turn)"); - filter.add(new AnotherTargetPredicate(2)); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter); - target2.setTargetTag(2); - this.getSpellAbility().addTarget(target2); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2).withChooseHint("to force to block").setTargetTag(2)); } private FeralContest(final FeralContest card) { diff --git a/Mage.Sets/src/mage/cards/f/FeralEncounter.java b/Mage.Sets/src/mage/cards/f/FeralEncounter.java index 26c9885fb88..fc5c85bc6fe 100644 --- a/Mage.Sets/src/mage/cards/f/FeralEncounter.java +++ b/Mage.Sets/src/mage/cards/f/FeralEncounter.java @@ -17,8 +17,8 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; import mage.util.CardUtil; import java.util.UUID; @@ -36,7 +36,7 @@ public final class FeralEncounter extends CardImpl { DelayedTriggeredAbility delayed = new FeralEncounterDelayedTriggeredAbility(); delayed.addTarget(new TargetControlledCreaturePermanent()); - delayed.addTarget(new TargetCreaturePermanent(0, 1, StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL, false)); + delayed.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(delayed)); } diff --git a/Mage.Sets/src/mage/cards/f/FesteringNewt.java b/Mage.Sets/src/mage/cards/f/FesteringNewt.java index 323b1267474..1e30b621dfc 100644 --- a/Mage.Sets/src/mage/cards/f/FesteringNewt.java +++ b/Mage.Sets/src/mage/cards/f/FesteringNewt.java @@ -18,8 +18,11 @@ import mage.constants.Duration; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.NamePredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -46,7 +49,7 @@ public final class FesteringNewt extends CardImpl { new LockedInCondition(new PermanentsOnTheBattlefieldCondition(filterBogbrewWitch)), "target creature an opponent controls gets -1/-1 until end of turn. That creature gets -4/-4 instead if you control a creature named Bogbrew Witch"); Ability ability = new DiesSourceTriggeredAbility(effect); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FeverCharm.java b/Mage.Sets/src/mage/cards/f/FeverCharm.java index 7921e494ded..fb08d418f01 100644 --- a/Mage.Sets/src/mage/cards/f/FeverCharm.java +++ b/Mage.Sets/src/mage/cards/f/FeverCharm.java @@ -13,6 +13,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class FeverCharm extends CardImpl { this.getSpellAbility().addMode(mode); // or Fever Charm deals 3 damage to target Wizard creature. mode = new Mode(new DamageTargetEffect(3)); - mode.addTarget(new TargetCreaturePermanent(filter)); + mode.addTarget(new TargetPermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FeveredSuspicion.java b/Mage.Sets/src/mage/cards/f/FeveredSuspicion.java index 9032c3b34c9..2f9ecf9032b 100644 --- a/Mage.Sets/src/mage/cards/f/FeveredSuspicion.java +++ b/Mage.Sets/src/mage/cards/f/FeveredSuspicion.java @@ -78,6 +78,7 @@ class FeveredSuspicionEffect extends OneShotEffect { } } controller.moveCards(cards, Zone.EXILED, source, game); + game.processAction(); nonlands.retainZone(Zone.EXILED, game); CardUtil.castMultipleWithAttributeForFree( controller, source, game, nonlands, diff --git a/Mage.Sets/src/mage/cards/f/FeySteed.java b/Mage.Sets/src/mage/cards/f/FeySteed.java index beaecd6abeb..df32f25e7e5 100644 --- a/Mage.Sets/src/mage/cards/f/FeySteed.java +++ b/Mage.Sets/src/mage/cards/f/FeySteed.java @@ -16,6 +16,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.permanent.AttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -50,7 +51,7 @@ public final class FeySteed extends CardImpl { // Whenever Fey Steed attacks, another target attacking creature you control gains indestructible until end of turn. Ability ability = new AttacksTriggeredAbility( new GainAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), false); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Whenever a creature or planeswalker you control becomes the target of a spell or ability an opponent controls, you may draw a card. diff --git a/Mage.Sets/src/mage/cards/f/FieldOfTheDead.java b/Mage.Sets/src/mage/cards/f/FieldOfTheDead.java index 92c7fdadf5c..448e161a1ad 100644 --- a/Mage.Sets/src/mage/cards/f/FieldOfTheDead.java +++ b/Mage.Sets/src/mage/cards/f/FieldOfTheDead.java @@ -4,7 +4,6 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; @@ -32,13 +31,9 @@ public final class FieldOfTheDead extends CardImpl { this.addAbility(new ColorlessManaAbility()); // Whenever Field of the Dead or another land you control enters, if you control seven or more lands with different names, create a 2/2 black Zombie creature token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldThisOrAnotherTriggeredAbility( - new CreateTokenEffect(new ZombieToken()), StaticFilters.FILTER_LAND, false, true - ), FieldOfTheDeadCondition.instance, "Whenever {this} or another land " + - "you control enters, if you control seven or more lands with different names, " + - "create a 2/2 black Zombie creature token." - )); + this.addAbility(new EntersBattlefieldThisOrAnotherTriggeredAbility( + new CreateTokenEffect(new ZombieToken()), StaticFilters.FILTER_LAND, false, true + ).withInterveningIf(FieldOfTheDeadCondition.instance)); } private FieldOfTheDead(final FieldOfTheDead card) { @@ -69,4 +64,9 @@ enum FieldOfTheDeadCondition implements Condition { .distinct() .count() > 6; } + + @Override + public String toString() { + return "you control seven or more lands with different names"; + } } diff --git a/Mage.Sets/src/mage/cards/f/FieldSurgeon.java b/Mage.Sets/src/mage/cards/f/FieldSurgeon.java index 32e91858a89..11a8dceb448 100644 --- a/Mage.Sets/src/mage/cards/f/FieldSurgeon.java +++ b/Mage.Sets/src/mage/cards/f/FieldSurgeon.java @@ -1,4 +1,3 @@ - package mage.cards.f; import mage.MageInt; @@ -11,10 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -24,12 +20,6 @@ import java.util.UUID; */ public final class FieldSurgeon extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("an untapped creature you control"); - - static { - filter.add(TappedPredicate.UNTAPPED); - } - public FieldSurgeon(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.subtype.add(SubType.HUMAN); @@ -38,8 +28,10 @@ public final class FieldSurgeon extends CardImpl { this.toughness = new MageInt(1); // Tap an untapped creature you control: Prevent the next 1 damage that would be dealt to target creature this turn. - Ability ability = new SimpleActivatedAbility(new PreventDamageToTargetEffect(Duration.EndOfTurn, 1), - new TapTargetCost(new TargetControlledCreaturePermanent(filter))); + Ability ability = new SimpleActivatedAbility( + new PreventDamageToTargetEffect(Duration.EndOfTurn, 1), + new TapTargetCost(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE) + ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FiendBinder.java b/Mage.Sets/src/mage/cards/f/FiendBinder.java index 5059619cdc4..34ac77e08a6 100644 --- a/Mage.Sets/src/mage/cards/f/FiendBinder.java +++ b/Mage.Sets/src/mage/cards/f/FiendBinder.java @@ -12,6 +12,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -34,7 +35,7 @@ public final class FiendBinder extends CardImpl { // Whenever Fiend Binder attacks, tap target creature defending player controls. Ability ability = new AttacksTriggeredAbility(new TapTargetEffect(), false); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FieryGambit.java b/Mage.Sets/src/mage/cards/f/FieryGambit.java index 2b7283c329e..f4adba73023 100644 --- a/Mage.Sets/src/mage/cards/f/FieryGambit.java +++ b/Mage.Sets/src/mage/cards/f/FieryGambit.java @@ -44,7 +44,7 @@ class FieryGambitEffect extends OneShotEffect { FieryGambitEffect() { super(Outcome.Benefit); - this.staticText = "Flip a coin until you lose a flip or choose to stop flipping. If you lose a flip, Fiery Gambit has no effect. If you win one or more flips, Fiery Gambit deals 3 damage to target creature. If you win two or more flips, Fiery Gambit deals 6 damage to each opponent. If you win three or more flips, draw nine cards and untap all lands you control"; + this.staticText = "Flip a coin until you lose a flip or choose to stop flipping. If you lose a flip, {this} has no effect. If you win one or more flips, {this} deals 3 damage to target creature. If you win two or more flips, {this} deals 6 damage to each opponent. If you win three or more flips, draw nine cards and untap all lands you control"; } private FieryGambitEffect(final FieryGambitEffect effect) { diff --git a/Mage.Sets/src/mage/cards/f/FightOrFlight.java b/Mage.Sets/src/mage/cards/f/FightOrFlight.java index 55a1bcd9a6a..2a1a4f5ed9d 100644 --- a/Mage.Sets/src/mage/cards/f/FightOrFlight.java +++ b/Mage.Sets/src/mage/cards/f/FightOrFlight.java @@ -1,9 +1,9 @@ package mage.cards.f; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.combat.CantAttackAllEffect; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -18,7 +18,7 @@ import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.ArrayList; import java.util.List; @@ -26,13 +26,12 @@ import java.util.UUID; import java.util.stream.Collectors; /** - * * @author LevelX2 & L_J */ public final class FightOrFlight extends CardImpl { public FightOrFlight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); // At the beginning of combat on each opponent’s turn, separate all creatures that player controls into two piles. Only creatures in the pile of their choice can attack this turn. this.addAbility(new BeginningOfCombatTriggeredAbility(TargetController.OPPONENT, new FightOrFlightEffect(), false)); @@ -73,7 +72,7 @@ class FightOrFlightEffect extends OneShotEffect { } FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures to put in the first pile"); filter.add(new ControllerIdPredicate(targetPlayer.getId())); - TargetCreaturePermanent creatures = new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, true); + TargetPermanent creatures = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); List pile1 = new ArrayList<>(); if (player.choose(Outcome.Neutral, creatures, source, game)) { List targets = creatures.getTargets(); diff --git a/Mage.Sets/src/mage/cards/f/FinestHour.java b/Mage.Sets/src/mage/cards/f/FinestHour.java index b594c923a25..6b000b1adad 100644 --- a/Mage.Sets/src/mage/cards/f/FinestHour.java +++ b/Mage.Sets/src/mage/cards/f/FinestHour.java @@ -1,19 +1,18 @@ package mage.cards.f; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.AttacksAloneControlledTriggeredAbility; import mage.abilities.condition.common.FirstCombatPhaseCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.AdditionalCombatPhaseEffect; +import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.keyword.ExaltedAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import java.util.UUID; + /** - * * @author awjackson */ public final class FinestHour extends CardImpl { @@ -26,12 +25,9 @@ public final class FinestHour extends CardImpl { // Whenever a creature you control attacks alone, if it's the first combat phase of the turn, untap that // creature. After this phase, there is an additional combat phase. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksAloneControlledTriggeredAbility(new UntapTargetEffect("untap that creature"), true, false), - FirstCombatPhaseCondition.instance, - "Whenever a creature you control attacks alone, if it's the first combat phase of the turn, " + - "untap that creature. After this phase, there is an additional combat phase." - ); + Ability ability = new AttacksAloneControlledTriggeredAbility( + new UntapTargetEffect("untap that creature"), true, false + ).withInterveningIf(FirstCombatPhaseCondition.instance); ability.addEffect(new AdditionalCombatPhaseEffect()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FirbolgFlutist.java b/Mage.Sets/src/mage/cards/f/FirbolgFlutist.java index ad9f3e92b5d..7a45290f3a3 100644 --- a/Mage.Sets/src/mage/cards/f/FirbolgFlutist.java +++ b/Mage.Sets/src/mage/cards/f/FirbolgFlutist.java @@ -14,10 +14,13 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author TheElk801 */ @@ -42,7 +45,7 @@ public final class FirbolgFlutist extends CardImpl { ability.addEffect(new GainAbilityTargetEffect( new MyriadAbility(), Duration.EndOfTurn ).setText("and myriad until end of turn")); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.addAbility(ability.withFlavorWord("Enthralling Performance")); } diff --git a/Mage.Sets/src/mage/cards/f/FireBowman.java b/Mage.Sets/src/mage/cards/f/FireBowman.java index 7b98f5f4d38..b545be81e67 100644 --- a/Mage.Sets/src/mage/cards/f/FireBowman.java +++ b/Mage.Sets/src/mage/cards/f/FireBowman.java @@ -10,7 +10,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.target.common.TargetAnyTarget; import java.util.UUID; @@ -30,7 +29,7 @@ public final class FireBowman extends CardImpl { // Sacrifice Fire Bowman: Fire Bowman deals 1 damage to any target. Activate this ability only during your turn, before attackers are declared. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new DamageTargetEffect(1, "it"), + new DamageTargetEffect(1, "it"), new SacrificeSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance ); ability.addTarget(new TargetAnyTarget()); diff --git a/Mage.Sets/src/mage/cards/f/FiremaneAngel.java b/Mage.Sets/src/mage/cards/f/FiremaneAngel.java index 4a290c38a90..b61e49d77b5 100644 --- a/Mage.Sets/src/mage/cards/f/FiremaneAngel.java +++ b/Mage.Sets/src/mage/cards/f/FiremaneAngel.java @@ -1,36 +1,33 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.PhaseStep; import mage.constants.TargetController; import mage.constants.Zone; import mage.game.Game; +import java.util.UUID; + /** - * * @author Loki */ public final class FiremaneAngel extends CardImpl { public FiremaneAngel(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{W}{W}"); this.subtype.add(SubType.ANGEL); this.power = new MageInt(4); @@ -38,17 +35,20 @@ public final class FiremaneAngel extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); + // Firststrike this.addAbility(FirstStrikeAbility.getInstance()); + // At the beginning of your upkeep, if Firemane Angel is in your graveyard or on the battlefield, you may gain 1 life. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(Zone.ALL, TargetController.YOU, new GainLifeEffect(1), true), - SourceOnBattlefieldOrGraveyardCondition.instance, - "At the beginning of your upkeep, if {this} is in your graveyard or on the battlefield, you may gain 1 life."); - this.addAbility(ability); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + Zone.ALL, TargetController.YOU, new GainLifeEffect(1), true + ).withInterveningIf(FiremaneAngelCondition.instance)); + // {6}{R}{R}{W}{W}: Return Firemane Angel from your graveyard to the battlefield. Activate this ability only during your upkeep. - this.addAbility(new ConditionalActivatedAbility(Zone.GRAVEYARD, - new ReturnSourceFromGraveyardToBattlefieldEffect(false, false), new ManaCostsImpl<>("{6}{R}{R}{W}{W}"), new IsStepCondition(PhaseStep.UPKEEP), null)); + this.addAbility(new ActivateIfConditionActivatedAbility( + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(false, false), + new ManaCostsImpl<>("{6}{R}{R}{W}{W}"), IsStepCondition.getMyUpkeep() + )); } private FiremaneAngel(final FiremaneAngel card) { @@ -61,8 +61,7 @@ public final class FiremaneAngel extends CardImpl { } } -enum SourceOnBattlefieldOrGraveyardCondition implements Condition { - +enum FiremaneAngelCondition implements Condition { instance; @Override @@ -73,7 +72,6 @@ enum SourceOnBattlefieldOrGraveyardCondition implements Condition { @Override public String toString() { - return "if {this} is in your graveyard or on the battlefield"; + return "{this} is in your graveyard or on the battlefield"; } - } diff --git a/Mage.Sets/src/mage/cards/f/FirestormPhoenix.java b/Mage.Sets/src/mage/cards/f/FirestormPhoenix.java index 18608d7ade1..ab89248d8f7 100644 --- a/Mage.Sets/src/mage/cards/f/FirestormPhoenix.java +++ b/Mage.Sets/src/mage/cards/f/FirestormPhoenix.java @@ -58,7 +58,7 @@ class FirestormPhoenixEffect extends ReplacementEffectImpl { FirestormPhoenixEffect() { super(Duration.Custom, Outcome.ReturnToHand); - staticText = "If {this} would die, return {this} to its owner's hand instead. " + + staticText = "If {this} would die, return it to its owner's hand instead. " + "Until that player's next turn, that player plays with that card revealed in their hand and can't play it"; } diff --git a/Mage.Sets/src/mage/cards/f/FirewakeSliver.java b/Mage.Sets/src/mage/cards/f/FirewakeSliver.java index 421eea7ad80..a6ca4f9908d 100644 --- a/Mage.Sets/src/mage/cards/f/FirewakeSliver.java +++ b/Mage.Sets/src/mage/cards/f/FirewakeSliver.java @@ -18,6 +18,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -47,7 +48,7 @@ public final class FirewakeSliver extends CardImpl { // All Slivers have "{1}, Sacrifice this permanent: Target Sliver creature gets +2/+2 until end of turn." Ability gainedAbility = new SimpleActivatedAbility(new BoostTargetEffect(2, 2, Duration.EndOfTurn), new GenericManaCost(1)); gainedAbility.addCost(new SacrificeSourceCost()); - gainedAbility.addTarget(new TargetCreaturePermanent(targetSliverFilter)); + gainedAbility.addTarget(new TargetPermanent(targetSliverFilter)); this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( gainedAbility, Duration.WhileOnBattlefield, filter, "All Slivers have \"{1}, Sacrifice this permanent: Target Sliver creature gets +2/+2 until end of turn.\""))); diff --git a/Mage.Sets/src/mage/cards/f/FirjasRetribution.java b/Mage.Sets/src/mage/cards/f/FirjasRetribution.java index 5b9fde1d43c..a221f46eb32 100644 --- a/Mage.Sets/src/mage/cards/f/FirjasRetribution.java +++ b/Mage.Sets/src/mage/cards/f/FirjasRetribution.java @@ -23,6 +23,7 @@ import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.AngelWarriorVigilanceToken; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -53,7 +54,7 @@ public final class FirjasRetribution extends CardImpl { // II — Until end of turn, Angels you control gain "{T}: Destroy target creature with less power than this creature." Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new GainAbilityAllEffect( ability, Duration.EndOfTurn, filter2 ).setText("until end of turn, Angels you control gain \"{T}: Destroy target creature with power less than this creature's power.\"")); diff --git a/Mage.Sets/src/mage/cards/f/FirkraagCunningInstigator.java b/Mage.Sets/src/mage/cards/f/FirkraagCunningInstigator.java index 3ca9c31a2d8..df63aa6c02e 100644 --- a/Mage.Sets/src/mage/cards/f/FirkraagCunningInstigator.java +++ b/Mage.Sets/src/mage/cards/f/FirkraagCunningInstigator.java @@ -2,7 +2,7 @@ package mage.cards.f; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.AttacksPlayerWithCreaturesTriggeredAbility; import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.combat.GoadTargetEffect; @@ -14,14 +14,13 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.counters.CounterType; import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicate; -import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; -import mage.game.events.DefenderAttackedEvent; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; import java.util.UUID; @@ -30,10 +29,11 @@ import java.util.UUID; */ public final class FirkraagCunningInstigator extends CardImpl { - private static final FilterPermanent filter = new FilterCreaturePermanent(); + private static final FilterPermanent filterHadToAttack = new FilterCreaturePermanent(); + private static final FilterPermanent filterDragons = new FilterControlledPermanent(SubType.DRAGON, "Dragons you control"); static { - filter.add(FirkraagCunningInstigatorPredicate.instance); + filterHadToAttack.add(FirkraagCunningInstigatorPredicate.instance); } public FirkraagCunningInstigator(UUID ownerId, CardSetInfo setInfo) { @@ -51,13 +51,16 @@ public final class FirkraagCunningInstigator extends CardImpl { this.addAbility(HasteAbility.getInstance()); // Whenever one or more Dragons you control attack an opponent, goad target creature that player controls. - this.addAbility(new FirkraagCunningInstigatorTriggeredAbility()); + Ability abilityGoad = new AttacksPlayerWithCreaturesTriggeredAbility(new GoadTargetEffect(), 1, filterDragons, SetTargetPointer.PLAYER, true); + abilityGoad.addTarget(new TargetPermanent(new FilterCreaturePermanent("target creature that player controls"))); + abilityGoad.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); + this.addAbility(abilityGoad); // Whenever a creature deals combat damage to one of your opponents, if that creature had to attack this combat, you put a +1/+1 counter on Firkraag, Cunning Instigator and you draw a card. Ability ability = new DealsDamageToAPlayerAllTriggeredAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance()) .setText("you put a +1/+1 counter on {this}"), - filter, false, SetTargetPointer.NONE, + filterHadToAttack, false, SetTargetPointer.NONE, true, false, TargetController.OPPONENT ).setTriggerPhrase("Whenever a creature deals combat damage to one of your opponents, " + "if that creature had to attack this combat, "); @@ -88,48 +91,3 @@ enum FirkraagCunningInstigatorPredicate implements Predicate { .anyMatch(input.getId()::equals); } } - -class FirkraagCunningInstigatorTriggeredAbility extends TriggeredAbilityImpl { - - FirkraagCunningInstigatorTriggeredAbility() { - super(Zone.BATTLEFIELD, new GoadTargetEffect()); - } - - private FirkraagCunningInstigatorTriggeredAbility(final FirkraagCunningInstigatorTriggeredAbility ability) { - super(ability); - } - - @Override - public FirkraagCunningInstigatorTriggeredAbility copy() { - return new FirkraagCunningInstigatorTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DEFENDER_ATTACKED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (this.isControlledBy(event.getPlayerId()) - && game.getOpponents(this.getControllerId()).contains(event.getTargetId()) - && ((DefenderAttackedEvent) event) - .getAttackers(game) - .stream() - .anyMatch(permanent -> permanent.hasSubtype(SubType.DRAGON, game))) { - this.getTargets().clear(); - FilterPermanent filter = new FilterCreaturePermanent( - "creature controlled by " + game.getPlayer(event.getTargetId()).getName() - ); - filter.add(new ControllerIdPredicate(event.getTargetId())); - this.addTarget(new TargetPermanent(filter)); - return true; - } - return false; - } - - @Override - public String getRule() { - return "Whenever one or more Dragons you control attack an opponent, goad target creature that player controls."; - } -} diff --git a/Mage.Sets/src/mage/cards/f/FirstResponse.java b/Mage.Sets/src/mage/cards/f/FirstResponse.java index 593558d1870..90dc5d591dd 100644 --- a/Mage.Sets/src/mage/cards/f/FirstResponse.java +++ b/Mage.Sets/src/mage/cards/f/FirstResponse.java @@ -1,19 +1,17 @@ - package mage.cards.f; -import java.util.UUID; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.common.LiveLostLastTurnCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TargetController; import mage.game.permanent.token.SoldierToken; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class FirstResponse extends CardImpl { @@ -22,10 +20,9 @@ public final class FirstResponse extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); // At the beginning of each upkeep, if you lost life last turn, create a 1/1 white Soldier creature token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(TargetController.ANY, new CreateTokenEffect(new SoldierToken()), false), - LiveLostLastTurnCondition.instance, - "At the beginning of each upkeep, if you lost life last turn, create a 1/1 white Soldier creature token.")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.ANY, new CreateTokenEffect(new SoldierToken()), false + ).withInterveningIf(LiveLostLastTurnCondition.instance)); } private FirstResponse(final FirstResponse card) { diff --git a/Mage.Sets/src/mage/cards/f/FlameWreathedPhoenix.java b/Mage.Sets/src/mage/cards/f/FlameWreathedPhoenix.java index 7dc266963c0..869683d3ddc 100644 --- a/Mage.Sets/src/mage/cards/f/FlameWreathedPhoenix.java +++ b/Mage.Sets/src/mage/cards/f/FlameWreathedPhoenix.java @@ -1,14 +1,10 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.TributeNotPaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.ReturnToHandSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FlyingAbility; @@ -17,17 +13,18 @@ import mage.abilities.keyword.TributeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class FlameWreathedPhoenix extends CardImpl { public FlameWreathedPhoenix(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); this.subtype.add(SubType.PHOENIX); this.power = new MageInt(3); @@ -35,15 +32,18 @@ public final class FlameWreathedPhoenix extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); + // Tribute 2 (As this creature enters the battlefield, an opponent of your choice may put 2 +1/+1 counter on it.) this.addAbility(new TributeAbility(2)); - // When Flame-Wreathed Phoenix enters the battlefield, if tribute wasn't paid, it gains haste and "When this creature dies, return it to its owner's hand." - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield)); - Effect effect = new GainAbilitySourceEffect(new DiesSourceTriggeredAbility(new ReturnToHandSourceEffect())); - ability.addEffect(effect); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, TributeNotPaidCondition.instance, - "When {this} enters, if tribute wasn't paid, it gains haste and \"When this creature dies, return it to its owner's hand.\"")); + // When Flame-Wreathed Phoenix enters the battlefield, if tribute wasn't paid, it gains haste and "When this creature dies, return it to its owner's hand." + Ability ability = new EntersBattlefieldTriggeredAbility( + new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield).setText("it gains haste") + ).withInterveningIf(TributeNotPaidCondition.instance); + ability.addEffect(new GainAbilitySourceEffect( + new DiesSourceTriggeredAbility(new ReturnToHandSourceEffect()) + ).setText("and \"When this creature dies, return it to its owner's hand.\"")); + this.addAbility(ability); } private FlameWreathedPhoenix(final FlameWreathedPhoenix card) { diff --git a/Mage.Sets/src/mage/cards/f/FlamecacheGecko.java b/Mage.Sets/src/mage/cards/f/FlamecacheGecko.java index e1557767dfb..8b46cdf87ef 100644 --- a/Mage.Sets/src/mage/cards/f/FlamecacheGecko.java +++ b/Mage.Sets/src/mage/cards/f/FlamecacheGecko.java @@ -8,7 +8,6 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.OpponentsLostLifeCondition; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.mana.BasicManaEffect; import mage.cards.CardImpl; @@ -32,14 +31,9 @@ public final class FlamecacheGecko extends CardImpl { this.toughness = new MageInt(2); // When Flamecache Gecko enters, if an opponent lost life this turn, add {B}{R}. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility( - new BasicManaEffect(new Mana( - 0, 0, 1, 1, 0, 0, 0, 0 - )) - ), OpponentsLostLifeCondition.instance, "When {this} enters, " + - "if an opponent lost life this turn, add {B}{R}." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new BasicManaEffect(new Mana(0, 0, 1, 1, 0, 0, 0, 0)) + ).withInterveningIf(OpponentsLostLifeCondition.instance)); // {1}{R}, Discard a card: Draw a card. Ability ability = new SimpleActivatedAbility( diff --git a/Mage.Sets/src/mage/cards/f/FlamestickCourier.java b/Mage.Sets/src/mage/cards/f/FlamestickCourier.java index 7ef97f22936..620ce4cdd3a 100644 --- a/Mage.Sets/src/mage/cards/f/FlamestickCourier.java +++ b/Mage.Sets/src/mage/cards/f/FlamestickCourier.java @@ -20,6 +20,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -49,7 +50,7 @@ public final class FlamestickCourier extends CardImpl { ability.addEffect(new ConditionalContinuousEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom), SourceTappedCondition.TAPPED,"and has haste for as long as {this} remains tapped")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FlashFoliage.java b/Mage.Sets/src/mage/cards/f/FlashFoliage.java index 6730fc8a77c..a3874a07191 100644 --- a/Mage.Sets/src/mage/cards/f/FlashFoliage.java +++ b/Mage.Sets/src/mage/cards/f/FlashFoliage.java @@ -17,6 +17,7 @@ import mage.game.permanent.Permanent; import mage.game.permanent.token.SaprolingToken; import mage.game.permanent.token.Token; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -35,7 +36,7 @@ public final class FlashFoliage extends CardImpl { // Create a 1/1 green Saproling creature token that’s blocking target creature attacking you. this.getSpellAbility().addEffect(new FlashFoliageEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreatureAttackingYou())); + this.getSpellAbility().addTarget(new TargetPermanent(new FilterCreatureAttackingYou())); // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); diff --git a/Mage.Sets/src/mage/cards/f/FleetingReflection.java b/Mage.Sets/src/mage/cards/f/FleetingReflection.java index 6f0fa97ed61..406ecddfbae 100644 --- a/Mage.Sets/src/mage/cards/f/FleetingReflection.java +++ b/Mage.Sets/src/mage/cards/f/FleetingReflection.java @@ -10,12 +10,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.other.AnotherTargetPredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; import mage.util.functions.EmptyCopyApplier; import java.util.UUID; @@ -25,18 +24,14 @@ import java.util.UUID; */ public final class FleetingReflection extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other target creature"); - - static { - filter.add(new AnotherTargetPredicate(2)); - } - public FleetingReflection(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Target creature you control gains hexproof until end of turn. Untap that creature. Until end of turn, it becomes a copy of up to one other target creature. this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent().setTargetTag(1)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1, filter, false).setTargetTag(2)); + this.getSpellAbility().addTarget(new TargetPermanent( + 0, 1, StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2 + ).setTargetTag(2)); this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HexproofAbility.getInstance(), Duration.EndOfTurn)); this.getSpellAbility().addEffect(new UntapTargetEffect().setText("Untap that creature")); this.getSpellAbility().addEffect(new FleetingReflectionEffect()); diff --git a/Mage.Sets/src/mage/cards/f/FleshCarver.java b/Mage.Sets/src/mage/cards/f/FleshCarver.java index 7ba5d59fdcd..83a490fd4b2 100644 --- a/Mage.Sets/src/mage/cards/f/FleshCarver.java +++ b/Mage.Sets/src/mage/cards/f/FleshCarver.java @@ -1,7 +1,6 @@ package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; @@ -16,8 +15,8 @@ import mage.abilities.keyword.IntimidateAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.StaticFilters; @@ -26,7 +25,8 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.permanent.token.HorrorXXBlackToken; import mage.players.Player; -import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; /** * @@ -67,7 +67,6 @@ class FleshCarverAbility extends DiesSourceTriggeredAbility { public FleshCarverAbility() { super(new FleshCarverEffect(), false); - setTriggerPhrase("When Flesh Carver dies, "); } private FleshCarverAbility(final FleshCarverAbility ability) { diff --git a/Mage.Sets/src/mage/cards/f/Fleshformer.java b/Mage.Sets/src/mage/cards/f/Fleshformer.java index 0f3ec0e2994..5593c572276 100644 --- a/Mage.Sets/src/mage/cards/f/Fleshformer.java +++ b/Mage.Sets/src/mage/cards/f/Fleshformer.java @@ -5,18 +5,15 @@ import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.abilities.keyword.FearAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -35,17 +32,15 @@ public final class Fleshformer extends CardImpl { this.toughness = new MageInt(2); // {W}{U}{B}{R}{G}: Fleshformer gets +2/+2 and gains fear until end of turn. Target creature gets -2/-2 until end of turn. Activate this ability only during your turn. - Effect effect = new BoostSourceEffect(2, 2, Duration.EndOfTurn); - effect.setText("{this} gets +2/+2"); - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{W}{U}{B}{R}{G}"), MyTurnCondition.instance); - effect = new GainAbilitySourceEffect(FearAbility.getInstance(), Duration.EndOfTurn); - effect.setText("and gains fear until end of turn"); - ability.addEffect(effect); + Ability ability = new ActivateIfConditionActivatedAbility( + new BoostSourceEffect(2, 2, Duration.EndOfTurn) + .setText("{this} gets +2/+2"), + new ManaCostsImpl<>("{W}{U}{B}{R}{G}"), MyTurnCondition.instance + ); + ability.addEffect(new GainAbilitySourceEffect(FearAbility.getInstance(), Duration.EndOfTurn).setText("and gains fear until end of turn")); ability.addEffect(new BoostTargetEffect(-2, -2, Duration.EndOfTurn)); ability.addTarget(new TargetCreaturePermanent()); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); - } private Fleshformer(final Fleshformer card) { diff --git a/Mage.Sets/src/mage/cards/f/FleshlessGladiator.java b/Mage.Sets/src/mage/cards/f/FleshlessGladiator.java index 4677f02dad8..7a909084c51 100644 --- a/Mage.Sets/src/mage/cards/f/FleshlessGladiator.java +++ b/Mage.Sets/src/mage/cards/f/FleshlessGladiator.java @@ -4,7 +4,7 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.common.CorruptedCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; import mage.cards.CardImpl; @@ -30,7 +30,7 @@ public final class FleshlessGladiator extends CardImpl { this.toughness = new MageInt(2); // Corrupted -- {2}{B}: Return Fleshless Gladiator from your graveyard to the battlefield tapped. You lose 1 life. Activate only if an opponent has three or more poison counters. - Ability ability = new ConditionalActivatedAbility( + Ability ability = new ActivateIfConditionActivatedAbility( Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(true, false), new ManaCostsImpl<>("{2}{B}"), CorruptedCondition.instance ); diff --git a/Mage.Sets/src/mage/cards/f/FleshpulperGiant.java b/Mage.Sets/src/mage/cards/f/FleshpulperGiant.java index ae1354019a3..a18ce8ee871 100644 --- a/Mage.Sets/src/mage/cards/f/FleshpulperGiant.java +++ b/Mage.Sets/src/mage/cards/f/FleshpulperGiant.java @@ -13,6 +13,7 @@ import mage.constants.SubType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ToughnessPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -36,7 +37,7 @@ public final class FleshpulperGiant extends CardImpl { // When Fleshpulper Giant enters the battlefield, you may destroy target creature with toughness 2 or less. Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), true); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/Flood.java b/Mage.Sets/src/mage/cards/f/Flood.java index da0062f8b25..9493e460098 100644 --- a/Mage.Sets/src/mage/cards/f/Flood.java +++ b/Mage.Sets/src/mage/cards/f/Flood.java @@ -14,6 +14,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -33,7 +34,7 @@ public final class Flood extends CardImpl { // {U}{U}: Tap target creature without flying. Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new ManaCostsImpl<>("{U}{U}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FoeRazerRegent.java b/Mage.Sets/src/mage/cards/f/FoeRazerRegent.java index 1f2b30ccf9d..1976254a805 100644 --- a/Mage.Sets/src/mage/cards/f/FoeRazerRegent.java +++ b/Mage.Sets/src/mage/cards/f/FoeRazerRegent.java @@ -20,11 +20,14 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author LevelX2 */ @@ -41,7 +44,7 @@ public final class FoeRazerRegent extends CardImpl { // When Foe-Razer Regent enters the battlefield, you may have it fight target creature you don't control. Ability ability = new EntersBattlefieldTriggeredAbility(new FightTargetSourceEffect().setText("you may have it fight target creature you don't control"), true); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.addAbility(ability); // Whenever a creature you control fights, put two +1/+1 counters on it at the beginning of the next end step. diff --git a/Mage.Sets/src/mage/cards/f/Fogwalker.java b/Mage.Sets/src/mage/cards/f/Fogwalker.java index 2a89e279241..99ef23892b5 100644 --- a/Mage.Sets/src/mage/cards/f/Fogwalker.java +++ b/Mage.Sets/src/mage/cards/f/Fogwalker.java @@ -10,10 +10,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -30,7 +33,7 @@ public final class Fogwalker extends CardImpl { this.addAbility(new SkulkAbility()); // When Fogwalker enters the battlefield, target creature an opponent controls doesn't untap during its controller's next untap step. EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DontUntapInControllersNextUntapStepTargetEffect()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FollowedFootsteps.java b/Mage.Sets/src/mage/cards/f/FollowedFootsteps.java index f74dfae2f0e..7dba248429a 100644 --- a/Mage.Sets/src/mage/cards/f/FollowedFootsteps.java +++ b/Mage.Sets/src/mage/cards/f/FollowedFootsteps.java @@ -1,29 +1,27 @@ package mage.cards.f; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.abilities.keyword.EnchantAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author LoneFox - * */ public final class FollowedFootsteps extends CardImpl { @@ -35,11 +33,10 @@ public final class FollowedFootsteps extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Copy)); - Ability ability = new EnchantAbility(auraTarget); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget)); // At the beginning of your upkeep, create a token that's a copy of enchanted creature. - this.addAbility(new OnEventTriggeredAbility(GameEvent.EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", new FollowedFootstepsEffect(), false)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new FollowedFootstepsEffect())); } private FollowedFootsteps(final FollowedFootsteps card) { diff --git a/Mage.Sets/src/mage/cards/f/FoodChain.java b/Mage.Sets/src/mage/cards/f/FoodChain.java index b7d07f21a25..70e19426fdd 100644 --- a/Mage.Sets/src/mage/cards/f/FoodChain.java +++ b/Mage.Sets/src/mage/cards/f/FoodChain.java @@ -15,12 +15,11 @@ import mage.cards.CardSetInfo; import mage.choices.ChoiceColor; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; import java.util.ArrayList; import java.util.List; @@ -35,9 +34,10 @@ public final class FoodChain extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); // Exile a creature you control: Add X mana of any one color, where X is the exiled creature's converted mana cost plus one. Spend this mana only to cast creature spells. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new FoodChainManaEffect(), - new ExileTargetCost(new TargetControlledCreaturePermanent(StaticFilters.FILTER_CONTROLLED_A_CREATURE))); - this.addAbility(ability); + this.addAbility(new SimpleManaAbility( + new FoodChainManaEffect(), + new ExileTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_A_CREATURE)) + )); } private FoodChain(final FoodChain card) { diff --git a/Mage.Sets/src/mage/cards/f/FoolsTome.java b/Mage.Sets/src/mage/cards/f/FoolsTome.java index f0af4a58904..044d905ebd7 100644 --- a/Mage.Sets/src/mage/cards/f/FoolsTome.java +++ b/Mage.Sets/src/mage/cards/f/FoolsTome.java @@ -1,30 +1,29 @@ - package mage.cards.f; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.common.HellbentCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; + +import java.util.UUID; /** - * * @author LoneFox */ public final class FoolsTome extends CardImpl { public FoolsTome(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // {2}, {tap}: Draw a card. Activate this ability only if you have no cards in hand. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), - new ManaCostsImpl<>("{2}"), HellbentCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DrawCardSourceControllerEffect(1), new GenericManaCost(2), HellbentCondition.instance + ); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/ForcePull.java b/Mage.Sets/src/mage/cards/f/ForcePull.java index ec89792c393..4a9b00a41cb 100644 --- a/Mage.Sets/src/mage/cards/f/ForcePull.java +++ b/Mage.Sets/src/mage/cards/f/ForcePull.java @@ -10,6 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class ForcePull extends CardImpl { // Destroy targer creature with spaceflight. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Scry 3 this.getSpellAbility().addEffect(new ScryEffect(3)); diff --git a/Mage.Sets/src/mage/cards/f/Forcefield.java b/Mage.Sets/src/mage/cards/f/Forcefield.java index 598a204c83b..8ef14e236d8 100644 --- a/Mage.Sets/src/mage/cards/f/Forcefield.java +++ b/Mage.Sets/src/mage/cards/f/Forcefield.java @@ -1,6 +1,5 @@ package mage.cards.f; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -13,7 +12,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.UnblockedPredicate; import mage.game.Game; @@ -21,11 +19,12 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author emerald000 */ public final class Forcefield extends CardImpl { @@ -74,7 +73,7 @@ class ForcefieldEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { - Target target = new TargetCreaturePermanent(1, 1, filter, true); + Target target = new TargetPermanent(1, 1, filter, true); if (controller.choose(Outcome.PreventDamage, target, source, game)) { Permanent creature = game.getPermanent(target.getFirstTarget()); if (creature != null) { diff --git a/Mage.Sets/src/mage/cards/f/ForebodingSteamboat.java b/Mage.Sets/src/mage/cards/f/ForebodingSteamboat.java new file mode 100644 index 00000000000..cf4068fceeb --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/ForebodingSteamboat.java @@ -0,0 +1,173 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; +import mage.abilities.effects.keyword.InvestigateEffect; +import mage.abilities.keyword.CrewAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.ExileZone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInExile; +import mage.target.targetpointer.FixedTargets; +import mage.util.CardUtil; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class ForebodingSteamboat extends CardImpl { + + public ForebodingSteamboat(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}{B}{B}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(5); + this.toughness = new MageInt(7); + + // When Foreboding Steamboat enters, each player chooses two nontoken, non-Vehicle creatures they control. Exile them until Foreboding Steamboat leaves the battlefield. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ForebodingSteamboatExileEffect())); + + // Whenever Foreboding Steamboat attacks, put a card exiled with it into its owner's graveyard. If you do, investigate. + this.addAbility(new AttacksTriggeredAbility(new ForebodingSteamboatInvestigateEffect())); + + // Crew 2 + this.addAbility(new CrewAbility(2)); + } + + private ForebodingSteamboat(final ForebodingSteamboat card) { + super(card); + } + + @Override + public ForebodingSteamboat copy() { + return new ForebodingSteamboat(this); + } +} + +class ForebodingSteamboatExileEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("nontoken, non-Vehicle creatures you control"); + + static { + filter.add(TokenPredicate.FALSE); + filter.add(Predicates.not(SubType.VEHICLE.getPredicate())); + } + + ForebodingSteamboatExileEffect() { + super(Outcome.Benefit); + staticText = "each player chooses two nontoken, non-Vehicle creatures they control. " + + "Exile them until {this} leaves the battlefield"; + } + + private ForebodingSteamboatExileEffect(final ForebodingSteamboatExileEffect effect) { + super(effect); + } + + @Override + public ForebodingSteamboatExileEffect copy() { + return new ForebodingSteamboatExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (source.getSourcePermanentIfItStillExists(game) == null) { + // if source permanent is already gone then nothing gets exiled in the first place + return false; + } + Set toExile = new HashSet<>(); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player == null) { + continue; + } + List permanents = game.getBattlefield().getActivePermanents(filter, playerId, source, game); + if (permanents.size() <= 2) { + toExile.addAll(permanents); + continue; + } + TargetPermanent target = new TargetPermanent(2, filter); + target.withNotTarget(true); + player.choose(outcome, target, source, game); + toExile.addAll( + target.getTargets() + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()) + ); + } + if (toExile.isEmpty()) { + return false; + } + return !toExile.isEmpty() + && new ExileUntilSourceLeavesEffect() + .setTargetPointer(new FixedTargets(toExile, game)) + .apply(game, source); + } +} + +class ForebodingSteamboatInvestigateEffect extends OneShotEffect { + + ForebodingSteamboatInvestigateEffect() { + super(Outcome.Benefit); + staticText = "put a card exiled with it into its owner's graveyard. If you do, investigate"; + } + + private ForebodingSteamboatInvestigateEffect(final ForebodingSteamboatInvestigateEffect effect) { + super(effect); + } + + @Override + public ForebodingSteamboatInvestigateEffect copy() { + return new ForebodingSteamboatInvestigateEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)); + if (player == null || exileZone == null) { + return false; + } + Card card; + switch (exileZone.size()) { + case 0: + return false; + case 1: + card = exileZone.getRandom(game); + break; + default: + TargetCard target = new TargetCardInExile(StaticFilters.FILTER_CARD, exileZone.getId()); + target.withChooseHint("to put into its owner's graveyard"); + player.choose(outcome, target, source, game); + card = game.getCard(target.getFirstTarget()); + } + if (card == null) { + return false; + } + player.moveCards(card, Zone.GRAVEYARD, source, game); + InvestigateEffect.doInvestigate(player.getId(), 1, game, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/f/ForerunnerOfSlaughter.java b/Mage.Sets/src/mage/cards/f/ForerunnerOfSlaughter.java index 4fa8e818dcb..a14c3497683 100644 --- a/Mage.Sets/src/mage/cards/f/ForerunnerOfSlaughter.java +++ b/Mage.Sets/src/mage/cards/f/ForerunnerOfSlaughter.java @@ -17,6 +17,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorlessPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -43,7 +44,7 @@ public final class ForerunnerOfSlaughter extends CardImpl { // {1}: Target colorless creature gains haste until end of turn. Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn), new GenericManaCost(1)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/ForgestokerDragon.java b/Mage.Sets/src/mage/cards/f/ForgestokerDragon.java index a9250517cca..30881f1df2f 100644 --- a/Mage.Sets/src/mage/cards/f/ForgestokerDragon.java +++ b/Mage.Sets/src/mage/cards/f/ForgestokerDragon.java @@ -1,32 +1,29 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.SourceAttackingCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.combat.CantBlockTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ForgestokerDragon extends CardImpl { public ForgestokerDragon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}{R}"); this.subtype.add(SubType.DRAGON); this.power = new MageInt(5); @@ -34,14 +31,15 @@ public final class ForgestokerDragon extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - // {1}{R}: Forgestoker Dragon deals 1 damage to target creature. That creature can't block this combat. Activate this ability only if Forgestoker Dragon is attacking. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new ManaCostsImpl<>("{1}{R}"), SourceAttackingCondition.instance); - ability.addTarget(new TargetCreaturePermanent()); - Effect effect = new CantBlockTargetEffect(Duration.EndOfCombat); - effect.setText("That creature can't block this combat"); - ability.addEffect(effect); - this.addAbility(ability); + // {1}{R}: Forgestoker Dragon deals 1 damage to target creature. That creature can't block this combat. Activate this ability only if Forgestoker Dragon is attacking. + Ability ability = new ActivateIfConditionActivatedAbility( + new DamageTargetEffect(1), new ManaCostsImpl<>("{1}{R}"), SourceAttackingCondition.instance + ); + ability.addEffect(new CantBlockTargetEffect(Duration.EndOfCombat) + .setText("That creature can't block this combat")); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); } private ForgestokerDragon(final ForgestokerDragon card) { diff --git a/Mage.Sets/src/mage/cards/f/ForgottenAncient.java b/Mage.Sets/src/mage/cards/f/ForgottenAncient.java index 748b0db0823..6256a3ffe3c 100644 --- a/Mage.Sets/src/mage/cards/f/ForgottenAncient.java +++ b/Mage.Sets/src/mage/cards/f/ForgottenAncient.java @@ -2,22 +2,24 @@ package mage.cards.f; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SpellCastAllTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.ArrayList; import java.util.List; @@ -35,9 +37,9 @@ public final class ForgottenAncient extends CardImpl { this.toughness = new MageInt(3); // Whenever a player casts a spell, you may put a +1/+1 counter on Forgotten Ancient. - Effect effect = new AddCountersSourceEffect(CounterType.P1P1.createInstance()); - Ability ability = new SpellCastAllTriggeredAbility(effect, true); - this.addAbility(ability); + this.addAbility(new SpellCastAllTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true + )); // At the beginning of your upkeep, you may move any number of +1/+1 counters from Forgotten Ancient onto other creatures. this.addAbility(new BeginningOfUpkeepTriggeredAbility(new ForgottenAncientEffect(), true)); @@ -56,7 +58,7 @@ public final class ForgottenAncient extends CardImpl { class ForgottenAncientEffect extends OneShotEffect { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); + private static final FilterPermanent filter = new FilterCreaturePermanent("another creature"); static { filter.add(AnotherPredicate.instance); @@ -98,7 +100,7 @@ class ForgottenAncientEffect extends OneShotEffect { List counterMovements = new ArrayList<>(); do { - Target target = new TargetCreaturePermanent(1, 1, filter, true); + Target target = new TargetPermanent(1, 1, filter, true); if (!target.canChoose(controller.getId(), source, game)) { break; } diff --git a/Mage.Sets/src/mage/cards/f/FoundryHornet.java b/Mage.Sets/src/mage/cards/f/FoundryHornet.java index df6e2b9cccf..2ee71b649b2 100644 --- a/Mage.Sets/src/mage/cards/f/FoundryHornet.java +++ b/Mage.Sets/src/mage/cards/f/FoundryHornet.java @@ -1,28 +1,36 @@ package mage.cards.f; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class FoundryHornet extends CardImpl { - private static final String rule = "When {this} enters, if you control a creature with a +1/+1 counter on it, creatures your opponents control get -1/-1 until end of turn."; + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("you control a creature with a +1/+1 counter on it"); + + static { + filter.add(CounterType.P1P1.getPredicate()); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); public FoundryHornet(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); @@ -35,8 +43,10 @@ public final class FoundryHornet extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Foundry Hornet enters the battlefield, if you control a creature with a +1/+1 counter on it, creatures your opponents control get -1/-1 until end of turn. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new BoostAllEffect(-1, -1, Duration.EndOfTurn, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, false), false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new PermanentsOnTheBattlefieldCondition(StaticFilters.FILTER_A_CREATURE_P1P1), rule)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new BoostAllEffect( + -1, -1, Duration.EndOfTurn, + StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, false + ), false).withInterveningIf(condition)); } private FoundryHornet(final FoundryHornet card) { diff --git a/Mage.Sets/src/mage/cards/f/FowlStrike.java b/Mage.Sets/src/mage/cards/f/FowlStrike.java index 92ae669dcb9..ce423d2a787 100644 --- a/Mage.Sets/src/mage/cards/f/FowlStrike.java +++ b/Mage.Sets/src/mage/cards/f/FowlStrike.java @@ -9,6 +9,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -29,7 +30,7 @@ public final class FowlStrike extends CardImpl { // Destroy target creature with flying. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Reinforce 2--{2}{G} this.addAbility(new ReinforceAbility(2, new ManaCostsImpl<>("{2}{G}"))); diff --git a/Mage.Sets/src/mage/cards/f/FracturedPowerstone.java b/Mage.Sets/src/mage/cards/f/FracturedPowerstone.java index 844b5135367..33882c5b5c8 100644 --- a/Mage.Sets/src/mage/cards/f/FracturedPowerstone.java +++ b/Mage.Sets/src/mage/cards/f/FracturedPowerstone.java @@ -46,7 +46,7 @@ class FracturedPowerstoneEffect extends OneShotEffect { FracturedPowerstoneEffect() { super(Outcome.Benefit); - staticText = "Roll the planar"; + staticText = "Roll the planar die"; } private FracturedPowerstoneEffect(final FracturedPowerstoneEffect effect) { diff --git a/Mage.Sets/src/mage/cards/f/FreeRangeChicken.java b/Mage.Sets/src/mage/cards/f/FreeRangeChicken.java index 1895348acc8..d2cd14ad8d3 100644 --- a/Mage.Sets/src/mage/cards/f/FreeRangeChicken.java +++ b/Mage.Sets/src/mage/cards/f/FreeRangeChicken.java @@ -49,7 +49,7 @@ class FreeRangeChickenEffect extends OneShotEffect { FreeRangeChickenEffect() { super(Outcome.BoostCreature); - this.staticText = "Roll two six-sided dice. If both results are the same, Free-Range Chicken gets +X/+X until end of turn, where X is that result. If the total of those results is equal to any other total you have rolled this turn for Free-Range Chicken, sacrifice it"; + this.staticText = "Roll two six-sided dice. If both results are the same, {this} gets +X/+X until end of turn, where X is that result. If the total of those results is equal to any other total you have rolled this turn for {this}, sacrifice it"; } private FreeRangeChickenEffect(final FreeRangeChickenEffect effect) { diff --git a/Mage.Sets/src/mage/cards/f/FreewindEquenaut.java b/Mage.Sets/src/mage/cards/f/FreewindEquenaut.java index a656674ee8e..1d68fd6e959 100644 --- a/Mage.Sets/src/mage/cards/f/FreewindEquenaut.java +++ b/Mage.Sets/src/mage/cards/f/FreewindEquenaut.java @@ -18,6 +18,7 @@ import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterAttackingOrBlockingCreature; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class FreewindEquenaut extends CardImpl { SimpleActivatedAbility ability = new SimpleActivatedAbility( new DamageTargetEffect(2), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(new FilterAttackingOrBlockingCreature())); + ability.addTarget(new TargetPermanent(new FilterAttackingOrBlockingCreature())); this.addAbility(new SimpleStaticAbility( new ConditionalContinuousEffect( new GainAbilitySourceEffect(ability, Duration.WhileOnBattlefield), diff --git a/Mage.Sets/src/mage/cards/f/FriendlyRivalry.java b/Mage.Sets/src/mage/cards/f/FriendlyRivalry.java index 892eed11554..c9748da9aaf 100644 --- a/Mage.Sets/src/mage/cards/f/FriendlyRivalry.java +++ b/Mage.Sets/src/mage/cards/f/FriendlyRivalry.java @@ -7,13 +7,14 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SuperType; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.other.AnotherTargetPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; import java.util.ArrayList; import java.util.List; @@ -25,7 +26,7 @@ import java.util.UUID; */ public final class FriendlyRivalry extends CardImpl { - private static final FilterControlledCreaturePermanent filter2 = new FilterControlledCreaturePermanent("other target legendary creature you control"); + private static final FilterPermanent filter2 = new FilterControlledCreaturePermanent("other target legendary creature you control"); static { filter2.add(new AnotherTargetPredicate(2)); @@ -37,15 +38,9 @@ public final class FriendlyRivalry extends CardImpl { // Target creature you control and up to one other target legendary creature you control each deal damage equal to their power to target creature you don't control. this.getSpellAbility().addEffect(new FriendlyRivalryEffect()); - - TargetControlledCreaturePermanent target1 = new TargetControlledCreaturePermanent(); - this.getSpellAbility().addTarget(target1.setTargetTag(1).withChooseHint("to deal damage")); - - TargetControlledCreaturePermanent target2 = new TargetControlledCreaturePermanent(0, 1, filter2, false); - this.getSpellAbility().addTarget(target2.setTargetTag(2).withChooseHint("to deal damage")); - - TargetCreaturePermanent target3 = new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL); - this.getSpellAbility().addTarget(target3.setTargetTag(3).withChooseHint("to take damage")); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent().setTargetTag(1).withChooseHint("to deal damage")); + this.getSpellAbility().addTarget(new TargetPermanent(0, 1, filter2).setTargetTag(2).withChooseHint("to deal damage")); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL).setTargetTag(3).withChooseHint("to take damage")); } private FriendlyRivalry(final FriendlyRivalry card) { diff --git a/Mage.Sets/src/mage/cards/f/FrightshroudCourier.java b/Mage.Sets/src/mage/cards/f/FrightshroudCourier.java index a19bf49df6a..87c5824ffbd 100644 --- a/Mage.Sets/src/mage/cards/f/FrightshroudCourier.java +++ b/Mage.Sets/src/mage/cards/f/FrightshroudCourier.java @@ -20,6 +20,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -49,7 +50,7 @@ public final class FrightshroudCourier extends CardImpl { ability.addEffect(new ConditionalContinuousEffect(new GainAbilityTargetEffect(FearAbility.getInstance(), Duration.Custom), SourceTappedCondition.TAPPED,"and has fear for as long as {this} remains tapped")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FrodoAdventurousHobbit.java b/Mage.Sets/src/mage/cards/f/FrodoAdventurousHobbit.java index 09d3789d3a9..13541c46e6e 100644 --- a/Mage.Sets/src/mage/cards/f/FrodoAdventurousHobbit.java +++ b/Mage.Sets/src/mage/cards/f/FrodoAdventurousHobbit.java @@ -6,7 +6,6 @@ import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceIsRingBearerCondition; import mage.abilities.condition.common.YouGainedLifeCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.dynamicvalue.common.ControllerGainedLifeCount; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -48,15 +47,10 @@ public final class FrodoAdventurousHobbit extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // Whenever Frodo, Adventurous Hobbit attacks, if you gained 3 or more life this turn, the Ring tempts you. Then if Frodo is your Ring-bearer and the Ring has tempted you two or more times this game, draw a card. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new TheRingTemptsYouEffect()), - condition, "Whenever {this} attacks, if you gained 3 or more life this turn, " + - "the Ring tempts you. Then if {this} is your Ring-bearer and the Ring " + - "has tempted you two or more times this game, draw a card." - ); + Ability ability = new AttacksTriggeredAbility(new TheRingTemptsYouEffect()).withInterveningIf(condition); ability.addEffect(new ConditionalOneShotEffect( - new DrawCardSourceControllerEffect(1), - FrodoAdventurousHobbitCondition.instance + new DrawCardSourceControllerEffect(1), FrodoAdventurousHobbitCondition.instance, + "Then if {this} is your Ring-bearer and the Ring has tempted you two or more times this game, draw a card." )); this.addAbility(ability.addHint(ControllerGainedLifeCount.getHint()), new PlayerGainedLifeWatcher()); } diff --git a/Mage.Sets/src/mage/cards/f/Froghemoth.java b/Mage.Sets/src/mage/cards/f/Froghemoth.java index 7d64d15ca39..d4824823731 100644 --- a/Mage.Sets/src/mage/cards/f/Froghemoth.java +++ b/Mage.Sets/src/mage/cards/f/Froghemoth.java @@ -1,20 +1,17 @@ package mage.cards.f; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.TrampleAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.abilities.keyword.TrampleAbility; -import mage.abilities.keyword.HasteAbility; -import mage.constants.CardType; import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.FilterCard; @@ -24,6 +21,11 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInGraveyard; +import mage.target.targetadjustment.DefineByTriggerTargetAdjuster; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; /** * @@ -64,6 +66,7 @@ class FroghemothTriggeredAbility extends DealsCombatDamageToAPlayerTriggeredAbil public FroghemothTriggeredAbility() { super(new FroghemothEffect(), false); + setTargetAdjuster(DefineByTriggerTargetAdjuster.instance); } private FroghemothTriggeredAbility(final FroghemothTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/f/FrontierSiege.java b/Mage.Sets/src/mage/cards/f/FrontierSiege.java index a05e0807877..47aa48ade33 100644 --- a/Mage.Sets/src/mage/cards/f/FrontierSiege.java +++ b/Mage.Sets/src/mage/cards/f/FrontierSiege.java @@ -21,10 +21,13 @@ import mage.filter.predicate.mageobject.AbilityPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author LevelX2 */ @@ -49,7 +52,7 @@ public final class FrontierSiege extends CardImpl { Ability ability = new EntersBattlefieldAllTriggeredAbility( Zone.BATTLEFIELD, new FrontierSiegeFightEffect(), filter, true, SetTargetPointer.PERMANENT ); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.addAbility(new SimpleStaticAbility(new GainAnchorWordAbilitySourceEffect(ability, ModeChoice.DRAGONS))); } diff --git a/Mage.Sets/src/mage/cards/f/FrontlineHeroism.java b/Mage.Sets/src/mage/cards/f/FrontlineHeroism.java index ae262c06221..c204d86fa78 100644 --- a/Mage.Sets/src/mage/cards/f/FrontlineHeroism.java +++ b/Mage.Sets/src/mage/cards/f/FrontlineHeroism.java @@ -1,6 +1,5 @@ package mage.cards.f; -import mage.MageItem; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; @@ -13,10 +12,9 @@ import mage.constants.Outcome; import mage.filter.FilterPermanent; import mage.filter.FilterSpell; import mage.filter.StaticFilters; -import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.MageObjectReferencePredicate; import mage.filter.predicate.other.HasOnlySingleTargetPermanentPredicate; -import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.AkroanSoldierToken; @@ -125,13 +123,7 @@ class FrontlineHeroismEffect extends OneShotEffect { break; default: FilterPermanent filter = new FilterPermanent("token to target with the copied spell"); - filter.add(Predicates.or( - permanents - .stream() - .map(MageItem::getId) - .map(PermanentIdPredicate::new) - .collect(Collectors.toSet()) - )); + filter.add(new PermanentReferenceInCollectionPredicate(permanents, game)); TargetPermanent target = new TargetPermanent(filter); target.withNotTarget(true); player.choose(outcome, target, source, game); diff --git a/Mage.Sets/src/mage/cards/f/FulfillContract.java b/Mage.Sets/src/mage/cards/f/FulfillContract.java index b311c455f03..be31b45cd96 100644 --- a/Mage.Sets/src/mage/cards/f/FulfillContract.java +++ b/Mage.Sets/src/mage/cards/f/FulfillContract.java @@ -15,6 +15,7 @@ import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; @@ -37,7 +38,7 @@ public final class FulfillContract extends CardImpl { // Destroy target creature with a bounty counter on it. If that creature is destroyed this way, you may put a +1/+1 counter on target Rogue or Hunter you control. this.getSpellAbility().addEffect(new FulfillContractEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterBountyCreature)); + this.getSpellAbility().addTarget(new TargetPermanent(filterBountyCreature)); this.getSpellAbility().addTarget(new TargetControlledPermanent(filterRogueOrHunter)); } diff --git a/Mage.Sets/src/mage/cards/f/FulgentDistraction.java b/Mage.Sets/src/mage/cards/f/FulgentDistraction.java index a4209b808e8..f0a853840ed 100644 --- a/Mage.Sets/src/mage/cards/f/FulgentDistraction.java +++ b/Mage.Sets/src/mage/cards/f/FulgentDistraction.java @@ -1,28 +1,30 @@ package mage.cards.f; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import mage.MageItem; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.abilities.keyword.EquipAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + /** - * * @author maurer.it_at_gmail.com */ public final class FulgentDistraction extends CardImpl { - public FulgentDistraction (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{W}"); - + public FulgentDistraction(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); this.getSpellAbility().addEffect(new FulgentDistractionEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent(2)); @@ -51,27 +53,30 @@ class FulgentDistractionEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for ( UUID target : getTargetPointer().getTargets(game, source) ) { - Permanent creature = game.getPermanent(target); - - List copiedAttachments = new ArrayList<>(creature.getAttachments()); - for ( UUID equipmentId : copiedAttachments ) { - Permanent equipment = game.getPermanent(equipmentId); - boolean isEquipment = false; - - for (Ability ability : equipment.getAbilities()) { - if (ability instanceof EquipAbility) { - isEquipment = true; - break; - } - } - - if (isEquipment) { - creature.removeAttachment(equipmentId, source, game); - } + List permanents = this + .getTargetPointer() + .getTargets(game, source) + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + if (permanents.isEmpty()) { + return false; + } + for (Permanent permanent : permanents) { + permanent.tap(source, game); + } + for (Permanent permanent : permanents) { + Set attachments = permanent + .getAttachments() + .stream() + .map(game::getPermanent) + .filter(attachment -> attachment.hasSubtype(SubType.EQUIPMENT, game)) + .map(MageItem::getId) + .collect(Collectors.toSet()); + for (UUID attachmentId : attachments) { + permanent.removeAttachment(attachmentId, source, game); } - - creature.tap(source, game); } return true; } diff --git a/Mage.Sets/src/mage/cards/f/Fumble.java b/Mage.Sets/src/mage/cards/f/Fumble.java index e53fb2e3d89..b0ddcaa6973 100644 --- a/Mage.Sets/src/mage/cards/f/Fumble.java +++ b/Mage.Sets/src/mage/cards/f/Fumble.java @@ -1,8 +1,5 @@ package mage.cards.f; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; @@ -14,7 +11,6 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.SubType; -import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -22,8 +18,11 @@ import mage.target.Target; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class Fumble extends CardImpl { @@ -80,11 +79,12 @@ class FumbleEffect extends OneShotEffect { } } } - + new ReturnToHandTargetEffect().apply(game, source); if (!attachments.isEmpty()) { - Target target = new TargetCreaturePermanent(1, 1, StaticFilters.FILTER_PERMANENT_CREATURE, true); + Target target = new TargetCreaturePermanent(); + target.withNotTarget(true); Permanent newCreature = null; if (player.choose(Outcome.BoostCreature, target, source, game)) { newCreature = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/f/FungusElemental.java b/Mage.Sets/src/mage/cards/f/FungusElemental.java index 19dd31405ec..3af0437c734 100644 --- a/Mage.Sets/src/mage/cards/f/FungusElemental.java +++ b/Mage.Sets/src/mage/cards/f/FungusElemental.java @@ -1,32 +1,27 @@ package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.common.SourceEnteredThisTurnCondition; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; +import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.common.FilterControlledPermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class FungusElemental extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("Forest"); - - static { - filter.add(SubType.FOREST.getPredicate()); - } + private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.FOREST, "Forest"); public FungusElemental(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); @@ -37,11 +32,9 @@ public final class FungusElemental extends CardImpl { this.toughness = new MageInt(3); // {G}, Sacrifice a Forest: Put a +2/+2 counter on Fungus Elemental. Activate this ability only if Fungus Elemental entered the battlefield this turn. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, + Ability ability = new ActivateIfConditionActivatedAbility( new AddCountersSourceEffect(CounterType.P2P2.createInstance()), - new ManaCostsImpl<>("{G}"), - SourceEnteredThisTurnCondition.DID + new ManaCostsImpl<>("{G}"), SourceEnteredThisTurnCondition.DID ); ability.addCost(new SacrificeTargetCost(filter)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/f/FunnelWebRecluse.java b/Mage.Sets/src/mage/cards/f/FunnelWebRecluse.java index 30d29cc8ed1..196b73abc90 100644 --- a/Mage.Sets/src/mage/cards/f/FunnelWebRecluse.java +++ b/Mage.Sets/src/mage/cards/f/FunnelWebRecluse.java @@ -3,12 +3,12 @@ package mage.cards.f; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.MorbidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.keyword.InvestigateEffect; import mage.abilities.hint.common.MorbidHint; import mage.abilities.keyword.ReachAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; @@ -30,12 +30,8 @@ public final class FunnelWebRecluse extends CardImpl { this.addAbility(ReachAbility.getInstance()); // Morbid — When Funnel-Web Recluse enters the battlefield, if a creature died this turn, investigate. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new InvestigateEffect()), - MorbidCondition.instance, "Morbid — When {this} enters, " + - "if a creature died this turn, investigate. (Create a colorless Clue artifact token " + - "with \"{2}, Sacrifice this artifact: Draw a card.\")" - ).addHint(MorbidHint.instance)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new InvestigateEffect()) + .withInterveningIf(MorbidCondition.instance).setAbilityWord(AbilityWord.MORBID).addHint(MorbidHint.instance)); } private FunnelWebRecluse(final FunnelWebRecluse card) { diff --git a/Mage.Sets/src/mage/cards/f/FuriousResistance.java b/Mage.Sets/src/mage/cards/f/FuriousResistance.java index f56a4387d0e..1b399b95b25 100644 --- a/Mage.Sets/src/mage/cards/f/FuriousResistance.java +++ b/Mage.Sets/src/mage/cards/f/FuriousResistance.java @@ -16,6 +16,7 @@ import mage.filter.common.FilterBlockingCreature; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -32,7 +33,7 @@ public final class FuriousResistance extends CardImpl { // Target blocking creature gets +3/+0 and gains first strike until end of turn. this.getSpellAbility().addEffect(new FuriousResistanceEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private FuriousResistance(final FuriousResistance card) { diff --git a/Mage.Sets/src/mage/cards/f/FuriousRise.java b/Mage.Sets/src/mage/cards/f/FuriousRise.java index 74e1cb4d663..76265389d70 100644 --- a/Mage.Sets/src/mage/cards/f/FuriousRise.java +++ b/Mage.Sets/src/mage/cards/f/FuriousRise.java @@ -2,17 +2,20 @@ package mage.cards.f; import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.common.FerociousCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.AsThoughEffect; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.hint.common.FerociousHint; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AsThoughEffectType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; import mage.target.targetpointer.FixedTarget; @@ -31,9 +34,8 @@ public final class FuriousRise extends CardImpl { // At the beginning of your end step, if you control a creature with power 4 or greater, exile the top card of your library. // You may play that card until you exile another card with Furious Rise. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new BeginningOfEndStepTriggeredAbility( - new FuriousRiseEffect()), FerociousCondition.instance, - "At the beginning of your end step, if you control a creature with power 4 or greater, exile the top card of your library. You may play that card until you exile another card with {this}.")); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new FuriousRiseEffect()) + .withInterveningIf(FerociousCondition.instance).addHint(FerociousHint.instance)); } private FuriousRise(final FuriousRise card) { @@ -50,7 +52,7 @@ class FuriousRiseEffect extends OneShotEffect { FuriousRiseEffect() { super(Outcome.Benefit); - this.staticText = "exile the top card of your library. You may play that card until you exile another card with Furious Rise"; + this.staticText = "exile the top card of your library. You may play that card until you exile another card with {this}"; } private FuriousRiseEffect(final FuriousRiseEffect effect) { diff --git a/Mage.Sets/src/mage/cards/f/FurnaceDragon.java b/Mage.Sets/src/mage/cards/f/FurnaceDragon.java index 7a95df32bb3..126f065c409 100644 --- a/Mage.Sets/src/mage/cards/f/FurnaceDragon.java +++ b/Mage.Sets/src/mage/cards/f/FurnaceDragon.java @@ -1,11 +1,8 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromHandSourcePermanentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ExileAllEffect; import mage.abilities.keyword.AffinityForArtifactsAbility; import mage.abilities.keyword.FlyingAbility; @@ -13,23 +10,18 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.watchers.common.CastFromHandWatcher; +import java.util.UUID; + /** - * * @author fireshoes */ public final class FurnaceDragon extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("artifacts"); - - static { - filter.add(CardType.ARTIFACT.getPredicate()); - } - public FurnaceDragon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{6}{R}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{R}{R}{R}"); this.subtype.add(SubType.DRAGON); this.power = new MageInt(5); this.toughness = new MageInt(5); @@ -41,11 +33,9 @@ public final class FurnaceDragon extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Furnace Dragon enters the battlefield, if you cast it from your hand, exile all artifacts. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ExileAllEffect(filter), false), - CastFromHandSourcePermanentCondition.instance, - "When {this} enters, if you cast it from your hand, exile all artifacts."), - new CastFromHandWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new ExileAllEffect(StaticFilters.FILTER_PERMANENT_ARTIFACTS) + ).withInterveningIf(CastFromHandSourcePermanentCondition.instance), new CastFromHandWatcher()); } private FurnaceDragon(final FurnaceDragon card) { diff --git a/Mage.Sets/src/mage/cards/f/FyndhornDruid.java b/Mage.Sets/src/mage/cards/f/FyndhornDruid.java index c02c7dbc05e..89d02d9a0f4 100644 --- a/Mage.Sets/src/mage/cards/f/FyndhornDruid.java +++ b/Mage.Sets/src/mage/cards/f/FyndhornDruid.java @@ -1,13 +1,11 @@ package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -17,22 +15,23 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.watchers.common.WasBlockedThisTurnWatcher; +import java.util.UUID; + /** - * * @author L_J */ public final class FyndhornDruid extends CardImpl { public FyndhornDruid(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.DRUID); this.power = new MageInt(2); this.toughness = new MageInt(2); // When Fyndhorn Druid dies, if it was blocked this turn, you gain 4 life. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new DiesSourceTriggeredAbility(new GainLifeEffect(4)), new SourceWasBlockedThisTurnCondition(), - "When {this} dies, if it was blocked this turn, you gain 4 life."), new WasBlockedThisTurnWatcher()); + this.addAbility(new DiesSourceTriggeredAbility(new GainLifeEffect(4)) + .withInterveningIf(FyndhornDruidCondition.instance), new WasBlockedThisTurnWatcher()); } private FyndhornDruid(final FyndhornDruid card) { @@ -45,7 +44,8 @@ public final class FyndhornDruid extends CardImpl { } } -class SourceWasBlockedThisTurnCondition implements Condition { +enum FyndhornDruidCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { @@ -53,4 +53,9 @@ class SourceWasBlockedThisTurnCondition implements Condition { WasBlockedThisTurnWatcher watcher = game.getState().getWatcher(WasBlockedThisTurnWatcher.class); return sourcePermanent != null && watcher != null && watcher.getWasBlockedThisTurnCreatures().contains(new MageObjectReference(sourcePermanent, game)); } + + @Override + public String toString() { + return "it was blocked this turn"; + } } diff --git a/Mage.Sets/src/mage/cards/g/GOTOJAIL.java b/Mage.Sets/src/mage/cards/g/GOTOJAIL.java index 7f4fa3d699f..730b6accdfe 100644 --- a/Mage.Sets/src/mage/cards/g/GOTOJAIL.java +++ b/Mage.Sets/src/mage/cards/g/GOTOJAIL.java @@ -18,12 +18,15 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.util.CardUtil; import java.util.List; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * @author spjspj */ @@ -34,7 +37,7 @@ public final class GOTOJAIL extends CardImpl { // When GO TO JAIL enters the battlefield, exile target creature an opponent controls until GO TO JAIL leaves the battlefield. Ability ability = new EntersBattlefieldTriggeredAbility(new GoToJailExileEffect()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); // At the beginning of the upkeep of the exiled card's owner, that player rolls two six-sided dice. If they roll doubles, sacrifice GO TO JAIL. diff --git a/Mage.Sets/src/mage/cards/g/GaeasCourser.java b/Mage.Sets/src/mage/cards/g/GaeasCourser.java index 977999527ad..d1a4fdde5f8 100644 --- a/Mage.Sets/src/mage/cards/g/GaeasCourser.java +++ b/Mage.Sets/src/mage/cards/g/GaeasCourser.java @@ -1,26 +1,25 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class GaeasCourser extends CardImpl { private static final Condition condition - = new CardsInControllerGraveyardCondition(3, StaticFilters.FILTER_CARD_CREATURE); + = new CardsInControllerGraveyardCondition(3, StaticFilters.FILTER_CARD_CREATURES); public GaeasCourser(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); @@ -31,11 +30,7 @@ public final class GaeasCourser extends CardImpl { this.toughness = new MageInt(5); // Whenever Gaea's Courser attacks, if there are three or more creature cards in your graveyard, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new DrawCardSourceControllerEffect(1)), - condition, - "Whenever {this} attacks, if there are three or more creature cards in your graveyard, draw a card." - )); + this.addAbility(new AttacksTriggeredAbility(new DrawCardSourceControllerEffect(1)).withInterveningIf(condition)); } private GaeasCourser(final GaeasCourser card) { diff --git a/Mage.Sets/src/mage/cards/g/GalacticWayfarer.java b/Mage.Sets/src/mage/cards/g/GalacticWayfarer.java new file mode 100644 index 00000000000..7fb6e3daa56 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GalacticWayfarer.java @@ -0,0 +1,39 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.LanderToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GalacticWayfarer extends CardImpl { + + public GalacticWayfarer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SCOUT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When this creature enters, create a Lander token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new LanderToken()))); + } + + private GalacticWayfarer(final GalacticWayfarer card) { + super(card); + } + + @Override + public GalacticWayfarer copy() { + return new GalacticWayfarer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GaladrielElvenQueen.java b/Mage.Sets/src/mage/cards/g/GaladrielElvenQueen.java index 27298b87bae..eda2d229fa6 100644 --- a/Mage.Sets/src/mage/cards/g/GaladrielElvenQueen.java +++ b/Mage.Sets/src/mage/cards/g/GaladrielElvenQueen.java @@ -3,10 +3,9 @@ package mage.cards.g; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.choices.TwoChoiceVote; @@ -35,18 +34,9 @@ public final class GaladrielElvenQueen extends CardImpl { this.toughness = new MageInt(5); // Will of the council -- At the beginning of combat on your turn, if another Elf entered the battlefield under your control this turn, starting with you, each player votes for dominion or guidance. If dominion gets more votes, the Ring tempts you, then you put a +1/+1 counter on your Ring-bearer. If guidance gets more votes or the vote is tied, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - Zone.BATTLEFIELD, - TargetController.YOU, new GaladrielElvenQueenEffect(), - false - ), - GaladrielElvenQueenCondition.instance, - "At the beginning of combat on your turn, if another Elf entered the battlefield under " - + "your control this turn, starting with you, each player votes for dominion or guidance. " - + "If dominion gets more votes, the Ring tempts you, then you put a +1/+1 counter on your " - + "Ring-bearer. If guidance gets more votes or the vote is tied, draw a card." - ).setAbilityWord(AbilityWord.WILL_OF_THE_COUNCIL), new GaladrielElvenQueenWatcher()); + this.addAbility(new BeginningOfCombatTriggeredAbility( + Zone.BATTLEFIELD, TargetController.YOU, new GaladrielElvenQueenEffect(), false + ).withInterveningIf(GaladrielElvenQueenCondition.instance).setAbilityWord(AbilityWord.WILL_OF_THE_COUNCIL), new GaladrielElvenQueenWatcher()); } private GaladrielElvenQueen(final GaladrielElvenQueen card) { @@ -73,6 +63,11 @@ enum GaladrielElvenQueenCondition implements Condition { source.getControllerId() ); } + + @Override + public String toString() { + return "another Elf entered the battlefield under your control this turn"; + } } class GaladrielElvenQueenWatcher extends Watcher { diff --git a/Mage.Sets/src/mage/cards/g/GaleWaterdeepProdigy.java b/Mage.Sets/src/mage/cards/g/GaleWaterdeepProdigy.java index c7a50440a70..67471e9fd54 100644 --- a/Mage.Sets/src/mage/cards/g/GaleWaterdeepProdigy.java +++ b/Mage.Sets/src/mage/cards/g/GaleWaterdeepProdigy.java @@ -1,21 +1,20 @@ package mage.cards.g; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.ChooseABackgroundAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.common.MayCastTargetCardEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.constants.*; import mage.filter.FilterCard; -import mage.filter.common.FilterInstantOrSorcerySpell; +import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.target.common.TargetCardInYourGraveyard; -import mage.watchers.common.CastFromHandWatcher; +import mage.target.targetadjustment.TargetAdjuster; +import mage.target.targetpointer.FirstTargetPointer; import java.util.UUID; @@ -36,7 +35,14 @@ public final class GaleWaterdeepProdigy extends CardImpl { // Whenever you cast an instant or sorcery spell from your hand, // you may cast up to one of the other type from your graveyard. // If a spell cast from your graveyard this way would be put into your graveyard, exile it instead. - this.addAbility(new GaleWaterdeepProdigyTriggeredAbility()); + Ability ability = new SpellCastControllerTriggeredAbility(Zone.BATTLEFIELD, + new MayCastTargetCardEffect(true) + .setText("you may cast up to one target card of the other type from your graveyard. If a spell cast from your graveyard this way would be put into your graveyard, exile it instead."), + StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, + false, SetTargetPointer.SPELL, Zone.HAND + ); + ability.setTargetAdjuster(GaleWaterdeepProdigyAdjuster.instance); + this.addAbility(ability); // Choose a Background this.addAbility(ChooseABackgroundAbility.getInstance()); @@ -52,7 +58,8 @@ public final class GaleWaterdeepProdigy extends CardImpl { } } -class GaleWaterdeepProdigyTriggeredAbility extends SpellCastControllerTriggeredAbility { +enum GaleWaterdeepProdigyAdjuster implements TargetAdjuster { + instance; private static final FilterCard SORCERY_FILTER = new FilterCard("a sorcery card in your graveyard"); private static final FilterCard INSTANT_FILTER = new FilterCard("an instant card in your graveyard"); @@ -61,51 +68,22 @@ class GaleWaterdeepProdigyTriggeredAbility extends SpellCastControllerTriggeredA SORCERY_FILTER.add(CardType.SORCERY.getPredicate()); INSTANT_FILTER.add(CardType.INSTANT.getPredicate()); } - - public GaleWaterdeepProdigyTriggeredAbility() { - super( - new MayCastTargetCardEffect(true) - .setText("you may cast up to one target card of the other type from your graveyard. " - + "If a spell cast from your graveyard this way would be put into your graveyard, exile it instead."), - new FilterInstantOrSorcerySpell("an instant or sorcery spell from your hand"), - false - ); - addWatcher(new CastFromHandWatcher()); - } - - private GaleWaterdeepProdigyTriggeredAbility(final GaleWaterdeepProdigyTriggeredAbility ability) { - super(ability); - } - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (!super.checkTrigger(event, game)) { - return false; - } + public void adjustTargets(Ability ability, Game game) { + UUID spellId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability); + ability.getTargets().clear(); + ability.getAllEffects().setTargetPointer(new FirstTargetPointer()); - CastFromHandWatcher watcher = game.getState().getWatcher(CastFromHandWatcher.class); - if (watcher == null || !watcher.spellWasCastFromHand(event.getSourceId())) { - return false; - } - - Spell spell = game.getState().getStack().getSpell(event.getSourceId()); + Spell spell = game.getSpellOrLKIStack(spellId); if (spell == null) { - return false; + return; } - - FilterCard filterCard; + FilterCard filter; if (spell.isSorcery(game)) { - filterCard = INSTANT_FILTER; + filter = INSTANT_FILTER; } else { - filterCard = SORCERY_FILTER; + filter = SORCERY_FILTER; } - this.getTargets().clear(); - this.getTargets().add(new TargetCardInYourGraveyard(filterCard)); - return true; + ability.addTarget(new TargetCardInYourGraveyard(0, 1, filter)); } - - @Override - public GaleWaterdeepProdigyTriggeredAbility copy() { - return new GaleWaterdeepProdigyTriggeredAbility(this); - } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/g/GalepowderMage.java b/Mage.Sets/src/mage/cards/g/GalepowderMage.java index 91b441fdc4a..ea12ca3153b 100644 --- a/Mage.Sets/src/mage/cards/g/GalepowderMage.java +++ b/Mage.Sets/src/mage/cards/g/GalepowderMage.java @@ -10,10 +10,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * @author LevelX2 */ @@ -31,7 +34,7 @@ public final class GalepowderMage extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever Galepowder Mage attacks, exile another target creature. Return that card to the battlefield under its owner's control at the beginning of the next end step. Ability ability = new AttacksTriggeredAbility(new ExileReturnBattlefieldNextEndStepTargetEffect(), false); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/Galestrike.java b/Mage.Sets/src/mage/cards/g/Galestrike.java index d148c224a39..4a050605fee 100644 --- a/Mage.Sets/src/mage/cards/g/Galestrike.java +++ b/Mage.Sets/src/mage/cards/g/Galestrike.java @@ -9,6 +9,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -28,7 +29,7 @@ public final class Galestrike extends CardImpl { // Return target tapped creature to its owner's hand. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); diff --git a/Mage.Sets/src/mage/cards/g/Gallantry.java b/Mage.Sets/src/mage/cards/g/Gallantry.java index c70f8ccc2b6..2386fe06fe1 100644 --- a/Mage.Sets/src/mage/cards/g/Gallantry.java +++ b/Mage.Sets/src/mage/cards/g/Gallantry.java @@ -10,6 +10,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.filter.common.FilterBlockingCreature; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -26,7 +27,7 @@ public final class Gallantry extends CardImpl { // Target blocking creature gets +4/+4 until end of turn. this.getSpellAbility().addEffect(new BoostTargetEffect(4, 4, Duration.EndOfTurn)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } diff --git a/Mage.Sets/src/mage/cards/g/GallifreyFallsNoMore.java b/Mage.Sets/src/mage/cards/g/GallifreyFallsNoMore.java index 239abcb8d91..f4c0f6e8631 100644 --- a/Mage.Sets/src/mage/cards/g/GallifreyFallsNoMore.java +++ b/Mage.Sets/src/mage/cards/g/GallifreyFallsNoMore.java @@ -1,11 +1,5 @@ - package mage.cards.g; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.PhaseOutTargetEffect; import mage.abilities.effects.common.replacement.DealtDamageToCreatureBySourceDies; @@ -13,40 +7,34 @@ import mage.cards.CardSetInfo; import mage.cards.SplitCard; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Outcome; import mage.constants.SpellAbilityType; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.game.Game; -import mage.game.permanent.token.CentaurToken; -import mage.players.Player; import mage.target.common.TargetControlledCreaturePermanent; import mage.watchers.common.DamagedByWatcher; +import java.util.UUID; + /** - * * @author dragonfyre23 */ public final class GallifreyFallsNoMore extends SplitCard { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("target creatures you control"); public GallifreyFallsNoMore(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{R}{R}", "{2}{W}", SpellAbilityType.SPLIT_FUSED); // Gallifrey Falls // Gallifrey Falls deals 4 damage to each creature. - getLeftHalfCard().getSpellAbility().addEffect(new DamageAllEffect(4, new FilterCreaturePermanent())); + this.getLeftHalfCard().getSpellAbility().addEffect(new DamageAllEffect(4, new FilterCreaturePermanent())); //If a creature dealt damage this way would die this turn, exile it instead. - getLeftHalfCard().getSpellAbility().addEffect(new DealtDamageToCreatureBySourceDies(getLeftHalfCard(), Duration.EndOfTurn)); - getLeftHalfCard().getSpellAbility().addWatcher(new DamagedByWatcher(false)); + this.getLeftHalfCard().getSpellAbility().addEffect(new DealtDamageToCreatureBySourceDies(this.getLeftHalfCard(), Duration.EndOfTurn)); + this.getLeftHalfCard().getSpellAbility().addWatcher(new DamagedByWatcher(false)); // No More // Any number of target creatures you control phase out. - getRightHalfCard().getSpellAbility().addEffect(new PhaseOutTargetEffect()); - getRightHalfCard().getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, false)); - + this.getRightHalfCard().getSpellAbility().addEffect(new PhaseOutTargetEffect()); + this.getRightHalfCard().getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE)); } private GallifreyFallsNoMore(final GallifreyFallsNoMore card) { diff --git a/Mage.Sets/src/mage/cards/g/GalvanicBombardment.java b/Mage.Sets/src/mage/cards/g/GalvanicBombardment.java index 408b6a76962..56987b65038 100644 --- a/Mage.Sets/src/mage/cards/g/GalvanicBombardment.java +++ b/Mage.Sets/src/mage/cards/g/GalvanicBombardment.java @@ -1,7 +1,6 @@ package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; @@ -17,8 +16,9 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes * modified tiera3 - added Hint */ @@ -29,16 +29,17 @@ public final class GalvanicBombardment extends CardImpl { static { filter.add(new NamePredicate("Galvanic Bombardment")); } + private static final Hint hint = new ValueHint( "Cards named Galvanic Bombardment in your graveyard", new GalvanicBombardmentCardsInControllerGraveyardCount(filter) ); public GalvanicBombardment(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); // Galvanic Bombardment deals X damage to target creature, where X is 2 plus the number of cards named Galvanic Bombardment in your graveyard. Effect effect = new DamageTargetEffect(new GalvanicBombardmentCardsInControllerGraveyardCount(filter)); - effect.setText("{this} deals X damage to target creature, where X is 2 plus the number of cards named {this} in your graveyard"); + effect.setText("{this} deals X damage to target creature, where X is 2 plus the number of cards named Galvanic Bombardment in your graveyard"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addHint(hint); @@ -71,8 +72,8 @@ class GalvanicBombardmentCardsInControllerGraveyardCount implements DynamicValue int amount = 0; Player controller = game.getPlayer(sourceAbility.getControllerId()); if (controller != null) { - amount += controller.getGraveyard().count(filter, sourceAbility.getControllerId(), sourceAbility, game); - } + amount += controller.getGraveyard().count(filter, sourceAbility.getControllerId(), sourceAbility, game); + } return amount + 2; } diff --git a/Mage.Sets/src/mage/cards/g/GangUp.java b/Mage.Sets/src/mage/cards/g/GangUp.java index 12bc2d46121..b63be78de94 100644 --- a/Mage.Sets/src/mage/cards/g/GangUp.java +++ b/Mage.Sets/src/mage/cards/g/GangUp.java @@ -8,11 +8,14 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.PowerTargetAdjuster; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE; + /** * @author TheElk801 */ @@ -26,7 +29,7 @@ public final class GangUp extends CardImpl { // Destroy target creature with power X or less. this.getSpellAbility().addEffect(new DestroyTargetEffect("destroy target creature with power X or less")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE)); this.getSpellAbility().setTargetAdjuster(new PowerTargetAdjuster(ComparisonType.OR_LESS)); } diff --git a/Mage.Sets/src/mage/cards/g/GarbageElementalC.java b/Mage.Sets/src/mage/cards/g/GarbageElementalC.java index d08d8e48842..618280dd5b2 100644 --- a/Mage.Sets/src/mage/cards/g/GarbageElementalC.java +++ b/Mage.Sets/src/mage/cards/g/GarbageElementalC.java @@ -2,7 +2,7 @@ package mage.cards.g; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.BattleCryAbility; import mage.cards.CardImpl; @@ -34,10 +34,7 @@ public final class GarbageElementalC extends CardImpl { this.addAbility(new BattleCryAbility()); // When Garbage Elemental enters the battlefield, roll two six-sided dice. Create a number of 1/1 red Goblin creature tokens equal to the difference between those results. - this.addAbility(new EntersBattlefieldAbility(new GarbageElementalCEffect(), - null, - "When {this} enters, roll two six-sided dice. Create a number of 1/1 red Goblin creature tokens equal to the difference between those results", - null)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GarbageElementalCEffect())); } diff --git a/Mage.Sets/src/mage/cards/g/GargantuanGorilla.java b/Mage.Sets/src/mage/cards/g/GargantuanGorilla.java index b7f752ece69..92b7d80888d 100644 --- a/Mage.Sets/src/mage/cards/g/GargantuanGorilla.java +++ b/Mage.Sets/src/mage/cards/g/GargantuanGorilla.java @@ -20,6 +20,7 @@ import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -42,7 +43,7 @@ public final class GargantuanGorilla extends CardImpl { Ability ability = new SimpleActivatedAbility(new GargantuanGorillaFightEffect(), new TapSourceCost()); FilterCreaturePermanent filter = new FilterCreaturePermanent(); filter.add(AnotherPredicate.instance); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GargosViciousWatcher.java b/Mage.Sets/src/mage/cards/g/GargosViciousWatcher.java index 40e324de19b..abbc020b067 100644 --- a/Mage.Sets/src/mage/cards/g/GargosViciousWatcher.java +++ b/Mage.Sets/src/mage/cards/g/GargosViciousWatcher.java @@ -15,7 +15,7 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.filter.FilterCard; import mage.filter.StaticFilters; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -45,10 +45,11 @@ public final class GargosViciousWatcher extends CardImpl { this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 4))); // Whenever a creature you control becomes the target of a spell, Gargos, Vicious Watcher fights up to one target creature you don't control. - TriggeredAbility ability = new BecomesTargetAnyTriggeredAbility(new FightTargetSourceEffect(), - StaticFilters.FILTER_CONTROLLED_A_CREATURE, StaticFilters.FILTER_SPELL_A, - SetTargetPointer.NONE, false); - ability.addTarget(new TargetCreaturePermanent(0, 1, StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL, false)); + TriggeredAbility ability = new BecomesTargetAnyTriggeredAbility( + new FightTargetSourceEffect(), StaticFilters.FILTER_CONTROLLED_A_CREATURE, + StaticFilters.FILTER_SPELL_A, SetTargetPointer.NONE, false + ); + ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GarzasAssassin.java b/Mage.Sets/src/mage/cards/g/GarzasAssassin.java index d2edccf206b..d57bbbb003d 100644 --- a/Mage.Sets/src/mage/cards/g/GarzasAssassin.java +++ b/Mage.Sets/src/mage/cards/g/GarzasAssassin.java @@ -19,9 +19,12 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.util.CardUtil; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author choiseul11 & L_J @@ -37,7 +40,7 @@ public final class GarzasAssassin extends CardImpl { // Sacrifice Garza's Assassin: Destroy target nonblack creature. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + ability.addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.addAbility(ability); // Recover—Pay half your life, rounded up. diff --git a/Mage.Sets/src/mage/cards/g/GateSmasher.java b/Mage.Sets/src/mage/cards/g/GateSmasher.java index add5d33975e..276d48bc734 100644 --- a/Mage.Sets/src/mage/cards/g/GateSmasher.java +++ b/Mage.Sets/src/mage/cards/g/GateSmasher.java @@ -1,12 +1,8 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.AttachableToRestrictedAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EquipAbility; @@ -15,22 +11,21 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AttachmentType; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ToughnessPredicate; -import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class GateSmasher extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature with toughness 4 or greater"); + private static final FilterPermanent filter = new FilterCreaturePermanent("creature with toughness 4 or greater"); static { filter.add(new ToughnessPredicate(ComparisonType.MORE_THAN, 3)); @@ -40,22 +35,18 @@ public final class GateSmasher extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); this.subtype.add(SubType.EQUIPMENT); - Target target = new TargetControlledCreaturePermanent(1, 1, filter, false); // Gate Smasher can be attached only to a creature with toughness 4 or greater. - this.addAbility(new AttachableToRestrictedAbility(target)); + this.addAbility(new AttachableToRestrictedAbility(new TargetPermanent(filter))); // Equipped creature gets +3/+0 and has trample. - Effect effect = new BoostEquippedEffect(3, 0); - effect.setText("Equipped creature gets +3/+0"); - Ability ability = new SimpleStaticAbility(effect); - effect = new GainAbilityAttachedEffect(TrampleAbility.getInstance(), AttachmentType.EQUIPMENT); - effect.setText("and has trample"); - ability.addEffect(effect); + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(3, 0)); + ability.addEffect(new GainAbilityAttachedEffect( + TrampleAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText("and has trample")); this.addAbility(ability); // Equip {3} - this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(3), target, false)); - + this.addAbility(new EquipAbility(3, false)); } private GateSmasher(final GateSmasher card) { diff --git a/Mage.Sets/src/mage/cards/g/GateToPhyrexia.java b/Mage.Sets/src/mage/cards/g/GateToPhyrexia.java index fee42e3c657..1ac461a9523 100644 --- a/Mage.Sets/src/mage/cards/g/GateToPhyrexia.java +++ b/Mage.Sets/src/mage/cards/g/GateToPhyrexia.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; import mage.abilities.condition.common.IsStepCondition; @@ -10,14 +8,13 @@ import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.PhaseStep; import mage.constants.Zone; import mage.filter.StaticFilters; import mage.target.common.TargetArtifactPermanent; -import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author fireshoes */ public final class GateToPhyrexia extends CardImpl { @@ -26,9 +23,10 @@ public final class GateToPhyrexia extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}{B}"); // Sacrifice a creature: Destroy target artifact. Activate this ability only during your upkeep and only once each turn. - Ability ability = new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), + Ability ability = new LimitedTimesPerTurnActivatedAbility( + Zone.BATTLEFIELD, new DestroyTargetEffect(), new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE), - 1, new IsStepCondition(PhaseStep.UPKEEP)); + 1, IsStepCondition.getMyUpkeep()); ability.addTarget(new TargetArtifactPermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GateToTheAfterlife.java b/Mage.Sets/src/mage/cards/g/GateToTheAfterlife.java index 83142c9ee67..ea008ad3afc 100644 --- a/Mage.Sets/src/mage/cards/g/GateToTheAfterlife.java +++ b/Mage.Sets/src/mage/cards/g/GateToTheAfterlife.java @@ -1,14 +1,13 @@ package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalActivatedAbility; -import mage.abilities.effects.Effect; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.abilities.effects.common.GainLifeEffect; @@ -17,38 +16,40 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.NamePredicate; -import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** * @author LevelX2 */ public final class GateToTheAfterlife extends CardImpl { + private static final Condition condition = new CardsInControllerGraveyardCondition(6, StaticFilters.FILTER_CARD_CREATURES); + public GateToTheAfterlife(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // Whenever a nontoken creature you control dies, you gain 1 life. Then you may draw a card. If you do, discard a card. - Ability ability = new DiesCreatureTriggeredAbility(new GainLifeEffect(1), false, StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN, false); - Effect effect = new DrawDiscardControllerEffect(1, 1, true); - effect.setText("Then you may draw a card. If you do, discard a card"); - ability.addEffect(effect); + Ability ability = new DiesCreatureTriggeredAbility( + new GainLifeEffect(1), false, + StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN, false + ); + ability.addEffect(new DrawDiscardControllerEffect(1, 1, true) + .setText("Then you may draw a card. If you do, discard a card")); this.addAbility(ability); // {2}, {T}, Sacrifice Gate to the Afterlife: Search your graveyard, hand, and/or library for a card named God-Pharaoh's Gift and put it onto the battlefield. If you seearch your library this way, shuffle it. Activate this ability only if there are six or more creature cards in your graveyard. - ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new GateToTheAfterlifeEffect(), new GenericManaCost(2), - new CardsInControllerGraveyardCondition(6, StaticFilters.FILTER_CARD_CREATURES) + ability = new ActivateIfConditionActivatedAbility( + new GateToTheAfterlifeEffect(), new GenericManaCost(2), condition ); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); diff --git a/Mage.Sets/src/mage/cards/g/GatebreakerRam.java b/Mage.Sets/src/mage/cards/g/GatebreakerRam.java index 8043d5e2d62..5ada9121c46 100644 --- a/Mage.Sets/src/mage/cards/g/GatebreakerRam.java +++ b/Mage.Sets/src/mage/cards/g/GatebreakerRam.java @@ -3,8 +3,7 @@ package mage.cards.g; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.condition.common.YouControlTwoOrMoreGatesCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; @@ -16,10 +15,8 @@ import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ComparisonType; import mage.constants.Duration; import mage.constants.SubType; -import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import java.util.UUID; @@ -29,16 +26,7 @@ import java.util.UUID; */ public final class GatebreakerRam extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent(); - - static { - filter.add(SubType.GATE.getPredicate()); - } - - private static final DynamicValue xValue - = new PermanentsOnBattlefieldCount(filter); - private static final Condition condition - = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.GATE)); public GatebreakerRam(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); @@ -50,17 +38,16 @@ public final class GatebreakerRam extends CardImpl { // Gatebreaker Ram gets +1/+1 for each Gate you control. this.addAbility(new SimpleStaticAbility( new BoostSourceEffect(xValue, xValue, Duration.WhileOnBattlefield) - .setText("{this} gets +1/+1 for each Gate you control.") ).addHint(GatesYouControlHint.instance)); // As long as you control two or more Gates, Gatebreaker Ram has vigilance and trample. Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( new GainAbilitySourceEffect(VigilanceAbility.getInstance()), - condition, "As long as you control two or more Gates, {this} has vigilance" + YouControlTwoOrMoreGatesCondition.instance, "As long as you control two or more Gates, {this} has vigilance" )); ability.addEffect(new ConditionalContinuousEffect( new GainAbilitySourceEffect(TrampleAbility.getInstance()), - condition, "and trample" + YouControlTwoOrMoreGatesCondition.instance, "and trample" )); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GatewatchBeacon.java b/Mage.Sets/src/mage/cards/g/GatewatchBeacon.java index d3d4f66a06c..a9b7e1b14f3 100644 --- a/Mage.Sets/src/mage/cards/g/GatewatchBeacon.java +++ b/Mage.Sets/src/mage/cards/g/GatewatchBeacon.java @@ -4,8 +4,6 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.Effects; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.mana.WhiteManaAbility; @@ -40,15 +38,10 @@ public final class GatewatchBeacon extends CardImpl { // Whenever a planeswalker you control enters, if Gatewatch Beacon has loyalty // counters on it, you may move a loyalty counter from Gatewatch Beacon onto that planeswalker. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldControlledTriggeredAbility( - Zone.BATTLEFIELD, - new GatewatchBeaconMoveCounterEffect(), - StaticFilters.FILTER_PERMANENT_PLANESWALKER, - true - ), GatewatchBeaconCondition.instance, "Whenever a planeswalker you control enters, if {this} has " + - "loyalty counters on it, you may move a loyalty counter from {this} onto that planeswalker" - )); + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, new GatewatchBeaconMoveCounterEffect(), + StaticFilters.FILTER_PERMANENT_PLANESWALKER, true + ).withInterveningIf(GatewatchBeaconCondition.instance)); } private GatewatchBeacon(final GatewatchBeacon card) { @@ -67,15 +60,12 @@ enum GatewatchBeaconCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Permanent permanent = source.getSourcePermanentIfItStillExists(game); - if (permanent == null) { - return false; - } - Effects effects = source.getEffects(); - if (effects.isEmpty()) { - return false; - } + return permanent != null && permanent.getCounters(game).getCount(CounterType.LOYALTY) > 0; + } - return permanent.getCounters(game).getCount(CounterType.LOYALTY) > 0; + @Override + public String toString() { + return "{this} has loyalty counters on it"; } } diff --git a/Mage.Sets/src/mage/cards/g/GazeOfJustice.java b/Mage.Sets/src/mage/cards/g/GazeOfJustice.java index eb15c2a56cb..988ddebe374 100644 --- a/Mage.Sets/src/mage/cards/g/GazeOfJustice.java +++ b/Mage.Sets/src/mage/cards/g/GazeOfJustice.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.costs.common.TapTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -10,20 +8,21 @@ import mage.abilities.keyword.FlashbackAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.TimingRule; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class GazeOfJustice extends CardImpl { - - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped white creatures you control"); + + private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("untapped white creatures you control"); static { filter.add(new ColorPredicate(ObjectColor.WHITE)); @@ -31,15 +30,15 @@ public final class GazeOfJustice extends CardImpl { } public GazeOfJustice(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{W}"); // As an additional cost to cast Gaze of Justice, tap three untapped white creatures you control. - this.getSpellAbility().addCost(new TapTargetCost(new TargetControlledCreaturePermanent(3, 3, filter, true))); - + this.getSpellAbility().addCost(new TapTargetCost(new TargetControlledPermanent(3, filter))); + // Exile target creature. this.getSpellAbility().addEffect(new ExileTargetEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - + // Flashback {5}{W} this.addAbility(new FlashbackAbility(this, new ManaCostsImpl<>("{5}{W}"))); } diff --git a/Mage.Sets/src/mage/cards/g/GazeOfTheGorgon.java b/Mage.Sets/src/mage/cards/g/GazeOfTheGorgon.java index 176fa182f0c..b0c2e7afb80 100644 --- a/Mage.Sets/src/mage/cards/g/GazeOfTheGorgon.java +++ b/Mage.Sets/src/mage/cards/g/GazeOfTheGorgon.java @@ -102,7 +102,7 @@ class GazeOfTheGorgonEffect extends OneShotEffect { List toDestroy = new ArrayList<>(); for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { if (!creature.getId().equals(targetCreature.getSourceId())) { - if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), targetCreature, game) || watcher.creatureHasBlockedAttacker(targetCreature, new MageObjectReference(creature, game), game)) { + if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), targetCreature) || watcher.creatureHasBlockedAttacker(targetCreature, new MageObjectReference(creature, game))) { toDestroy.add(creature); } } diff --git a/Mage.Sets/src/mage/cards/g/GeistcatchersRig.java b/Mage.Sets/src/mage/cards/g/GeistcatchersRig.java index 5f468e3b4c1..48ef5dc2ea2 100644 --- a/Mage.Sets/src/mage/cards/g/GeistcatchersRig.java +++ b/Mage.Sets/src/mage/cards/g/GeistcatchersRig.java @@ -13,6 +13,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -35,7 +36,7 @@ public final class GeistcatchersRig extends CardImpl { this.toughness = new MageInt(5); // When Geistcatcher's Rig enters the battlefield, you may have it deal 4 damage to target creature with flying. Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(4), true); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GeneralJarkeld.java b/Mage.Sets/src/mage/cards/g/GeneralJarkeld.java index f05d68a0bf5..7644cc8e9b4 100644 --- a/Mage.Sets/src/mage/cards/g/GeneralJarkeld.java +++ b/Mage.Sets/src/mage/cards/g/GeneralJarkeld.java @@ -1,11 +1,11 @@ - package mage.cards.g; import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -22,11 +22,12 @@ import java.util.Set; import java.util.UUID; /** - * * @author L_J */ public final class GeneralJarkeld extends CardImpl { + private static final Condition condition = new IsStepCondition(PhaseStep.DECLARE_BLOCKERS, false); + public GeneralJarkeld(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.supertype.add(SuperType.LEGENDARY); @@ -36,7 +37,9 @@ public final class GeneralJarkeld extends CardImpl { this.toughness = new MageInt(2); // {T}: Switch the blocking creatures of two target attacking creatures. Activate this ability only during the declare blockers step. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new GeneralJarkeldSwitchBlockersEffect(), new TapSourceCost(), new IsStepCondition(PhaseStep.DECLARE_BLOCKERS, false)); + Ability ability = new ActivateIfConditionActivatedAbility( + new GeneralJarkeldSwitchBlockersEffect(), new TapSourceCost(), condition + ); ability.addTarget(new TargetAttackingCreature(2)); this.addAbility(ability); } @@ -56,7 +59,9 @@ class GeneralJarkeldSwitchBlockersEffect extends OneShotEffect { GeneralJarkeldSwitchBlockersEffect() { super(Outcome.Benefit); - this.staticText = "Switch the blocking creatures of two target attacking creatures"; + this.staticText = "choose two target blocked attacking creatures. If each of those creatures could be " + + "blocked by all creatures that the other is blocked by, each creature that's blocking exactly one " + + "of those attacking creatures stops blocking it and is blocking the other attacking creature"; } private GeneralJarkeldSwitchBlockersEffect(final GeneralJarkeldSwitchBlockersEffect effect) { @@ -82,14 +87,14 @@ class GeneralJarkeldSwitchBlockersEffect extends OneShotEffect { Set blockers1 = new HashSet<>(); Set blockers2 = new HashSet<>(); Set multiBlockers = new HashSet<>(); - + blockerSearch1: for (UUID blockerId : chosenGroup1.getBlockers()) { Permanent blocker = game.getPermanent(blockerId); if (blocker != null) { if (game.getCombat().blockingGroupsContains(blocker.getId())) { // if (blocker.getBlocking() > 1) { for (CombatGroup group : game.getCombat().getBlockingGroups()) { - if (group.getBlockers().contains(blocker.getId())) { + if (group.getBlockers().contains(blocker.getId())) { int attackerCount = group.getAttackers().size(); if (attackerCount > 1) { multiBlockers.add(blocker); @@ -104,7 +109,7 @@ class GeneralJarkeldSwitchBlockersEffect extends OneShotEffect { } } } - + blockerSearch2: for (UUID blockerId : chosenGroup2.getBlockers()) { Permanent blocker = game.getPermanent(blockerId); @@ -126,11 +131,11 @@ class GeneralJarkeldSwitchBlockersEffect extends OneShotEffect { } } } - + handleSingleBlockers(blockers1, chosenGroup1, chosenGroup2, controller, game); handleSingleBlockers(blockers2, chosenGroup2, chosenGroup1, controller, game); handleMultiBlockers(multiBlockers, chosenGroup1, chosenGroup2, controller, game); - + // the ability doesn't unblock a group that loses all blockers, however it will newly block a previously unblocked group if it gains a blocker this way if (!(chosenGroup1.getBlockers().isEmpty())) { chosenGroup1.setBlocked(true, game); @@ -179,7 +184,7 @@ class GeneralJarkeldSwitchBlockersEffect extends OneShotEffect { } } } - + if (sameBlocked && chosenGroup != null) { // if none (should not happen) or all the blockers correspond to Jarkeld's targets, the blockers remain the same CombatGroup otherGroup = (chosenGroup.equals(chosenGroup1) ? chosenGroup2 : chosenGroup1); chosenGroup.remove(blocker.getId()); diff --git a/Mage.Sets/src/mage/cards/g/GenesisChamber.java b/Mage.Sets/src/mage/cards/g/GenesisChamber.java index 8a008b95dd0..1f9524e8727 100644 --- a/Mage.Sets/src/mage/cards/g/GenesisChamber.java +++ b/Mage.Sets/src/mage/cards/g/GenesisChamber.java @@ -1,10 +1,8 @@ package mage.cards.g; import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.condition.common.SourceTappedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -28,12 +26,11 @@ public final class GenesisChamber extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // Whenever a nontoken creature enters the battlefield, if Genesis Chamber is untapped, that creature's controller creates a 1/1 colorless Myr artifact creature token. - TriggeredAbility ability = new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new GenesisChamberEffect(), StaticFilters.FILTER_CREATURE_NON_TOKEN, false, SetTargetPointer.PERMANENT); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, - SourceTappedCondition.UNTAPPED, - "Whenever a nontoken creature enters, " - + "if {this} is untapped, " - + "that creature's controller creates a 1/1 colorless Myr artifact creature token")); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + Zone.BATTLEFIELD, new GenesisChamberEffect(), + StaticFilters.FILTER_CREATURE_NON_TOKEN, + false, SetTargetPointer.PERMANENT + ).withInterveningIf(SourceTappedCondition.UNTAPPED)); } private GenesisChamber(final GenesisChamber card) { diff --git a/Mage.Sets/src/mage/cards/g/GeologicalAppraiser.java b/Mage.Sets/src/mage/cards/g/GeologicalAppraiser.java index 14d9e76c83b..d330e3772a9 100644 --- a/Mage.Sets/src/mage/cards/g/GeologicalAppraiser.java +++ b/Mage.Sets/src/mage/cards/g/GeologicalAppraiser.java @@ -3,7 +3,6 @@ package mage.cards.g; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.keyword.DiscoverEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -26,11 +25,7 @@ public final class GeologicalAppraiser extends CardImpl { this.toughness = new MageInt(2); // When Geological Appraiser enters the battlefield, if you cast it, discover 3. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DiscoverEffect(3)), - CastFromEverywhereSourceCondition.instance, - "When {this} enters, if you cast it, discover 3." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DiscoverEffect(3)).withInterveningIf(CastFromEverywhereSourceCondition.instance)); } private GeologicalAppraiser(final GeologicalAppraiser card) { diff --git a/Mage.Sets/src/mage/cards/g/GerrardCapashen.java b/Mage.Sets/src/mage/cards/g/GerrardCapashen.java index ef9083d6696..4de35db4600 100644 --- a/Mage.Sets/src/mage/cards/g/GerrardCapashen.java +++ b/Mage.Sets/src/mage/cards/g/GerrardCapashen.java @@ -1,31 +1,31 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.common.SourceAttackingCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.CardsInTargetHandCount; +import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.players.Player; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author FenrisulfrX */ public final class GerrardCapashen extends CardImpl { public GerrardCapashen(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); @@ -33,16 +33,17 @@ public final class GerrardCapashen extends CardImpl { this.toughness = new MageInt(4); // At the beginning of your upkeep, you gain 1 life for each card in target opponent's hand. - Ability ability1 = new BeginningOfUpkeepTriggeredAbility(new GerrardCapashenEffect() - ); - ability1.addTarget(new TargetOpponent()); - this.addAbility(ability1); + Ability ability = new BeginningOfUpkeepTriggeredAbility(new GainLifeEffect(CardsInTargetHandCount.instance) + .setText("you gain 1 life for each card in target opponent's hand")); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); // {3}{W}: Tap target creature. Activate this ability only if {this} is attacking. - Ability ability2 = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), - new ManaCostsImpl<>("{3}{W}"), SourceAttackingCondition.instance); - ability2.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability2); + ability = new ActivateIfConditionActivatedAbility( + new TapTargetEffect(), new ManaCostsImpl<>("{3}{W}"), SourceAttackingCondition.instance + ); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); } private GerrardCapashen(final GerrardCapashen card) { @@ -54,34 +55,3 @@ public final class GerrardCapashen extends CardImpl { return new GerrardCapashen(this); } } - -class GerrardCapashenEffect extends OneShotEffect { - - GerrardCapashenEffect() { - super(Outcome.GainLife); - staticText = "you gain 1 life for each card in target opponent's hand."; - } - - private GerrardCapashenEffect(final GerrardCapashenEffect effect) { - super(effect); - } - - @Override - public GerrardCapashenEffect copy() { - return new GerrardCapashenEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Player targetOpponent = game.getPlayer(this.getTargetPointer().getFirst(game, source)); - if (controller != null && targetOpponent != null) { - int cardsInHand = targetOpponent.getHand().size(); - if (cardsInHand > 0) { - controller.gainLife(cardsInHand, game, source); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/g/GetawayGlamer.java b/Mage.Sets/src/mage/cards/g/GetawayGlamer.java index 59b5b92dafa..a6ce3f7a4bd 100644 --- a/Mage.Sets/src/mage/cards/g/GetawayGlamer.java +++ b/Mage.Sets/src/mage/cards/g/GetawayGlamer.java @@ -15,6 +15,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.List; @@ -41,7 +42,7 @@ public final class GetawayGlamer extends CardImpl { // + {1} -- Exile target nontoken creature. Return it to the battlefield under its owner's control at the beginning of the next end step. this.getSpellAbility().addEffect(new ExileReturnBattlefieldNextEndStepTargetEffect().withTextThatCard(false)); this.getSpellAbility().addTarget( - new TargetCreaturePermanent(filter).withChooseHint("to exile") + new TargetPermanent(filter).withChooseHint("to exile") ); this.getSpellAbility().withFirstModeCost(new GenericManaCost(1)); diff --git a/Mage.Sets/src/mage/cards/g/GhastlyDemise.java b/Mage.Sets/src/mage/cards/g/GhastlyDemise.java index 325d906c4cc..8159fb3594b 100644 --- a/Mage.Sets/src/mage/cards/g/GhastlyDemise.java +++ b/Mage.Sets/src/mage/cards/g/GhastlyDemise.java @@ -10,10 +10,13 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * @author cbt33 */ @@ -23,7 +26,7 @@ public final class GhastlyDemise extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}"); // Destroy target nonblack creature if its toughness is less than or equal to the number of cards in your graveyard. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.getSpellAbility().addEffect(new GhastlyDemiseEffect()); } diff --git a/Mage.Sets/src/mage/cards/g/GhirapurOrrery.java b/Mage.Sets/src/mage/cards/g/GhirapurOrrery.java index 6236d92407c..e3c02e28f66 100644 --- a/Mage.Sets/src/mage/cards/g/GhirapurOrrery.java +++ b/Mage.Sets/src/mage/cards/g/GhirapurOrrery.java @@ -1,40 +1,36 @@ - package mage.cards.g; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.IntCompareCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CardsInHandCondition; import mage.abilities.effects.common.DrawCardTargetEffect; import mage.abilities.effects.common.continuous.PlayAdditionalLandsAllEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.TargetController; -import mage.constants.Zone; -import mage.game.Game; -import mage.players.Player; + +import java.util.UUID; /** - * * @author emerald000 */ public final class GhirapurOrrery extends CardImpl { + private static final Condition condition = new CardsInHandCondition(ComparisonType.EQUAL_TO, 0, TargetController.ACTIVE); + public GhirapurOrrery(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // Each player may play an additional land on each of their turns. this.addAbility(new SimpleStaticAbility(new PlayAdditionalLandsAllEffect())); // At the beginning of each player's upkeep, if that player has no cards in hand, that player draws three cards. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(TargetController.ANY, new DrawCardTargetEffect(3), false), - new GhirapurOrreryCondition(), - "At the beginning of each player's upkeep, if that player has no cards in hand, that player draws three cards.")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.EACH_PLAYER, new DrawCardTargetEffect(3), false + ).withInterveningIf(condition)); } private GhirapurOrrery(final GhirapurOrrery card) { @@ -46,19 +42,3 @@ public final class GhirapurOrrery extends CardImpl { return new GhirapurOrrery(this); } } - -class GhirapurOrreryCondition extends IntCompareCondition { - - GhirapurOrreryCondition() { - super(ComparisonType.EQUAL_TO, 0); - } - - @Override - protected int getInputValue(Game game, Ability source) { - Player activePlayer = game.getPlayer(game.getActivePlayerId()); - if (activePlayer != null) { - return activePlayer.getHand().size(); - } - return 0; - } -} diff --git a/Mage.Sets/src/mage/cards/g/GhituAmplifier.java b/Mage.Sets/src/mage/cards/g/GhituAmplifier.java index 19273d99cb8..5a65b5b9370 100644 --- a/Mage.Sets/src/mage/cards/g/GhituAmplifier.java +++ b/Mage.Sets/src/mage/cards/g/GhituAmplifier.java @@ -5,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.KickerAbility; @@ -36,11 +35,7 @@ public final class GhituAmplifier extends CardImpl { this.addAbility(new KickerAbility("{2}{U}")); // When Ghitu Amplifier enters the battlefield, if it was kicked, return target creature an opponent controls to its owner's hand. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()), - KickedCondition.ONCE, "When {this} enters, " + - "if it was kicked, return target creature an opponent controls to its owner's hand." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()).withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetOpponentsCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/g/GhituChronicler.java b/Mage.Sets/src/mage/cards/g/GhituChronicler.java index 3ef095a1821..158eeb7c6c2 100644 --- a/Mage.Sets/src/mage/cards/g/GhituChronicler.java +++ b/Mage.Sets/src/mage/cards/g/GhituChronicler.java @@ -1,19 +1,16 @@ - package mage.cards.g; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.FilterCard; -import mage.filter.common.FilterInstantOrSorceryCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; @@ -23,9 +20,6 @@ import java.util.UUID; */ public final class GhituChronicler extends CardImpl { - private static final FilterCard filter - = new FilterInstantOrSorceryCard("instant or sorcery card from your graveyard"); - public GhituChronicler(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); @@ -38,12 +32,8 @@ public final class GhituChronicler extends CardImpl { this.addAbility(new KickerAbility("{3}{R}")); // When Ghitu Chronicler enters the battlefield, if it was kicked, return target instant or sorcery card from your graveyard to your hand. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), false), - KickedCondition.ONCE, "When {this} enters, if it was kicked, " + - "return target instant or sorcery card from your graveyard to your hand." - ); - ability.addTarget(new TargetCardInYourGraveyard(filter)); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()).withInterveningIf(KickedCondition.ONCE); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GhituJourneymage.java b/Mage.Sets/src/mage/cards/g/GhituJourneymage.java index 14249b36e39..5763d4c75ea 100644 --- a/Mage.Sets/src/mage/cards/g/GhituJourneymage.java +++ b/Mage.Sets/src/mage/cards/g/GhituJourneymage.java @@ -1,34 +1,35 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamagePlayersEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.constants.TargetController; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class GhituJourneymage extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("another Wizard"); + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.WIZARD, "you control another Wizard"); static { filter.add(AnotherPredicate.instance); - filter.add(SubType.WIZARD.getPredicate()); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + public GhituJourneymage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); @@ -38,12 +39,7 @@ public final class GhituJourneymage extends CardImpl { this.toughness = new MageInt(2); // When Ghitu Journeymage enters the battlefield, if you control another Wizard, Ghitu Journeymage deals 2 damage to each opponent. - TriggeredAbility triggeredAbility = new EntersBattlefieldTriggeredAbility(new DamagePlayersEffect(2, TargetController.OPPONENT)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - triggeredAbility, - new PermanentsOnTheBattlefieldCondition(filter), - "When {this} enters, if you control another Wizard, {this} deals 2 damage to each opponent." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DamagePlayersEffect(2, TargetController.OPPONENT)).withInterveningIf(condition)); } private GhituJourneymage(final GhituJourneymage card) { diff --git a/Mage.Sets/src/mage/cards/g/GhostTown.java b/Mage.Sets/src/mage/cards/g/GhostTown.java index 01e430d8539..7a26a8c3868 100644 --- a/Mage.Sets/src/mage/cards/g/GhostTown.java +++ b/Mage.Sets/src/mage/cards/g/GhostTown.java @@ -4,12 +4,10 @@ import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.NotMyTurnCondition; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.ReturnToHandSourceEffect; -import mage.abilities.hint.common.NotMyTurnHint; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import java.util.UUID; @@ -25,9 +23,9 @@ public final class GhostTown extends CardImpl { this.addAbility(new ColorlessManaAbility()); // {0}: Return Ghost Town to its owner's hand. Activate this ability only if it's not your turn. - this.addAbility(new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandSourceEffect(true), - new GenericManaCost(0), NotMyTurnCondition.instance) - .addHint(NotMyTurnHint.instance)); + this.addAbility(new ActivateIfConditionActivatedAbility( + new ReturnToHandSourceEffect(true), new GenericManaCost(0), NotMyTurnCondition.instance + )); } private GhostTown(final GhostTown card) { diff --git a/Mage.Sets/src/mage/cards/g/GhosthelmCourier.java b/Mage.Sets/src/mage/cards/g/GhosthelmCourier.java index 444545774e2..07756b42af4 100644 --- a/Mage.Sets/src/mage/cards/g/GhosthelmCourier.java +++ b/Mage.Sets/src/mage/cards/g/GhosthelmCourier.java @@ -20,6 +20,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -50,7 +51,7 @@ public final class GhosthelmCourier extends CardImpl { ability.addEffect(new ConditionalContinuousEffect(new GainAbilityTargetEffect(ShroudAbility.getInstance(), Duration.Custom), SourceTappedCondition.TAPPED,"and has shroud for as long as {this} remains tapped")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GhostlyDancers.java b/Mage.Sets/src/mage/cards/g/GhostlyDancers.java new file mode 100644 index 00000000000..7458b643734 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GhostlyDancers.java @@ -0,0 +1,87 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.abilityword.EerieAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.token.Spirit31Token; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GhostlyDancers extends CardImpl { + + public GhostlyDancers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); + + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(2); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When this creature enters, return an enchantment card from your graveyard to your hand or unlock a locked door of a Room you control. + this.addAbility(new EntersBattlefieldTriggeredAbility(new GhostlyDancersEffect())); + + // Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, create a 3/1 white Spirit creature token with flying. + this.addAbility(new EerieAbility(new CreateTokenEffect(new Spirit31Token()))); + } + + private GhostlyDancers(final GhostlyDancers card) { + super(card); + } + + @Override + public GhostlyDancers copy() { + return new GhostlyDancers(this); + } +} + +class GhostlyDancersEffect extends OneShotEffect { + + GhostlyDancersEffect() { + super(Outcome.Benefit); + staticText = "return an enchantment card from your graveyard to your hand or unlock a locked door of a Room you control"; + } + + private GhostlyDancersEffect(final GhostlyDancersEffect effect) { + super(effect); + } + + @Override + public GhostlyDancersEffect copy() { + return new GhostlyDancersEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + // TODO: 7/7/25 this needs to be refactored when rooms are implemented + Player player = game.getPlayer(source.getControllerId()); + if (player == null || player.getGraveyard().count(StaticFilters.FILTER_CARD_ENCHANTMENT, game) < 1) { + return false; + } + TargetCard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ENCHANTMENT); + target.withNotTarget(true); + player.choose(outcome, target, source, game); + Card card = game.getCard(target.getFirstTarget()); + return card != null && player.moveCards(card, Zone.HAND, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GhostlyVisit.java b/Mage.Sets/src/mage/cards/g/GhostlyVisit.java index cfb939434aa..df41330c4d1 100644 --- a/Mage.Sets/src/mage/cards/g/GhostlyVisit.java +++ b/Mage.Sets/src/mage/cards/g/GhostlyVisit.java @@ -6,8 +6,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author LoneFox @@ -19,7 +22,7 @@ public final class GhostlyVisit extends CardImpl { // Destroy target nonblack creature. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); } private GhostlyVisit(final GhostlyVisit card) { diff --git a/Mage.Sets/src/mage/cards/g/GiantOyster.java b/Mage.Sets/src/mage/cards/g/GiantOyster.java index df682ce3765..1311bc09995 100644 --- a/Mage.Sets/src/mage/cards/g/GiantOyster.java +++ b/Mage.Sets/src/mage/cards/g/GiantOyster.java @@ -24,6 +24,7 @@ import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -55,7 +56,7 @@ public final class GiantOyster extends CardImpl { .setText("For as long as {this} remains tapped, target tapped creature doesn't untap during its controller's untap step"), new TapSourceCost()); ability.addEffect(new GiantOysterCreateDelayedTriggerEffects()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GiantTrapDoorSpider.java b/Mage.Sets/src/mage/cards/g/GiantTrapDoorSpider.java index 5fb28ea8bea..0a608fea718 100644 --- a/Mage.Sets/src/mage/cards/g/GiantTrapDoorSpider.java +++ b/Mage.Sets/src/mage/cards/g/GiantTrapDoorSpider.java @@ -18,6 +18,7 @@ import mage.constants.Zone; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.filter.common.FilterCreatureAttackingYou; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -43,7 +44,7 @@ public final class GiantTrapDoorSpider extends CardImpl { Ability ability = new SimpleActivatedAbility(new ExileSourceEffect(), new ManaCostsImpl<>("{1}{R}{G}")); ability.addCost(new TapSourceCost()); ability.addEffect(new ExileTargetEffect().setText("and target creature without flying that's attacking you")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GiantsGrasp.java b/Mage.Sets/src/mage/cards/g/GiantsGrasp.java index 87f1342896a..bcb6ccb268f 100644 --- a/Mage.Sets/src/mage/cards/g/GiantsGrasp.java +++ b/Mage.Sets/src/mage/cards/g/GiantsGrasp.java @@ -1,24 +1,23 @@ package mage.cards.g; -import java.util.UUID; - -import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.continuous.GainControlTargetEffect; -import mage.constants.Duration; -import mage.constants.SubType; import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.AttachEffect; -import mage.constants.Outcome; -import mage.filter.common.FilterControlledPermanent; -import mage.target.TargetPermanent; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetNonlandPermanent; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class GiantsGrasp extends CardImpl { @@ -40,7 +39,7 @@ public final class GiantsGrasp extends CardImpl { // When Giant's Grasp enters the battlefield, gain control of target nonland permanent for as long as Giant's Grasp remains on the battlefield. GainControlTargetEffect controlEffect = new GainControlTargetEffect(Duration.UntilSourceLeavesBattlefield); - controlEffect.setText("gain control of target nonland permanent for as long as Giant's Grasp remains on the battlefield"); + controlEffect.setText("gain control of target nonland permanent for as long as {this} remains on the battlefield"); ability = new EntersBattlefieldTriggeredAbility(controlEffect); ability.addTarget(new TargetNonlandPermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/g/GibberingFiend.java b/Mage.Sets/src/mage/cards/g/GibberingFiend.java index 4ff11c3ffdf..0fe87e51653 100644 --- a/Mage.Sets/src/mage/cards/g/GibberingFiend.java +++ b/Mage.Sets/src/mage/cards/g/GibberingFiend.java @@ -1,21 +1,21 @@ package mage.cards.g; -import java.util.UUID; - import mage.MageInt; -import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; +import java.util.UUID; + /** * @author fireshoes */ @@ -28,16 +28,15 @@ public final class GibberingFiend extends CardImpl { this.toughness = new MageInt(1); // When Gibbering Fiend enters the battlefield, it deals 1 damage to each opponent. - this.addAbility(new EntersBattlefieldTriggeredAbility(new DamagePlayersEffect(1, TargetController.OPPONENT, "it"), false)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DamagePlayersEffect( + 1, TargetController.OPPONENT, "it" + ), false)); // Delirium — At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, // Gibbering Fiend deals 1 damage to that player. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(TargetController.OPPONENT, new DamageTargetEffect(1), false), - DeliriumCondition.instance, - "Delirium — At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, " - + "{this} deals 1 damage to that player.") - .addHint(CardTypesInGraveyardCount.YOU.getHint())); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.OPPONENT, new DamageTargetEffect(1, true, "that player"), false + ).withInterveningIf(DeliriumCondition.instance).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); } private GibberingFiend(final GibberingFiend card) { diff --git a/Mage.Sets/src/mage/cards/g/GideonBattleForged.java b/Mage.Sets/src/mage/cards/g/GideonBattleForged.java index dc1422b1aa1..a2adb7e3c1a 100644 --- a/Mage.Sets/src/mage/cards/g/GideonBattleForged.java +++ b/Mage.Sets/src/mage/cards/g/GideonBattleForged.java @@ -18,6 +18,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.TokenImpl; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -46,7 +47,7 @@ public final class GideonBattleForged extends CardImpl { // +2: Up to one target creature an opponent controls attacks Gideon, Battle-Forged during its controller's next turn if able. LoyaltyAbility loyaltyAbility = new LoyaltyAbility(new GideonBattleForgedAttacksIfAbleTargetEffect(Duration.Custom), 2); - loyaltyAbility.addTarget(new TargetCreaturePermanent(0, 1, filter, false)); + loyaltyAbility.addTarget(new TargetPermanent(0, 1, filter)); this.addAbility(loyaltyAbility); // +1: Until your next turn, target creature gains indestructible. Untap that creature. diff --git a/Mage.Sets/src/mage/cards/g/GideonJura.java b/Mage.Sets/src/mage/cards/g/GideonJura.java index f546e9a380b..b679e7c06f0 100644 --- a/Mage.Sets/src/mage/cards/g/GideonJura.java +++ b/Mage.Sets/src/mage/cards/g/GideonJura.java @@ -17,6 +17,7 @@ import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.TokenImpl; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponent; @@ -47,7 +48,7 @@ public final class GideonJura extends CardImpl { // −2: Destroy target tapped creature. LoyaltyAbility ability2 = new LoyaltyAbility(new DestroyTargetEffect(), -2); - ability2.addTarget(new TargetCreaturePermanent(filter)); + ability2.addTarget(new TargetPermanent(filter)); this.addAbility(ability2); // 0: Until end of turn, Gideon Jura becomes a 6/6 Human Soldier creature that's still a planeswalker. Prevent all damage that would be dealt to him this turn. diff --git a/Mage.Sets/src/mage/cards/g/GideonsDefeat.java b/Mage.Sets/src/mage/cards/g/GideonsDefeat.java index e7a8f4e6c83..a930cbc8b52 100644 --- a/Mage.Sets/src/mage/cards/g/GideonsDefeat.java +++ b/Mage.Sets/src/mage/cards/g/GideonsDefeat.java @@ -17,6 +17,7 @@ import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -36,7 +37,7 @@ public final class GideonsDefeat extends CardImpl { // Exile target white creature that's attacking or blocking. If it was a Gideon planeswalker, you gain 5 life. this.getSpellAbility().addEffect(new GideonsDefeatEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private GideonsDefeat(final GideonsDefeat card) { diff --git a/Mage.Sets/src/mage/cards/g/GiftOfDoom.java b/Mage.Sets/src/mage/cards/g/GiftOfDoom.java index 521ee336c6c..7600c148a41 100644 --- a/Mage.Sets/src/mage/cards/g/GiftOfDoom.java +++ b/Mage.Sets/src/mage/cards/g/GiftOfDoom.java @@ -22,7 +22,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; -import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -102,7 +101,7 @@ class GiftOfDoomEffect extends OneShotEffect { if (player == null || giftOfDoom == null) { return false; } - TargetCreaturePermanent target = new TargetCreaturePermanent(filter); + TargetPermanent target = new TargetPermanent(filter); target.withNotTarget(true); if (player.choose(outcome, target, source, game) && game.getPermanent(target.getFirstTarget()) != null diff --git a/Mage.Sets/src/mage/cards/g/Gigantiform.java b/Mage.Sets/src/mage/cards/g/Gigantiform.java index feb60a03ab0..9cd8967cd05 100644 --- a/Mage.Sets/src/mage/cards/g/Gigantiform.java +++ b/Mage.Sets/src/mage/cards/g/Gigantiform.java @@ -1,40 +1,43 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.StaticAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessAttachedEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.KickerAbility; import mage.abilities.keyword.TrampleAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.NamePredicate; -import mage.game.Game; -import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class Gigantiform extends CardImpl { + private static final FilterCard filter = new FilterCard("card named Gigantiform"); + + static { + filter.add(new NamePredicate("Gigantiform")); + } + public Gigantiform(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}{G}"); this.subtype.add(SubType.AURA); // Kicker {4} @@ -44,15 +47,21 @@ public final class Gigantiform extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget)); + // Enchanted creature has base power and toughness 8/8 and has trample. - this.addAbility(new GigantiformAbility()); + Ability ability = new SimpleStaticAbility( + new SetBasePowerToughnessAttachedEffect(8, 8, AttachmentType.AURA) + ); + ability.addEffect(new GainAbilityAttachedEffect( + TrampleAbility.getInstance(), AttachmentType.AURA + ).setText("and has trample")); + this.addAbility(ability); + // When Gigantiform enters the battlefield, if it was kicked, you may search your library for a card named Gigantiform, put it onto the battlefield, then shuffle your library. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new GigantiformEffect(), true), - KickedCondition.ONCE, - "When {this} enters, if it was kicked, you may search your library for a card named Gigantiform, put it onto the battlefield, then shuffle.")); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter)), true + ).withInterveningIf(KickedCondition.ONCE)); } private Gigantiform(final Gigantiform card) { @@ -64,65 +73,3 @@ public final class Gigantiform extends CardImpl { return new Gigantiform(this); } } - -class GigantiformAbility extends StaticAbility { - - public GigantiformAbility() { - super(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(TrampleAbility.getInstance(), AttachmentType.AURA)); - Ability ability = new SimpleStaticAbility( - new SetBasePowerToughnessSourceEffect(8, 8, Duration.WhileOnBattlefield) - ); - this.addEffect(new GainAbilityAttachedEffect(ability, AttachmentType.AURA)); - } - - private GigantiformAbility(final GigantiformAbility ability) { - super(ability); - } - - @Override - public GigantiformAbility copy() { - return new GigantiformAbility(this); - } - - @Override - public String getRule() { - return "Enchanted creature has base power and toughness 8/8 and has trample."; - } -} - -class GigantiformEffect extends OneShotEffect { - - private static final FilterCard filter = new FilterCard("card named Gigantiform"); - - static { - filter.add(new NamePredicate("Gigantiform")); - } - - public GigantiformEffect() { - super(Outcome.PutCardInPlay); - } - - private GigantiformEffect(final GigantiformEffect effect) { - super(effect); - } - - @Override - public GigantiformEffect copy() { - return new GigantiformEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller != null && controller.searchLibrary(target, source, game)) { - Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); - if (card != null) { - controller.moveCards(card, Zone.BATTLEFIELD, source, game); - } - controller.shuffleLibrary(source, game); - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/g/GildedCerodon.java b/Mage.Sets/src/mage/cards/g/GildedCerodon.java index 40d5fec95c6..e9ca33a3c48 100644 --- a/Mage.Sets/src/mage/cards/g/GildedCerodon.java +++ b/Mage.Sets/src/mage/cards/g/GildedCerodon.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.DesertControlledOrGraveyardCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.combat.CantBlockTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -20,8 +19,6 @@ import java.util.UUID; */ public final class GildedCerodon extends CardImpl { - private static final String rule = "Whenever {this} attacks, if you control a Desert or there is a Desert card in your graveyard, target creature can't block this turn."; - public GildedCerodon(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); @@ -31,13 +28,10 @@ public final class GildedCerodon extends CardImpl { this.toughness = new MageInt(4); // Whenever Gilded Cerodon attacks, if you control a Desert or there is a Desert card in your graveyard, target creature can't block this turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new CantBlockTargetEffect(Duration.EndOfTurn), false), - DesertControlledOrGraveyardCondition.instance, rule - ); + Ability ability = new AttacksTriggeredAbility(new CantBlockTargetEffect(Duration.EndOfTurn)) + .withInterveningIf(DesertControlledOrGraveyardCondition.instance); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability.addHint(DesertControlledOrGraveyardCondition.getHint())); - } private GildedCerodon(final GildedCerodon card) { diff --git a/Mage.Sets/src/mage/cards/g/GildedDrake.java b/Mage.Sets/src/mage/cards/g/GildedDrake.java index 20c836ec93d..07a9862b066 100644 --- a/Mage.Sets/src/mage/cards/g/GildedDrake.java +++ b/Mage.Sets/src/mage/cards/g/GildedDrake.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -12,17 +10,17 @@ import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; -import mage.filter.StaticFilters; +import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class GildedDrake extends CardImpl { @@ -36,11 +34,12 @@ public final class GildedDrake extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); + // When Gilded Drake enters the battlefield, exchange control of Gilded Drake and up to one target creature an opponent controls. If you don't make an exchange, sacrifice Gilded Drake. // This ability can't be countered except by spells and abilities. Ability ability = new EntersBattlefieldTriggeredAbility(new GildedDrakeEffect()); ability.setCanFizzle(false); - ability.addTarget(new TargetCreaturePermanent(0, 1, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, false)); + ability.addTarget(new TargetOpponentsCreaturePermanent(0, 1)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GilgameshMasterAtArms.java b/Mage.Sets/src/mage/cards/g/GilgameshMasterAtArms.java index 3deb2f77af6..d9a92bffc6a 100644 --- a/Mage.Sets/src/mage/cards/g/GilgameshMasterAtArms.java +++ b/Mage.Sets/src/mage/cards/g/GilgameshMasterAtArms.java @@ -1,7 +1,6 @@ package mage.cards.g; import mage.MageInt; -import mage.MageItem; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; @@ -14,8 +13,7 @@ import mage.constants.*; import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -165,13 +163,7 @@ class GilgameshMasterAtArmsAttachEffect extends OneShotEffect { break; } FilterPermanent filterPermanent = new FilterPermanent("Equipment"); - Predicates.or( - permanents - .stream() - .map(MageItem::getId) - .map(PermanentIdPredicate::new) - .collect(Collectors.toSet()) - ); + filterPermanent.add(new PermanentReferenceInCollectionPredicate(permanents, game)); return Optional .of(new TargetPermanent(0, 1, filterPermanent, true)) .map(t -> { diff --git a/Mage.Sets/src/mage/cards/g/GiltBladeProwler.java b/Mage.Sets/src/mage/cards/g/GiltBladeProwler.java index d6e26165c25..a50ddcaf47a 100644 --- a/Mage.Sets/src/mage/cards/g/GiltBladeProwler.java +++ b/Mage.Sets/src/mage/cards/g/GiltBladeProwler.java @@ -13,7 +13,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.watchers.common.DiscardedCardWatcher; import java.util.UUID; @@ -33,8 +32,8 @@ public final class GiltBladeProwler extends CardImpl { // {1}, {T}, Pay 1 life: Draw a card. Activate only if you've discarded a card this turn. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), - new GenericManaCost(1), ControllerDiscardedThisTurnCondition.instance + new DrawCardSourceControllerEffect(1), new GenericManaCost(1), + ControllerDiscardedThisTurnCondition.instance ); ability.addCost(new TapSourceCost()); ability.addCost(new PayLifeCost(1)); diff --git a/Mage.Sets/src/mage/cards/g/GiltLeafWinnower.java b/Mage.Sets/src/mage/cards/g/GiltLeafWinnower.java index 60d3c9a4a1e..470bc8c4f3c 100644 --- a/Mage.Sets/src/mage/cards/g/GiltLeafWinnower.java +++ b/Mage.Sets/src/mage/cards/g/GiltLeafWinnower.java @@ -16,6 +16,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicates; import mage.game.Game; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -43,7 +44,7 @@ public final class GiltLeafWinnower extends CardImpl { // When Gilt-Leaf Winnower enters the battlefield, you may destroy target non-Elf creature whose power and toughness aren't equal. Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), true); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GimlisRecklessMight.java b/Mage.Sets/src/mage/cards/g/GimlisRecklessMight.java index 8ad1f100229..824bf4b2c6e 100644 --- a/Mage.Sets/src/mage/cards/g/GimlisRecklessMight.java +++ b/Mage.Sets/src/mage/cards/g/GimlisRecklessMight.java @@ -1,30 +1,31 @@ package mage.cards.g; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.FormidableCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.FightTargetsEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterAttackingCreature; -import mage.filter.common.FilterCreaturePermanent; import mage.target.TargetPermanent; import java.util.UUID; /** - * * @author notgreat */ public final class GimlisRecklessMight extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterAttackingCreature("attacking creature you control"); + private static final FilterPermanent filter = new FilterAttackingCreature("attacking creature you control"); static { filter.add(TargetController.YOU.getControllerPredicate()); @@ -35,14 +36,15 @@ public final class GimlisRecklessMight extends CardImpl { // Creatures you control have haste. this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - HasteAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES))); + HasteAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES + ))); + // Formidable -- Whenever you attack, if creatures you control have total power 8 or greater, target attacking creature you control fights up to one target creature you don't control. - TriggeredAbility ability = new AttacksWithCreaturesTriggeredAbility(new FightTargetsEffect(),1); + Ability ability = new AttacksWithCreaturesTriggeredAbility(new FightTargetsEffect(), 1) + .withInterveningIf(FormidableCondition.instance); ability.addTarget(new TargetPermanent(filter)); ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); - ability.setAbilityWord(AbilityWord.FORMIDABLE); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, FormidableCondition.instance, - "Formidable — Whenever you attack, if creatures you control have total power 8 or greater, target attacking creature you control fights up to one target creature you don't control.")); + this.addAbility(ability.setAbilityWord(AbilityWord.FORMIDABLE)); } private GimlisRecklessMight(final GimlisRecklessMight card) { diff --git a/Mage.Sets/src/mage/cards/g/GixYawgmothPraetor.java b/Mage.Sets/src/mage/cards/g/GixYawgmothPraetor.java index 6fa05c7b7ff..f9811fed4a4 100644 --- a/Mage.Sets/src/mage/cards/g/GixYawgmothPraetor.java +++ b/Mage.Sets/src/mage/cards/g/GixYawgmothPraetor.java @@ -144,6 +144,7 @@ class GixYawgmothPraetorExileEffect extends OneShotEffect { int xValue = GetXValue.instance.calculate(game, source, this); Set toExile = opponent.getLibrary().getTopCards(game, xValue); controller.moveCards(toExile, Zone.EXILED, source, game); + game.processAction(); Cards cards = new CardsImpl(toExile); cards.retainZone(Zone.EXILED, game); CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, StaticFilters.FILTER_CARD, Integer.MAX_VALUE, null, true); diff --git a/Mage.Sets/src/mage/cards/g/GixianSkullflayer.java b/Mage.Sets/src/mage/cards/g/GixianSkullflayer.java index 17f6c723062..b8d4ab3d6de 100644 --- a/Mage.Sets/src/mage/cards/g/GixianSkullflayer.java +++ b/Mage.Sets/src/mage/cards/g/GixianSkullflayer.java @@ -1,26 +1,25 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.constants.SubType; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class GixianSkullflayer extends CardImpl { - private static final CardsInControllerGraveyardCondition condition - = new CardsInControllerGraveyardCondition(3, StaticFilters.FILTER_CARD_CREATURES); + private static final Condition condition = new CardsInControllerGraveyardCondition(3, StaticFilters.FILTER_CARD_CREATURES); public GixianSkullflayer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); @@ -32,11 +31,7 @@ public final class GixianSkullflayer extends CardImpl { this.toughness = new MageInt(3); // At the beginning of your upkeep, if there are three or more creature cards in your graveyard, put a +1/+1 counter on Gixian Skullflayer. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())), - condition, - "At the beginning of your upkeep, if there are three or more creature cards in your graveyard, put a +1/+1 counter on {this}." - )); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())).withInterveningIf(condition)); } private GixianSkullflayer(final GixianSkullflayer card) { diff --git a/Mage.Sets/src/mage/cards/g/GladeWatcher.java b/Mage.Sets/src/mage/cards/g/GladeWatcher.java index 07d0f2b4b4c..22da2a0cde7 100644 --- a/Mage.Sets/src/mage/cards/g/GladeWatcher.java +++ b/Mage.Sets/src/mage/cards/g/GladeWatcher.java @@ -1,9 +1,6 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.FormidableCondition; import mage.abilities.costs.mana.ManaCostsImpl; @@ -13,32 +10,30 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class GladeWatcher extends CardImpl { public GladeWatcher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(3); this.toughness = new MageInt(3); // Defender this.addAbility(DefenderAbility.getInstance()); + // Formidable — {G}: Glade Watcher can attack this turn as though it didn't have defender. Activate this ability only if creatures you control have total power 8 or greater. - Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, + this.addAbility(new ActivateIfConditionActivatedAbility( new CanAttackAsThoughItDidntHaveDefenderSourceEffect(Duration.EndOfTurn), - new ManaCostsImpl<>("{G}"), - FormidableCondition.instance); - ability.setAbilityWord(AbilityWord.FORMIDABLE); - this.addAbility(ability); + new ManaCostsImpl<>("{G}"), FormidableCondition.instance + ).setAbilityWord(AbilityWord.FORMIDABLE)); } private GladeWatcher(final GladeWatcher card) { diff --git a/Mage.Sets/src/mage/cards/g/GladewalkerRitualist.java b/Mage.Sets/src/mage/cards/g/GladewalkerRitualist.java index 38738ed0554..12b0c4e6424 100644 --- a/Mage.Sets/src/mage/cards/g/GladewalkerRitualist.java +++ b/Mage.Sets/src/mage/cards/g/GladewalkerRitualist.java @@ -1,7 +1,7 @@ package mage.cards.g; import mage.MageInt; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.ChangelingAbility; import mage.cards.CardImpl; @@ -9,9 +9,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.NamePredicate; import java.util.UUID; @@ -21,7 +21,7 @@ import java.util.UUID; public final class GladewalkerRitualist extends CardImpl { private static final FilterPermanent filter - = new FilterCreaturePermanent("another creature named Gladewalker Ritualist"); + = new FilterControlledCreaturePermanent("another creature you control named Gladewalker Ritualist"); static { filter.add(AnotherPredicate.instance); @@ -39,9 +39,7 @@ public final class GladewalkerRitualist extends CardImpl { this.addAbility(new ChangelingAbility()); // Whenever another creature named Gladewalker Ritualist you control enters, draw a card. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility( - new DrawCardSourceControllerEffect(1), filter - )); + this.addAbility(new EntersBattlefieldAllTriggeredAbility(new DrawCardSourceControllerEffect(1), filter)); } private GladewalkerRitualist(final GladewalkerRitualist card) { diff --git a/Mage.Sets/src/mage/cards/g/GlareOfSubdual.java b/Mage.Sets/src/mage/cards/g/GlareOfSubdual.java index ccecee5f520..64e746b7b43 100644 --- a/Mage.Sets/src/mage/cards/g/GlareOfSubdual.java +++ b/Mage.Sets/src/mage/cards/g/GlareOfSubdual.java @@ -7,33 +7,25 @@ import mage.abilities.effects.common.TapTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; import mage.target.TargetPermanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; import java.util.UUID; /** - * * @author Loki */ public final class GlareOfSubdual extends CardImpl { - private static final FilterControlledCreaturePermanent filterCost = new FilterControlledCreaturePermanent("untapped creature you control"); - - static { - filterCost.add(TappedPredicate.UNTAPPED); - } - public GlareOfSubdual(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{G}{W}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{W}"); // Tap an untapped creature you control: Tap target artifact or creature. - Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filterCost, true))); + Ability ability = new SimpleActivatedAbility( + new TapTargetEffect(), + new TapTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE)) + ); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GlaringAegis.java b/Mage.Sets/src/mage/cards/g/GlaringAegis.java index 8fb0ab81b99..801e5d89384 100644 --- a/Mage.Sets/src/mage/cards/g/GlaringAegis.java +++ b/Mage.Sets/src/mage/cards/g/GlaringAegis.java @@ -16,6 +16,8 @@ import mage.filter.StaticFilters; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author fireshoes @@ -35,7 +37,7 @@ public final class GlaringAegis extends CardImpl { // When Glaring Aegis enters the battlefield, tap target creature an opponent controls. Ability ability2 = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); - ability2.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability2.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability2); // Enchanted creature gets +1/+3. diff --git a/Mage.Sets/src/mage/cards/g/GlimmerdustNap.java b/Mage.Sets/src/mage/cards/g/GlimmerdustNap.java index 6291db3c059..d10c441d5a9 100644 --- a/Mage.Sets/src/mage/cards/g/GlimmerdustNap.java +++ b/Mage.Sets/src/mage/cards/g/GlimmerdustNap.java @@ -35,7 +35,7 @@ public final class GlimmerdustNap extends CardImpl { // Enchant tapped creature - TargetPermanent auraTarget = new TargetCreaturePermanent(filter); + TargetPermanent auraTarget = new TargetPermanent(filter); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); this.addAbility(new EnchantAbility(auraTarget)); diff --git a/Mage.Sets/src/mage/cards/g/Glimmervoid.java b/Mage.Sets/src/mage/cards/g/Glimmervoid.java index 496eb6510e7..6d7d609e923 100644 --- a/Mage.Sets/src/mage/cards/g/Glimmervoid.java +++ b/Mage.Sets/src/mage/cards/g/Glimmervoid.java @@ -1,33 +1,36 @@ - package mage.cards.g; -import java.util.UUID; -import mage.abilities.TriggeredAbility; -import mage.abilities.common.OnEventTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.mana.AnyColorManaAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; +import mage.constants.TargetController; import mage.filter.common.FilterControlledArtifactPermanent; -import mage.game.events.GameEvent; + +import java.util.UUID; /** - * * @author jonubuu */ public final class Glimmervoid extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledArtifactPermanent("you control no artifacts"), ComparisonType.EQUAL_TO, 0 + ); + public Glimmervoid(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // At the beginning of the end step, if you control no artifacts, sacrifice Glimmervoid. - TriggeredAbility triggered = new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new SacrificeSourceEffect()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(triggered, new PermanentsOnTheBattlefieldCondition(new FilterControlledArtifactPermanent(), ComparisonType.FEWER_THAN, 1), - "At the beginning of the end step, if you control no artifacts, sacrifice {this}.")); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.NEXT, new SacrificeSourceEffect(), false, condition + )); + // {tap}: Add one mana of any color. this.addAbility(new AnyColorManaAbility()); } diff --git a/Mage.Sets/src/mage/cards/g/GlintHornBuccaneer.java b/Mage.Sets/src/mage/cards/g/GlintHornBuccaneer.java index 871a50572c7..bc6b206fb60 100644 --- a/Mage.Sets/src/mage/cards/g/GlintHornBuccaneer.java +++ b/Mage.Sets/src/mage/cards/g/GlintHornBuccaneer.java @@ -6,7 +6,7 @@ import mage.abilities.TriggeredAbilityImpl; import mage.abilities.condition.common.SourceAttackingCondition; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.HasteAbility; @@ -41,9 +41,8 @@ public final class GlintHornBuccaneer extends CardImpl { this.addAbility(new GlintHornBuccaneerTriggeredAbility()); // {1}{R}, Discard a card: Draw a card. Activate this ability only if Glint-Horn Buccaneer is attacking. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), - new ManaCostsImpl<>("{1}{R}"), SourceAttackingCondition.instance + Ability ability = new ActivateIfConditionActivatedAbility( + new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{1}{R}"), SourceAttackingCondition.instance ); ability.addCost(new DiscardCardCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/g/GloriousEnforcer.java b/Mage.Sets/src/mage/cards/g/GloriousEnforcer.java index 9073f354890..815cd12948d 100644 --- a/Mage.Sets/src/mage/cards/g/GloriousEnforcer.java +++ b/Mage.Sets/src/mage/cards/g/GloriousEnforcer.java @@ -1,26 +1,25 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.DoubleStrikeAbility; -import mage.constants.Duration; -import mage.constants.SubType; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.TargetController; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class GloriousEnforcer extends CardImpl { @@ -39,14 +38,12 @@ public final class GloriousEnforcer extends CardImpl { this.addAbility(LifelinkAbility.getInstance()); // At the beginning of each combat, if you have more life than an opponent, Glorious Enforcer gains double strike until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - TargetController.ANY, new GainAbilitySourceEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn), - false - ), - GloriousEnforcerCondition.instance, - "At the beginning of each combat, if you have more life than an opponent, {this} gains double strike until end of turn." - )); + this.addAbility(new BeginningOfCombatTriggeredAbility( + TargetController.ANY, + new GainAbilitySourceEffect( + DoubleStrikeAbility.getInstance(), Duration.EndOfTurn + ), false + ).withInterveningIf(GloriousEnforcerCondition.instance)); } private GloriousEnforcer(final GloriousEnforcer card) { @@ -66,14 +63,20 @@ enum GloriousEnforcerCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - for (UUID opponentId : game.getOpponents(source.getControllerId())) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null && controller.getLife() > opponent.getLife()) { - return true; - } + if (controller == null) { + return false; + } + for (UUID opponentId : game.getOpponents(source.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null && controller.getLife() > opponent.getLife()) { + return true; } } return false; } + + @Override + public String toString() { + return "you have more life than an opponent"; + } } diff --git a/Mage.Sets/src/mage/cards/g/Glorybringer.java b/Mage.Sets/src/mage/cards/g/Glorybringer.java index a029e6847b5..898840dd46d 100644 --- a/Mage.Sets/src/mage/cards/g/Glorybringer.java +++ b/Mage.Sets/src/mage/cards/g/Glorybringer.java @@ -16,6 +16,7 @@ import mage.constants.SubType; import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -48,7 +49,7 @@ public final class Glorybringer extends CardImpl { Effect effect = new DamageTargetEffect(4); effect.setText("it deals 4 damage to target non-Dragon creature an opponent controls"); BecomesExertSourceTriggeredAbility ability = new BecomesExertSourceTriggeredAbility(effect); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(new ExertAbility(ability)); } diff --git a/Mage.Sets/src/mage/cards/g/GlyphOfDelusion.java b/Mage.Sets/src/mage/cards/g/GlyphOfDelusion.java index 431d0f82bec..4b6b8c25125 100644 --- a/Mage.Sets/src/mage/cards/g/GlyphOfDelusion.java +++ b/Mage.Sets/src/mage/cards/g/GlyphOfDelusion.java @@ -20,7 +20,6 @@ import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; import mage.watchers.common.BlockedAttackerWatcher; @@ -43,7 +42,7 @@ public final class GlyphOfDelusion extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); // Put X glyph counters on target creature that target Wall blocked this turn, where X is the power of that blocked creature. The creature gains “This creature doesn’t untap during your untap step if it has a glyph counter on it” and “At the beginning of your upkeep, remove a glyph counter from this creature.” - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addTarget(new GlyphOfDelusionSecondTarget()); this.getSpellAbility().addEffect(new GlyphOfDelusionEffect()); } @@ -82,7 +81,7 @@ class GlyphOfDelusionSecondTarget extends TargetPermanent { if (targetSource != null) { for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, source, game)) { if (!targets.containsKey(creature.getId()) && creature.canBeTargetedBy(targetSource, sourceControllerId, source, game)) { - if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), new MageObjectReference(firstTarget, game), game)) { + if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), new MageObjectReference(firstTarget, game))) { possibleTargets.add(creature.getId()); } } diff --git a/Mage.Sets/src/mage/cards/g/GlyphOfDestruction.java b/Mage.Sets/src/mage/cards/g/GlyphOfDestruction.java index ddfb5909c3b..ccb4409e045 100644 --- a/Mage.Sets/src/mage/cards/g/GlyphOfDestruction.java +++ b/Mage.Sets/src/mage/cards/g/GlyphOfDestruction.java @@ -1,26 +1,26 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.effects.common.DestroyTargetAtBeginningOfNextEndStepEffect; import mage.abilities.effects.common.PreventDamageToTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.BlockingPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author L_J */ public final class GlyphOfDestruction extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("blocking Wall you control"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("blocking Wall you control"); static { filter.add(SubType.WALL.getPredicate()); @@ -28,13 +28,13 @@ public final class GlyphOfDestruction extends CardImpl { } public GlyphOfDestruction(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); // Target blocking Wall you control gets +10/+0 until end of combat. Prevent all damage that would be dealt to it this turn. Destroy it at the beginning of the next end step. this.getSpellAbility().addEffect(new BoostTargetEffect(10, 0, Duration.EndOfCombat)); this.getSpellAbility().addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, Integer.MAX_VALUE).setText("Prevent all damage that would be dealt to it this turn")); this.getSpellAbility().addEffect(new DestroyTargetAtBeginningOfNextEndStepEffect().setText("Destroy it at the beginning of the next end step")); - this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private GlyphOfDestruction(final GlyphOfDestruction card) { diff --git a/Mage.Sets/src/mage/cards/g/GlyphOfDoom.java b/Mage.Sets/src/mage/cards/g/GlyphOfDoom.java index 8accdeb1223..101163093f7 100644 --- a/Mage.Sets/src/mage/cards/g/GlyphOfDoom.java +++ b/Mage.Sets/src/mage/cards/g/GlyphOfDoom.java @@ -19,7 +19,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import mage.watchers.common.BlockedAttackerWatcher; /** @@ -38,7 +38,7 @@ public final class GlyphOfDoom extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}"); // Choose target Wall creature. At this turn's next end of combat, destroy all creatures that were blocked by that creature this turn. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new InfoEffect("Choose target Wall creature")); this.getSpellAbility().addEffect(new GlyphOfDoomCreateDelayedTriggeredAbilityEffect()); } @@ -109,7 +109,7 @@ class GlyphOfDoomEffect extends OneShotEffect { List toDestroy = new ArrayList<>(); for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { if (!creature.getId().equals(targetCreature.getSourceId())) { - if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), targetCreature, game)) { + if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), targetCreature)) { toDestroy.add(creature); } } diff --git a/Mage.Sets/src/mage/cards/g/GlyphOfLife.java b/Mage.Sets/src/mage/cards/g/GlyphOfLife.java index d41a3c57d93..e947e944ca1 100644 --- a/Mage.Sets/src/mage/cards/g/GlyphOfLife.java +++ b/Mage.Sets/src/mage/cards/g/GlyphOfLife.java @@ -19,6 +19,7 @@ import mage.game.events.DamagedEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class GlyphOfLife extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{W}"); // Choose target Wall creature. Whenever that creature is dealt damage by an attacking creature this turn, you gain that much life. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new InfoEffect("Choose target Wall creature")); this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new GlyphOfLifeTriggeredAbility())); } diff --git a/Mage.Sets/src/mage/cards/g/GlyphOfReincarnation.java b/Mage.Sets/src/mage/cards/g/GlyphOfReincarnation.java index 2d4fafefeea..640b7749364 100644 --- a/Mage.Sets/src/mage/cards/g/GlyphOfReincarnation.java +++ b/Mage.Sets/src/mage/cards/g/GlyphOfReincarnation.java @@ -20,8 +20,8 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInGraveyard; -import mage.target.common.TargetCreaturePermanent; import mage.watchers.common.BlockedAttackerWatcher; import java.util.HashMap; @@ -46,7 +46,7 @@ public final class GlyphOfReincarnation extends CardImpl { this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, null, AfterCombatCondition.instance, "Cast this spell only after combat")); // Destroy all creatures that were blocked by target Wall this turn. They can’t be regenerated. For each creature that died this way, put a creature card from the graveyard of the player who controlled that creature the last time it became blocked by that Wall onto the battlefield under its owner’s control. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new GlyphOfReincarnationEffect()); } @@ -86,7 +86,7 @@ class GlyphOfReincarnationEffect extends OneShotEffect { Map destroyed = new HashMap<>(); for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { if (!creature.getId().equals(targetWall.getId())) { - if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), new MageObjectReference(targetWall, game), game)) { + if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), new MageObjectReference(targetWall, game))) { if (creature.destroy(source, game, true) && game.getState().getZone(creature.getId()) == Zone.GRAVEYARD) { // If a commander is replaced to command zone, the creature does not die Player permController = game.getPlayer(creature.getControllerId()); diff --git a/Mage.Sets/src/mage/cards/g/GnawingVermin.java b/Mage.Sets/src/mage/cards/g/GnawingVermin.java index 265cadccae4..ed9a70f7870 100644 --- a/Mage.Sets/src/mage/cards/g/GnawingVermin.java +++ b/Mage.Sets/src/mage/cards/g/GnawingVermin.java @@ -12,9 +12,12 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * * @author weirddan455 @@ -35,7 +38,7 @@ public final class GnawingVermin extends CardImpl { // When Gnawing Vermin dies, target creature you don't control gets -1/-1 until end of turn. ability = new DiesSourceTriggeredAbility(new BoostTargetEffect(-1, -1)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GoForBlood.java b/Mage.Sets/src/mage/cards/g/GoForBlood.java index 9829274798a..714bff806f4 100644 --- a/Mage.Sets/src/mage/cards/g/GoForBlood.java +++ b/Mage.Sets/src/mage/cards/g/GoForBlood.java @@ -7,11 +7,14 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author TheElk801 */ @@ -23,7 +26,7 @@ public final class GoForBlood extends CardImpl { // Target creature you control fights target creature you don't control. this.getSpellAbility().addEffect(new FightTargetsEffect()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); // Cycling {1} this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{1}"))); diff --git a/Mage.Sets/src/mage/cards/g/GoForTheThroat.java b/Mage.Sets/src/mage/cards/g/GoForTheThroat.java index 1f145b3380d..f3ff694c212 100644 --- a/Mage.Sets/src/mage/cards/g/GoForTheThroat.java +++ b/Mage.Sets/src/mage/cards/g/GoForTheThroat.java @@ -6,6 +6,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -26,7 +27,7 @@ public final class GoForTheThroat extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}"); // Destroy target nonartifact creature. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinBirdGrabber.java b/Mage.Sets/src/mage/cards/g/GoblinBirdGrabber.java index d63bcf6759c..53835aaa838 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinBirdGrabber.java +++ b/Mage.Sets/src/mage/cards/g/GoblinBirdGrabber.java @@ -4,7 +4,7 @@ import mage.MageInt; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -12,7 +12,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; @@ -41,9 +40,10 @@ public final class GoblinBirdGrabber extends CardImpl { this.toughness = new MageInt(1); // {R}: Goblin Bird-Grabber gains flying until end of turn. Activate this ability only if you control a creature with flying. - this.addAbility(new ConditionalActivatedAbility(Zone.BATTLEFIELD, new GainAbilitySourceEffect( - FlyingAbility.getInstance(), Duration.EndOfTurn - ), new ManaCostsImpl<>("{R}"), condition)); + this.addAbility(new ActivateIfConditionActivatedAbility( + new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), + new ManaCostsImpl<>("{R}"), condition + )); } private GoblinBirdGrabber(final GoblinBirdGrabber card) { diff --git a/Mage.Sets/src/mage/cards/g/GoblinBurrows.java b/Mage.Sets/src/mage/cards/g/GoblinBurrows.java index 2899d5e9ab4..c5c627e33b7 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinBurrows.java +++ b/Mage.Sets/src/mage/cards/g/GoblinBurrows.java @@ -15,6 +15,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class GoblinBurrows extends CardImpl { // {1}{R}, {tap}: Target Goblin creature gets +2/+0 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(2,0, Duration.EndOfTurn), new ManaCostsImpl<>("{1}{R}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinBushwhacker.java b/Mage.Sets/src/mage/cards/g/GoblinBushwhacker.java index aee5bf27ee4..f200e9172b6 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinBushwhacker.java +++ b/Mage.Sets/src/mage/cards/g/GoblinBushwhacker.java @@ -1,11 +1,9 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.HasteAbility; @@ -13,12 +11,13 @@ import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author North */ public final class GoblinBushwhacker extends CardImpl { @@ -35,19 +34,14 @@ public final class GoblinBushwhacker extends CardImpl { this.addAbility(new KickerAbility("{R}")); // When this creature enters, if it was kicked, creatures you control get +1/+0 and gain haste until end of turn. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new BoostControlledEffect(1, 0, Duration.EndOfTurn), false); + Ability ability = new EntersBattlefieldTriggeredAbility( + new BoostControlledEffect(1, 0, Duration.EndOfTurn) + .setText("creatures you control get +1/+0")).withInterveningIf(KickedCondition.ONCE); ability.addEffect(new GainAbilityControlledEffect( - HasteAbility.getInstance(), - Duration.EndOfTurn, + HasteAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES - )); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - ability, - KickedCondition.ONCE, - "When this creature enters, " - + "if it was kicked, " - + "creatures you control get +1/+0 and gain haste until end of turn." - )); + ).setText("and gain haste until end of turn")); + this.addAbility(ability); } private GoblinBushwhacker(final GoblinBushwhacker card) { diff --git a/Mage.Sets/src/mage/cards/g/GoblinFirestarter.java b/Mage.Sets/src/mage/cards/g/GoblinFirestarter.java index 92a7ac76a7e..b3b70ff4d1b 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinFirestarter.java +++ b/Mage.Sets/src/mage/cards/g/GoblinFirestarter.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -12,24 +10,26 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author fireshoes */ public final class GoblinFirestarter extends CardImpl { public GoblinFirestarter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); this.subtype.add(SubType.GOBLIN); this.power = new MageInt(1); this.toughness = new MageInt(1); // Sacrifice Goblin Firestarter: Goblin Firestarter deals 1 damage to any target. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new DamageTargetEffect(1,"it"), new SacrificeSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DamageTargetEffect(1, "it"), + new SacrificeSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance + ); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinGloryChaser.java b/Mage.Sets/src/mage/cards/g/GoblinGloryChaser.java index 0f965af1b8d..8444540ca98 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinGloryChaser.java +++ b/Mage.Sets/src/mage/cards/g/GoblinGloryChaser.java @@ -1,31 +1,27 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.RenownedSourceCondition; import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.MenaceAbility; import mage.abilities.keyword.RenownAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author fireshoes */ public final class GoblinGloryChaser extends CardImpl { public GoblinGloryChaser(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); this.subtype.add(SubType.GOBLIN); this.subtype.add(SubType.WARRIOR); this.power = new MageInt(1); @@ -35,13 +31,11 @@ public final class GoblinGloryChaser extends CardImpl { this.addAbility(new RenownAbility(1)); // As long as Goblin Glory Chaser is renowned, it has menace. - Effect effect = new ConditionalContinuousEffect( + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( new GainAbilitySourceEffect(new MenaceAbility(), Duration.WhileOnBattlefield), - RenownedSourceCondition.instance, - "As long as {this} is renowned, it has menace. " + - "(It can't be blocked except by two or more creatures.)"); - Ability ability = new SimpleStaticAbility(effect); - this.addAbility(ability); + RenownedSourceCondition.THIS, "as long as {this} is renowned, " + + "it has menace. (It can't be blocked except by two or more creatures.)" + ))); } private GoblinGloryChaser(final GoblinGloryChaser card) { diff --git a/Mage.Sets/src/mage/cards/g/GoblinLyre.java b/Mage.Sets/src/mage/cards/g/GoblinLyre.java index ab861f85f8f..71e203cdc04 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinLyre.java +++ b/Mage.Sets/src/mage/cards/g/GoblinLyre.java @@ -9,7 +9,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.players.Player; @@ -46,7 +45,7 @@ class GoblinLyreEffect extends OneShotEffect { GoblinLyreEffect() { super(Outcome.Damage); this.staticText = "Flip a coin. If you win the flip, {this} deals damage to target opponent or planeswalker equal to the number of creatures you control. " - + "If you lose the flip, Goblin Lyre deals damage to you equal to the number of creatures that opponent or that planeswalker's controller controls"; + + "If you lose the flip, {this} deals damage to you equal to the number of creatures that opponent or that planeswalker's controller controls"; } private GoblinLyreEffect(final GoblinLyreEffect effect) { diff --git a/Mage.Sets/src/mage/cards/g/GoblinRacketeer.java b/Mage.Sets/src/mage/cards/g/GoblinRacketeer.java index a02c72ddb6f..7b0198c6748 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinRacketeer.java +++ b/Mage.Sets/src/mage/cards/g/GoblinRacketeer.java @@ -10,6 +10,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -35,7 +36,7 @@ public final class GoblinRacketeer extends CardImpl { // Whenever Goblin Racketeer attacks, you may goad target creature defending player controls. Ability ability = new AttacksTriggeredAbility(new GoadTargetEffect(), true); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinRuinblaster.java b/Mage.Sets/src/mage/cards/g/GoblinRuinblaster.java index ef91213e832..b1d434bc76d 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinRuinblaster.java +++ b/Mage.Sets/src/mage/cards/g/GoblinRuinblaster.java @@ -2,11 +2,10 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.KickerAbility; @@ -16,14 +15,15 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.target.common.TargetNonBasicLandPermanent; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public final class GoblinRuinblaster extends CardImpl { public GoblinRuinblaster(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); this.subtype.add(SubType.GOBLIN); this.subtype.add(SubType.SHAMAN); @@ -33,14 +33,13 @@ public final class GoblinRuinblaster extends CardImpl { // Kicker {R} (You may pay an additional {R} as you cast this spell.) this.addAbility(new KickerAbility("{R}")); - // Haste this.addAbility(HasteAbility.getInstance()); // When Goblin Ruinblaster enters the battlefield, if it was kicked, destroy target nonbasic land. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), false); + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()).withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetNonBasicLandPermanent()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.ONCE, "When {this} enters, if it was kicked, destroy target nonbasic land.")); + this.addAbility(ability); } private GoblinRuinblaster(final GoblinRuinblaster card) { diff --git a/Mage.Sets/src/mage/cards/g/GoblinSkycutter.java b/Mage.Sets/src/mage/cards/g/GoblinSkycutter.java index fa99a35d84e..4cfbe13ee95 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinSkycutter.java +++ b/Mage.Sets/src/mage/cards/g/GoblinSkycutter.java @@ -17,6 +17,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -42,7 +43,7 @@ public final class GoblinSkycutter extends CardImpl { // Sacrifice Goblin Skycutter: Goblin Skycutter deals 2 damage to target creature with flying. That creature loses flying until end of turn. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2, "it"), new SacrificeSourceCost()); ability.addEffect(new LoseAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn).setText("that creature loses flying until end of turn")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinTaskmaster.java b/Mage.Sets/src/mage/cards/g/GoblinTaskmaster.java index 51af39c4703..dee31fb7217 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinTaskmaster.java +++ b/Mage.Sets/src/mage/cards/g/GoblinTaskmaster.java @@ -15,6 +15,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class GoblinTaskmaster extends CardImpl { // {1}{R}: Target Goblin creature gets +1/+0 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl<>("{1}{R}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Morph {R} diff --git a/Mage.Sets/src/mage/cards/g/GoblinTunneler.java b/Mage.Sets/src/mage/cards/g/GoblinTunneler.java index 794fcf94f45..acbd8568247 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinTunneler.java +++ b/Mage.Sets/src/mage/cards/g/GoblinTunneler.java @@ -16,6 +16,7 @@ import mage.constants.ComparisonType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class GoblinTunneler extends CardImpl { // {tap}: Target creature with power 2 or less can't be blocked this turn. Ability ability = new SimpleActivatedAbility(new CantBeBlockedTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinVandal.java b/Mage.Sets/src/mage/cards/g/GoblinVandal.java index a0e7da6ecd1..c189a74c840 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinVandal.java +++ b/Mage.Sets/src/mage/cards/g/GoblinVandal.java @@ -1,29 +1,23 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.continuous.AssignNoCombatDamageSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterArtifactPermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; -import mage.game.combat.CombatGroup; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.target.Target; -import mage.target.TargetPermanent; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.target.common.TargetArtifactPermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; + +import java.util.UUID; /** * @@ -40,14 +34,13 @@ public final class GoblinVandal extends CardImpl { this.toughness = new MageInt(1); // Whenever Goblin Vandal attacks and isn't blocked, you may pay {R}. If you do, destroy target artifact defending player controls and Goblin Vandal assigns no combat damage this turn. - Effect effect = new DestroyTargetEffect(); - effect.setText("destroy target artifact defending player controls"); - DoIfCostPaid effect2 = new DoIfCostPaid(effect, new ManaCostsImpl<>("{R}"), "Pay {R} to destroy artifact of defending player?"); - effect = new AssignNoCombatDamageSourceEffect(Duration.EndOfTurn); - effect.setText("and {this} assigns no combat damage this turn"); - effect2.addEffect(effect); - this.addAbility(new GoblinVandalTriggeredAbility(effect2)); - + DoIfCostPaid effect = new DoIfCostPaid(new DestroyTargetEffect().setText("destroy target artifact defending player controls"), + new ManaCostsImpl<>("{R}"), "Pay {R} to destroy artifact of defending player?"); + effect.addEffect(new AssignNoCombatDamageSourceEffect(Duration.EndOfTurn).setText("and {this} assigns no combat damage this turn")); + Ability ability = new AttacksAndIsNotBlockedTriggeredAbility(effect, false, SetTargetPointer.PLAYER); + ability.addTarget(new TargetArtifactPermanent()); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); + this.addAbility(ability); } private GoblinVandal(final GoblinVandal card) { @@ -59,47 +52,3 @@ public final class GoblinVandal extends CardImpl { return new GoblinVandal(this); } } - -class GoblinVandalTriggeredAbility extends TriggeredAbilityImpl { - - public GoblinVandalTriggeredAbility(Effect effect) { - super(Zone.BATTLEFIELD, effect, false ); - } - - private GoblinVandalTriggeredAbility(final GoblinVandalTriggeredAbility ability) { - super(ability); - } - - @Override - public GoblinVandalTriggeredAbility copy() { - return new GoblinVandalTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DECLARED_BLOCKERS; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Permanent sourcePermanent = game.getPermanent(getSourceId()); - if (sourcePermanent.isAttacking()) { - for (CombatGroup combatGroup: game.getCombat().getGroups()) { - if (combatGroup.getBlockers().isEmpty() && combatGroup.getAttackers().contains(getSourceId())) { - UUID defendingPlayerId = game.getCombat().getDefendingPlayerId(getSourceId(), game); - FilterPermanent filter = new FilterArtifactPermanent(); - filter.add(new ControllerIdPredicate(defendingPlayerId)); - Target target = new TargetPermanent(filter); - this.addTarget(target); - return true; - } - } - } - return false; - } - - @Override - public String getRule() { - return "Whenever {this} attacks and isn't blocked, you may pay {R}. If you do, destroy target artifact defending player controls and {this} assigns no combat damage this turn."; - } -} diff --git a/Mage.Sets/src/mage/cards/g/Godsend.java b/Mage.Sets/src/mage/cards/g/Godsend.java index ccf9d841a03..7a08c002b29 100644 --- a/Mage.Sets/src/mage/cards/g/Godsend.java +++ b/Mage.Sets/src/mage/cards/g/Godsend.java @@ -23,6 +23,7 @@ import mage.game.combat.CombatGroup; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FirstTargetPointer; import mage.target.targetpointer.FixedTarget; @@ -117,7 +118,7 @@ class GodsendTriggeredAbility extends TriggeredAbilityImpl { uuidPredicates.add(new PermanentIdPredicate(creatureId)); } filter.add(Predicates.or(uuidPredicates)); - this.getTargets().add(new TargetCreaturePermanent(filter)); + this.getTargets().add(new TargetPermanent(filter)); } return true; } diff --git a/Mage.Sets/src/mage/cards/g/GodtrackerOfJund.java b/Mage.Sets/src/mage/cards/g/GodtrackerOfJund.java index b890d219e00..4bc51670d13 100644 --- a/Mage.Sets/src/mage/cards/g/GodtrackerOfJund.java +++ b/Mage.Sets/src/mage/cards/g/GodtrackerOfJund.java @@ -1,33 +1,33 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; -import mage.constants.Zone; +import mage.constants.SubType; import mage.counters.CounterType; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class GodtrackerOfJund extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature with power 5 or greater"); - + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("a creature you control with power 5 or greater"); + static { filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 4)); } public GodtrackerOfJund(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{G}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.SHAMAN); @@ -35,8 +35,9 @@ public final class GodtrackerOfJund extends CardImpl { this.toughness = new MageInt(2); // Whenever a creature with power 5 or greater you control enters, you may put a +1/+1 counter on Godtracker of Jund. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, - new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter, true)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter, true + )); } private GodtrackerOfJund(final GodtrackerOfJund card) { diff --git a/Mage.Sets/src/mage/cards/g/GoldenGuardian.java b/Mage.Sets/src/mage/cards/g/GoldenGuardian.java index d04e4c4c767..af1a5657715 100644 --- a/Mage.Sets/src/mage/cards/g/GoldenGuardian.java +++ b/Mage.Sets/src/mage/cards/g/GoldenGuardian.java @@ -1,6 +1,5 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; @@ -8,26 +7,23 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.FightTargetSourceEffect; import mage.abilities.keyword.DefenderAbility; import mage.abilities.keyword.TransformAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class GoldenGuardian extends CardImpl { @@ -46,11 +42,10 @@ public final class GoldenGuardian extends CardImpl { // {2}: Golden Guardian fights another target creature you control. When Golden Guardian dies this turn, return it to the battlefield transformed under your control. this.addAbility(new TransformAbility()); - Ability ability = new SimpleActivatedAbility(new GoldenGuardianEffect(), new GenericManaCost(2)); - ability.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + Ability ability = new SimpleActivatedAbility(new FightTargetSourceEffect(), new GenericManaCost(2)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new GoldenGuardianDelayedTriggeredAbility(), false)); this.addAbility(ability); - } private GoldenGuardian(final GoldenGuardian card) { @@ -63,36 +58,6 @@ public final class GoldenGuardian extends CardImpl { } } -class GoldenGuardianEffect extends OneShotEffect { - - GoldenGuardianEffect() { - super(Outcome.Damage); - this.staticText = "{this} fights another target creature you control"; - } - - private GoldenGuardianEffect(final GoldenGuardianEffect effect) { - super(effect); - } - - @Override - public GoldenGuardianEffect copy() { - return new GoldenGuardianEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent creature1 = game.getPermanent(source.getSourceId()); - Permanent creature2 = game.getPermanent(source.getFirstTarget()); - // 20110930 - 701.10 - if (creature1 != null && creature2 != null) { - if (creature1.isCreature(game) && creature2.isCreature(game)) { - return creature1.fight(creature2, source, game); - } - } - return false; - } -} - class GoldenGuardianDelayedTriggeredAbility extends DelayedTriggeredAbility { public GoldenGuardianDelayedTriggeredAbility() { diff --git a/Mage.Sets/src/mage/cards/g/GolemArtisan.java b/Mage.Sets/src/mage/cards/g/GolemArtisan.java index 893ec99853d..e4fbc4bc4f7 100644 --- a/Mage.Sets/src/mage/cards/g/GolemArtisan.java +++ b/Mage.Sets/src/mage/cards/g/GolemArtisan.java @@ -17,10 +17,13 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE; + /** * @author nantuko */ @@ -35,13 +38,13 @@ public final class GolemArtisan extends CardImpl { // {2}: Target artifact creature gets +1/+1 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(1, 1, Duration.EndOfTurn), new GenericManaCost(2)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_PERMANENT_ARTIFACT_CREATURE)); this.addAbility(ability); // {2}: Target artifact creature gains your choice of flying, trample, or haste until end of turn. ability = new SimpleActivatedAbility(new GainsChoiceOfAbilitiesEffect( FlyingAbility.getInstance(), TrampleAbility.getInstance(), HasteAbility.getInstance()), new GenericManaCost(2)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_PERMANENT_ARTIFACT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GoliathHatchery.java b/Mage.Sets/src/mage/cards/g/GoliathHatchery.java index 2cfe4da6bb4..a1449663878 100644 --- a/Mage.Sets/src/mage/cards/g/GoliathHatchery.java +++ b/Mage.Sets/src/mage/cards/g/GoliathHatchery.java @@ -1,13 +1,12 @@ package mage.cards.g; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CorruptedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.ToxicAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; @@ -38,11 +37,10 @@ public final class GoliathHatchery extends CardImpl { )); // Corrupted -- At the beginning of your upkeep, if an opponent has three or more poison counters, choose a creature you control, then draw cards equal to its total toxic value. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - new GoliathHatcheryEffect(), false - ).setAbilityWord(AbilityWord.CORRUPTED), CorruptedCondition.instance, null - ).addHint(CorruptedCondition.getHint())); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new GoliathHatcheryEffect()) + .withInterveningIf(CorruptedCondition.instance) + .setAbilityWord(AbilityWord.CORRUPTED) + .addHint(CorruptedCondition.getHint())); } private GoliathHatchery(final GoliathHatchery card) { @@ -59,8 +57,7 @@ class GoliathHatcheryEffect extends OneShotEffect { GoliathHatcheryEffect() { super(Outcome.Benefit); - staticText = "if an opponent has three or more poison counters, " + - "choose a creature you control, then draw cards equal to its total toxic value"; + staticText = "choose a creature you control, then draw cards equal to its total toxic value"; } private GoliathHatcheryEffect(final GoliathHatcheryEffect effect) { diff --git a/Mage.Sets/src/mage/cards/g/GollumObsessedStalker.java b/Mage.Sets/src/mage/cards/g/GollumObsessedStalker.java index f513e05e29a..03fa20978c7 100644 --- a/Mage.Sets/src/mage/cards/g/GollumObsessedStalker.java +++ b/Mage.Sets/src/mage/cards/g/GollumObsessedStalker.java @@ -1,13 +1,12 @@ package mage.cards.g; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.dynamicvalue.common.ControllerGainedLifeCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.hint.Hint; import mage.abilities.keyword.SkulkAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -63,8 +62,8 @@ public final class GollumObsessedStalker extends CardImpl { class GollumObsessedStalkerWatcher extends Watcher { - // For each creature name, the players damaged by them during combat. - private final Map> playersPerName = new HashMap<>(); + // The players damaged by anything named "Gollum, Obsessed Stalker" during combat. + private final Set playersGollumDamaged = new HashSet<>(); public GollumObsessedStalkerWatcher() { super(WatcherScope.GAME); @@ -81,18 +80,14 @@ class GollumObsessedStalkerWatcher extends Watcher { return; } - String name = creature.getName(); UUID playerId = event.getPlayerId(); - if (creature.getName().isEmpty() || playerId == null) { - return; + if (creature.getName().equals("Gollum, Obsessed Stalker") && playerId != null) { + playersGollumDamaged.add(playerId); } - - playersPerName.computeIfAbsent(name, k -> new HashSet<>()); - playersPerName.get(name).add(playerId); } - public Set getPlayersDamagedByNamed(String name) { - return playersPerName.getOrDefault(name, new HashSet<>()); + public Set getPlayersDamaged() { + return playersGollumDamaged; } } @@ -101,7 +96,7 @@ class GollumObsessedStalkerEffect extends OneShotEffect { GollumObsessedStalkerEffect() { super(Outcome.LoseLife); staticText = "each opponent dealt combat damage this game by a creature named " - + "{this} loses life equal to the amount of life you gained this turn."; + + "Gollum, Obsessed Stalker loses life equal to the amount of life you gained this turn."; } private GollumObsessedStalkerEffect(final GollumObsessedStalkerEffect effect) { @@ -122,9 +117,8 @@ class GollumObsessedStalkerEffect extends OneShotEffect { return false; } - String name = gollum.getName(); int amount = lifeWatcher.getLifeGained(source.getControllerId()); - Set playersDamaged = damageWatcher.getPlayersDamagedByNamed(name); + Set playersDamaged = damageWatcher.getPlayersDamaged(); if (amount == 0 || playersDamaged.isEmpty()) { return true; @@ -157,34 +151,17 @@ enum GollumObsessedStalkerHint implements Hint { return ""; } - String name = null; - Permanent gollum = game.getPermanentOrLKIBattlefield(ability.getSourceId()); - if (gollum != null) { - // Gollum is or was in play, its name is using LKI. - name = gollum.getName(); - } else { - // if Gollum LKI not in play (like in hand or in command zone), - // find the object. - MageObject gollumObj = game.getObject(ability.getSourceId()); - if (gollumObj != null) { - name = gollumObj.getName(); - } - } - if (name == null || name.isEmpty()) { - return ""; - } - // Not filtering by opponent intentionally, just to provide full info everywhere. List namesOfPlayersDealtDamage = - watcher.getPlayersDamagedByNamed(name) - .stream() - .map(game::getPlayer) - .filter(Objects::nonNull) - .map(Player::getName) - .filter(n -> !n.isEmpty()) - .collect(Collectors.toList()); + watcher.getPlayersDamaged() + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .map(Player::getName) + .filter(n -> !n.isEmpty()) + .collect(Collectors.toList()); - return "Players dealt combat damage by creatures named " + name + " this game: [" + return "Players dealt combat damage by creatures named Gollum, Obsessed Stalker this game: [" + String.join(", ", namesOfPlayersDealtDamage) + "]"; } diff --git a/Mage.Sets/src/mage/cards/g/GornogTheRedReaper.java b/Mage.Sets/src/mage/cards/g/GornogTheRedReaper.java index 4411563c90c..93f24e52fe4 100644 --- a/Mage.Sets/src/mage/cards/g/GornogTheRedReaper.java +++ b/Mage.Sets/src/mage/cards/g/GornogTheRedReaper.java @@ -1,7 +1,8 @@ package mage.cards.g; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.common.AttacksPlayerWithCreaturesTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; @@ -16,13 +17,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AttackingPredicate; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; -import mage.game.events.DefenderAttackedEvent; -import mage.game.events.GameEvent; import mage.target.TargetPermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; import java.util.UUID; @@ -31,16 +30,17 @@ import java.util.UUID; */ public final class GornogTheRedReaper extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.WARRIOR, "Attacking Warriors"); - private static final FilterPermanent filter2 = new FilterPermanent(SubType.COWARD, "Cowards your opponents control"); + private static final FilterPermanent filterAttackWarrior = new FilterCreaturePermanent(SubType.WARRIOR, "Attacking Warriors"); + private static final FilterPermanent filterWarrior = new FilterControlledPermanent(SubType.WARRIOR, "Warriors you control"); + private static final FilterPermanent filterCoward = new FilterPermanent(SubType.COWARD, "Cowards your opponents control"); static { - filter.add(AttackingPredicate.instance); - filter2.add(TargetController.OPPONENT.getControllerPredicate()); + filterAttackWarrior.add(AttackingPredicate.instance); + filterCoward.add(TargetController.OPPONENT.getControllerPredicate()); } - private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter2, null); - private static final Hint hint = new ValueHint(filter2.getMessage(), xValue); + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filterCoward, null); + private static final Hint hint = new ValueHint(filterCoward.getMessage(), xValue); public GornogTheRedReaper(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); @@ -58,11 +58,16 @@ public final class GornogTheRedReaper extends CardImpl { this.addAbility(new SimpleStaticAbility(new CowardsCantBlockWarriorsEffect())); // Whenever one or more Warriors you control attack a player, target creature that player controls becomes a Coward. - this.addAbility(new GornogTheRedReaperTriggeredAbility()); + Ability ability = new AttacksPlayerWithCreaturesTriggeredAbility( + new BecomesCreatureTypeTargetEffect(Duration.EndOfGame, SubType.COWARD).setText("target creature that player controls becomes a Coward"), + filterWarrior, SetTargetPointer.PLAYER); + ability.addTarget(new TargetPermanent()); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); + this.addAbility(ability); // Attacking Warriors you control get +X/+0, where X is the number of Cowards your opponents control. this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( - xValue, StaticValue.get(0), Duration.WhileOnBattlefield, filter, false + xValue, StaticValue.get(0), Duration.WhileOnBattlefield, filterAttackWarrior, false )).addHint(hint)); } @@ -75,42 +80,3 @@ public final class GornogTheRedReaper extends CardImpl { return new GornogTheRedReaper(this); } } - -class GornogTheRedReaperTriggeredAbility extends TriggeredAbilityImpl { - - GornogTheRedReaperTriggeredAbility() { - super(Zone.BATTLEFIELD, new BecomesCreatureTypeTargetEffect(Duration.EndOfGame, SubType.COWARD) - .setText("target creature that player controls becomes a Coward")); - this.setTriggerPhrase("Whenever one or more Warriors you control attack a player, "); - } - - private GornogTheRedReaperTriggeredAbility(final GornogTheRedReaperTriggeredAbility ability) { - super(ability); - } - - @Override - public GornogTheRedReaperTriggeredAbility copy() { - return new GornogTheRedReaperTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DEFENDER_ATTACKED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (game.getPlayer(event.getTargetId()) == null - || ((DefenderAttackedEvent) event) - .getAttackers(game) - .stream() - .noneMatch(p -> p.hasSubtype(SubType.WARRIOR, game) && p.isControlledBy(getControllerId()))) { - return false; - } - FilterPermanent filter = new FilterCreaturePermanent("creature controlled by defending player"); - filter.add(new ControllerIdPredicate(event.getTargetId())); - this.getTargets().clear(); - this.addTarget(new TargetPermanent(filter)); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/g/GoroGoroDiscipleOfRyusei.java b/Mage.Sets/src/mage/cards/g/GoroGoroDiscipleOfRyusei.java index 2ea296d1457..0a5ab3cfd16 100644 --- a/Mage.Sets/src/mage/cards/g/GoroGoroDiscipleOfRyusei.java +++ b/Mage.Sets/src/mage/cards/g/GoroGoroDiscipleOfRyusei.java @@ -5,7 +5,7 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.hint.ConditionHint; @@ -13,7 +13,10 @@ import mage.abilities.hint.Hint; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; @@ -29,7 +32,7 @@ import java.util.UUID; public final class GoroGoroDiscipleOfRyusei extends CardImpl { private static final FilterPermanent filter - = new FilterControlledCreaturePermanent("if you control an attacking modified creature"); + = new FilterControlledCreaturePermanent("you control an attacking modified creature"); static { filter.add(AttackingPredicate.instance); @@ -37,9 +40,7 @@ public final class GoroGoroDiscipleOfRyusei extends CardImpl { } private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); - private static final Hint hint = new ConditionHint( - condition, "You control and attacking modified creature" - ); + private static final Hint hint = new ConditionHint(condition); public GoroGoroDiscipleOfRyusei(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); @@ -57,8 +58,8 @@ public final class GoroGoroDiscipleOfRyusei extends CardImpl { ), new ManaCostsImpl<>("{R}"))); // {3}{R}{R}: Create a 5/5 red Dragon Spirit creature token with flying. Activate only if you control an attacking modified creature. - this.addAbility(new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new CreateTokenEffect(new DragonSpiritToken()), + this.addAbility(new ActivateIfConditionActivatedAbility( + new CreateTokenEffect(new DragonSpiritToken()), new ManaCostsImpl<>("{3}{R}{R}"), condition ).addHint(hint)); } diff --git a/Mage.Sets/src/mage/cards/g/GossamerChains.java b/Mage.Sets/src/mage/cards/g/GossamerChains.java index 56afe0a9dba..5cc3c833f3a 100644 --- a/Mage.Sets/src/mage/cards/g/GossamerChains.java +++ b/Mage.Sets/src/mage/cards/g/GossamerChains.java @@ -13,6 +13,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.UnblockedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -32,7 +33,7 @@ public final class GossamerChains extends CardImpl { // Return Gossamer Chains to its owner's hand: Prevent all combat damage that would be dealt by target unblocked creature this turn. Ability ability = new SimpleActivatedAbility(new PreventDamageByTargetEffect(Duration.EndOfTurn, true), new ReturnToHandFromBattlefieldSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GougedZealot.java b/Mage.Sets/src/mage/cards/g/GougedZealot.java index e0bb7822c98..4c573cf9ca6 100644 --- a/Mage.Sets/src/mage/cards/g/GougedZealot.java +++ b/Mage.Sets/src/mage/cards/g/GougedZealot.java @@ -3,12 +3,12 @@ package mage.cards.g; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.DamageAllControlledTargetEffect; import mage.abilities.keyword.ReachAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SetTargetPointer; import mage.constants.SubType; @@ -16,7 +16,6 @@ import mage.constants.SubType; import java.util.UUID; /** - * * @author weirddan455 */ public final class GougedZealot extends CardImpl { @@ -33,11 +32,11 @@ public final class GougedZealot extends CardImpl { this.addAbility(ReachAbility.getInstance()); // Delirium — Whenever Gouged Zealot attacks, if there are four or more card types among cards in your graveyard, Gouged Zealot deals 1 damage to each creature defending player controls. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new DamageAllControlledTargetEffect(1), false, null, SetTargetPointer.PLAYER), - DeliriumCondition.instance, - "Delirium — Whenever {this} attacks, if there are four or more card types among cards in your graveyard, {this} deals 1 damage to each creature defending player controls." - ).addHint(CardTypesInGraveyardCount.YOU.getHint())); + this.addAbility(new AttacksTriggeredAbility( + new DamageAllControlledTargetEffect(1) + .setText("{this} deals 1 damage to each creature defending player controls"), + false, null, SetTargetPointer.PLAYER + ).withInterveningIf(DeliriumCondition.instance).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); } private GougedZealot(final GougedZealot card) { diff --git a/Mage.Sets/src/mage/cards/g/GovernTheGuildless.java b/Mage.Sets/src/mage/cards/g/GovernTheGuildless.java index 81e25b92ed2..73ee79d0453 100644 --- a/Mage.Sets/src/mage/cards/g/GovernTheGuildless.java +++ b/Mage.Sets/src/mage/cards/g/GovernTheGuildless.java @@ -12,6 +12,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.MonocoloredPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -31,7 +32,7 @@ public final class GovernTheGuildless extends CardImpl { // Gain control of target monocolored creature. this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.Custom)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Forecast - {1}{U}, Reveal Govern the Guildless from your hand: Target creature becomes the color or colors of your choice until end of turn. ForecastAbility ability = new ForecastAbility(new BecomesColorOrColorsTargetEffect(Duration.EndOfTurn), new ManaCostsImpl<>("{1}{U}")); diff --git a/Mage.Sets/src/mage/cards/g/GrafRats.java b/Mage.Sets/src/mage/cards/g/GrafRats.java index 5b37662a5df..6715c1b3c80 100644 --- a/Mage.Sets/src/mage/cards/g/GrafRats.java +++ b/Mage.Sets/src/mage/cards/g/GrafRats.java @@ -1,11 +1,10 @@ package mage.cards.g; import mage.MageInt; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.MeldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.MeldEffect; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -30,13 +29,9 @@ public final class GrafRats extends CardImpl { this.meldsToClazz = mage.cards.c.ChitteringHost.class; // At the beginning of combat on your turn, if you both own and control Graf Rats and a creature named Midnight Scavengers, exile them, then meld them into Chittering Host. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility(new MeldEffect( - "Midnight Scavengers", "Chittering Host" - )), condition, "At the beginning " + - "of combat on your turn, if you both own and control {this} and a creature " + - "named Midnight Scavengers, exile them, then meld them into Chittering Host." - )); + this.addAbility(new BeginningOfCombatTriggeredAbility(new MeldEffect( + "Midnight Scavengers", "Chittering Host" + )).withInterveningIf(condition)); } private GrafRats(final GrafRats card) { diff --git a/Mage.Sets/src/mage/cards/g/GrandArchitect.java b/Mage.Sets/src/mage/cards/g/GrandArchitect.java index e21d3124bc3..99f2d0e2372 100644 --- a/Mage.Sets/src/mage/cards/g/GrandArchitect.java +++ b/Mage.Sets/src/mage/cards/g/GrandArchitect.java @@ -17,13 +17,13 @@ import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; -import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; @@ -33,7 +33,7 @@ import java.util.UUID; public final class GrandArchitect extends CardImpl { private static final FilterCreaturePermanent boostFilter = new FilterCreaturePermanent("blue creatures"); - private static final FilterControlledCreaturePermanent tapFilter = new FilterControlledCreaturePermanent("untapped blue creature you control"); + private static final FilterControlledPermanent tapFilter = new FilterControlledCreaturePermanent("untapped blue creature you control"); static { boostFilter.add(new ColorPredicate(ObjectColor.BLUE)); @@ -108,9 +108,8 @@ class GrandArchitectManaAbility extends ActivatedManaAbilityImpl { private final FilterPermanent filter; - GrandArchitectManaAbility(FilterControlledCreaturePermanent filter) { - super(Zone.BATTLEFIELD, new BasicManaEffect(new GrandArchitectConditionalMana()), - new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, true))); + GrandArchitectManaAbility(FilterControlledPermanent filter) { + super(Zone.BATTLEFIELD, new BasicManaEffect(new GrandArchitectConditionalMana()), new TapTargetCost(filter)); this.netMana.add(new GrandArchitectConditionalMana()); this.filter = filter; } diff --git a/Mage.Sets/src/mage/cards/g/GrapeshotCatapult.java b/Mage.Sets/src/mage/cards/g/GrapeshotCatapult.java index 12561052632..ae8d84dce82 100644 --- a/Mage.Sets/src/mage/cards/g/GrapeshotCatapult.java +++ b/Mage.Sets/src/mage/cards/g/GrapeshotCatapult.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class GrapeshotCatapult extends CardImpl { // {tap}: Grapeshot Catapult deals 1 damage to target creature with flying. Ability activatedAbility = new SimpleActivatedAbility(new DamageTargetEffect(1), new TapSourceCost()); - activatedAbility.addTarget(new TargetCreaturePermanent(filter)); + activatedAbility.addTarget(new TargetPermanent(filter)); this.addAbility(activatedAbility); } diff --git a/Mage.Sets/src/mage/cards/g/GraspOfTheHieromancer.java b/Mage.Sets/src/mage/cards/g/GraspOfTheHieromancer.java index 13ce22155bc..2aafbb2a977 100644 --- a/Mage.Sets/src/mage/cards/g/GraspOfTheHieromancer.java +++ b/Mage.Sets/src/mage/cards/g/GraspOfTheHieromancer.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleStaticAbility; @@ -13,12 +11,7 @@ import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AttachmentType; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; @@ -26,14 +19,15 @@ import mage.game.events.GameEvent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class GraspOfTheHieromancer extends CardImpl { public GraspOfTheHieromancer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); this.subtype.add(SubType.AURA); // Enchant creature @@ -42,18 +36,18 @@ public final class GraspOfTheHieromancer extends CardImpl { this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); Ability ability = new EnchantAbility(auraTarget); this.addAbility(ability); - + // Enchanted creature gets +1/+1 and has "Whenever this creature attacks, tap target creature defending player controls." ability = new SimpleStaticAbility(new BoostEnchantedEffect(1, 1, Duration.WhileOnBattlefield)); - Ability gainedAbility = new GraspOfTheHieromancerTriggeredAbility(new TapTargetEffect(), false); - gainedAbility.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature defending player controls"))); + Ability gainedAbility = new GraspOfTheHieromancerTriggeredAbility(new TapTargetEffect(), false); + gainedAbility.addTarget(new TargetPermanent(new FilterCreaturePermanent("creature defending player controls"))); Effect effect = new GainAbilityAttachedEffect(gainedAbility, AttachmentType.AURA); effect.setText("and has \"Whenever this creature attacks, tap target creature defending player controls.\""); ability.addEffect(effect); this.addAbility(ability); - + } - + private GraspOfTheHieromancer(final GraspOfTheHieromancer card) { super(card); } @@ -65,9 +59,8 @@ public final class GraspOfTheHieromancer extends CardImpl { } class GraspOfTheHieromancerTriggeredAbility extends TriggeredAbilityImpl { - - + public GraspOfTheHieromancerTriggeredAbility(Effect effect, boolean optional) { super(Zone.BATTLEFIELD, effect, optional); } @@ -83,17 +76,16 @@ class GraspOfTheHieromancerTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (game.getCombat().getAttackers().contains(getSourceId()) ) { + if (game.getCombat().getAttackers().contains(getSourceId())) { UUID defendingPlayerId = game.getCombat().getDefendingPlayerId(getSourceId(), game); - if (defendingPlayerId != null) { + if (defendingPlayerId != null) { this.getTargets().clear(); FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); UUID defenderId = game.getCombat().getDefenderId(getSourceId()); filter.add(new ControllerIdPredicate(defenderId)); - TargetCreaturePermanent target = new TargetCreaturePermanent(filter); - this.addTarget(target); + this.addTarget(new TargetPermanent(filter)); return true; - } + } } return false; } diff --git a/Mage.Sets/src/mage/cards/g/GrasslandCrusader.java b/Mage.Sets/src/mage/cards/g/GrasslandCrusader.java index 0536fa34cb4..64dc8f3e3a2 100644 --- a/Mage.Sets/src/mage/cards/g/GrasslandCrusader.java +++ b/Mage.Sets/src/mage/cards/g/GrasslandCrusader.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class GrasslandCrusader extends CardImpl { // {tap}: Target Elf or Soldier creature gets +2/+2 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(2, 2, Duration.EndOfTurn), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GravePeril.java b/Mage.Sets/src/mage/cards/g/GravePeril.java index ab662134f50..5db7ed7787f 100644 --- a/Mage.Sets/src/mage/cards/g/GravePeril.java +++ b/Mage.Sets/src/mage/cards/g/GravePeril.java @@ -1,6 +1,5 @@ package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.Effect; @@ -16,14 +15,15 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author emerald000 */ public final class GravePeril extends CardImpl { public GravePeril(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); // When a nonblack creature enters the battlefield, sacrifice Grave Peril. If you do, destroy that creature. this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new GravePerilEffect(), StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK, false, SetTargetPointer.PERMANENT).setTriggerPhrase("When a nonblack creature enters, ")); @@ -43,7 +43,7 @@ class GravePerilEffect extends OneShotEffect { GravePerilEffect() { super(Outcome.DestroyPermanent); - this.staticText = "sacrifice Grave Peril. If you do, destroy that creature"; + this.staticText = "sacrifice {this}. If you do, destroy that creature"; } private GravePerilEffect(final GravePerilEffect effect) { diff --git a/Mage.Sets/src/mage/cards/g/GraveScrabbler.java b/Mage.Sets/src/mage/cards/g/GraveScrabbler.java index 2eb04dcdb6b..d03ead0c285 100644 --- a/Mage.Sets/src/mage/cards/g/GraveScrabbler.java +++ b/Mage.Sets/src/mage/cards/g/GraveScrabbler.java @@ -1,22 +1,25 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.MadnessAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; import mage.target.common.TargetCardInGraveyard; +import java.util.UUID; + public final class GraveScrabbler extends CardImpl { + private static final FilterCard filter = new FilterCreatureCard("creature card from a graveyard"); + public GraveScrabbler(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.subtype.add(SubType.ZOMBIE); @@ -24,15 +27,14 @@ public final class GraveScrabbler extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); - //Madness {1}{B} + // Madness {1}{B} this.addAbility(new MadnessAbility(new ManaCostsImpl<>("{1}{B}"))); - //When Grave Scrabbler enters the battlefield, if its madness cost was paid, - //you may return target creature card from a graveyard to its owner's hand. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); - ability.addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card in a graveyard"))); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, MadnessAbility.getCondition(), - "When {this} enters, if its madness cost was paid, you may return target creature card from a graveyard to its owner's hand.")); + // When Grave Scrabbler enters the battlefield, if its madness cost was paid, you may return target creature card from a graveyard to its owner's hand. + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true) + .withInterveningIf(MadnessAbility.getCondition()); + ability.addTarget(new TargetCardInGraveyard(filter)); + this.addAbility(ability); } private GraveScrabbler(final GraveScrabbler card) { diff --git a/Mage.Sets/src/mage/cards/g/GravelSlinger.java b/Mage.Sets/src/mage/cards/g/GravelSlinger.java index ab01098cca4..8f40f40e767 100644 --- a/Mage.Sets/src/mage/cards/g/GravelSlinger.java +++ b/Mage.Sets/src/mage/cards/g/GravelSlinger.java @@ -15,6 +15,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterAttackingOrBlockingCreature; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -32,7 +33,7 @@ public final class GravelSlinger extends CardImpl { // {tap}: Gravel Slinger deals 1 damage to target attacking or blocking creature. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(new FilterAttackingOrBlockingCreature())); + ability.addTarget(new TargetPermanent(new FilterAttackingOrBlockingCreature())); this.addAbility(ability); // Morph {1}{W} this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{1}{W}"))); diff --git a/Mage.Sets/src/mage/cards/g/Gravelighter.java b/Mage.Sets/src/mage/cards/g/Gravelighter.java index ff42e68b7d9..2f492cd509a 100644 --- a/Mage.Sets/src/mage/cards/g/Gravelighter.java +++ b/Mage.Sets/src/mage/cards/g/Gravelighter.java @@ -36,7 +36,7 @@ public final class Gravelighter extends CardImpl { new DrawCardSourceControllerEffect(1), new SacrificeAllEffect(StaticFilters.FILTER_PERMANENT_CREATURE), MorbidCondition.instance, "draw a card if a creature died this turn. " + - "Otherwise, each player sacrifices a creature" + "Otherwise, each player sacrifices a creature of their choice" )).addHint(MorbidHint.instance)); } diff --git a/Mage.Sets/src/mage/cards/g/GravespawnSovereign.java b/Mage.Sets/src/mage/cards/g/GravespawnSovereign.java index 126f0f857cf..fd0955b3970 100644 --- a/Mage.Sets/src/mage/cards/g/GravespawnSovereign.java +++ b/Mage.Sets/src/mage/cards/g/GravespawnSovereign.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -11,21 +9,20 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterCreatureCard; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.target.common.TargetCardInGraveyard; -import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class GravespawnSovereign extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Zombies you control"); + private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("untapped Zombies you control"); static { filter.add(SubType.ZOMBIE.getPredicate()); @@ -39,10 +36,11 @@ public final class GravespawnSovereign extends CardImpl { this.toughness = new MageInt(3); // Tap five untapped Zombies you control: Put target creature card from a graveyard onto the battlefield under your control. - Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), new TapTargetCost(new TargetControlledCreaturePermanent(5, 5, filter, true))); + Ability ability = new SimpleActivatedAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect(), new TapTargetCost(5, filter) + ); ability.addTarget(new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURE_A_GRAVEYARD)); this.addAbility(ability); - } private GravespawnSovereign(final GravespawnSovereign card) { diff --git a/Mage.Sets/src/mage/cards/g/GravityNegator.java b/Mage.Sets/src/mage/cards/g/GravityNegator.java index 8b90a1c8ba7..5d908c291a2 100644 --- a/Mage.Sets/src/mage/cards/g/GravityNegator.java +++ b/Mage.Sets/src/mage/cards/g/GravityNegator.java @@ -16,8 +16,11 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Duration; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * * @author fireshoes @@ -40,7 +43,7 @@ public final class GravityNegator extends CardImpl { // Whenenever Gravity Negator attacks, you may pay {C}. If you do, another target creature gains flying until end of turn. Ability ability = new AttacksTriggeredAbility(new DoIfCostPaid(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{C}")), false, "Whenever {this} attacks, you may pay {C}. If you do, another target creature gains flying until end of turn."); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GreaterGargadon.java b/Mage.Sets/src/mage/cards/g/GreaterGargadon.java index 73ea8940947..6afb1ceb7ef 100644 --- a/Mage.Sets/src/mage/cards/g/GreaterGargadon.java +++ b/Mage.Sets/src/mage/cards/g/GreaterGargadon.java @@ -1,7 +1,6 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.ActivatedAbilityImpl; import mage.abilities.costs.common.SacrificeTargetCost; @@ -18,7 +17,8 @@ import mage.counters.CounterType; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.game.Game; -import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; /** * @@ -81,6 +81,6 @@ class GreaterGargadonAbility extends ActivatedAbilityImpl { @Override public String getRule() { - return super.getRule() + " Activate only if Greater Gargadon is suspended."; + return super.getRule() + " Activate only if {this} is suspended."; } } diff --git a/Mage.Sets/src/mage/cards/g/GreenerPastures.java b/Mage.Sets/src/mage/cards/g/GreenerPastures.java index 41af30b83f1..91388dce603 100644 --- a/Mage.Sets/src/mage/cards/g/GreenerPastures.java +++ b/Mage.Sets/src/mage/cards/g/GreenerPastures.java @@ -1,9 +1,9 @@ package mage.cards.g; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.effects.common.CreateTokenTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -16,7 +16,6 @@ import mage.players.Player; import java.util.UUID; /** - * * @author TheElk801 */ public final class GreenerPastures extends CardImpl { @@ -26,7 +25,7 @@ public final class GreenerPastures extends CardImpl { // At the beginning of each player's upkeep, if that player controls more lands than each other player, the player creates a 1/1 green Saproling creature token. this.addAbility(new BeginningOfUpkeepTriggeredAbility( - TargetController.EACH_PLAYER, new CreateTokenTargetEffect(new SaprolingToken()), + TargetController.EACH_PLAYER, new CreateTokenTargetEffect(new SaprolingToken()).setText("the player creates a 1/1 green Saproling creature token"), false ).withInterveningIf(ActivePlayerMostLandsCondition.instance)); } diff --git a/Mage.Sets/src/mage/cards/g/GreenhiltTrainee.java b/Mage.Sets/src/mage/cards/g/GreenhiltTrainee.java index 31122f6b718..7c985e7530f 100644 --- a/Mage.Sets/src/mage/cards/g/GreenhiltTrainee.java +++ b/Mage.Sets/src/mage/cards/g/GreenhiltTrainee.java @@ -11,7 +11,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; @@ -30,8 +29,9 @@ public final class GreenhiltTrainee extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(3); + Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new BoostTargetEffect(4, 4, Duration.EndOfTurn), + new BoostTargetEffect(4, 4, Duration.EndOfTurn), new TapSourceCost(), GreenhiltTraineeCondition.instance ); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/g/GrenzoHavocRaiser.java b/Mage.Sets/src/mage/cards/g/GrenzoHavocRaiser.java index 755c7b2dc10..2f5e42808ec 100644 --- a/Mage.Sets/src/mage/cards/g/GrenzoHavocRaiser.java +++ b/Mage.Sets/src/mage/cards/g/GrenzoHavocRaiser.java @@ -19,7 +19,9 @@ import mage.game.events.DamagedEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.DefineByTriggerTargetAdjuster; import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; @@ -69,6 +71,7 @@ class GrenzoHavocRaiserTriggeredAbility extends TriggeredAbilityImpl { public GrenzoHavocRaiserTriggeredAbility(Effect effect) { super(Zone.BATTLEFIELD, effect, false); setTriggerPhrase("Whenever a creature you control deals combat damage to a player, "); + setTargetAdjuster(DefineByTriggerTargetAdjuster.instance); } private GrenzoHavocRaiserTriggeredAbility(final GrenzoHavocRaiserTriggeredAbility ability) { @@ -107,7 +110,7 @@ class GrenzoHavocRaiserTriggeredAbility extends TriggeredAbilityImpl { FilterCreaturePermanent filter = new FilterCreaturePermanent("creature " + damagedPlayer.getLogName() + " controls"); filter.add(new ControllerIdPredicate(damagedPlayer.getId())); this.getTargets().clear(); - this.addTarget(new TargetCreaturePermanent(filter)); + this.addTarget(new TargetPermanent(filter)); for (Effect effect : this.getAllEffects()) { if (effect instanceof GrenzoHavocRaiserEffect) { effect.setTargetPointer(new FixedTarget(event.getPlayerId())); diff --git a/Mage.Sets/src/mage/cards/g/GriffinAerie.java b/Mage.Sets/src/mage/cards/g/GriffinAerie.java index 2c23807b080..95c852f9c70 100644 --- a/Mage.Sets/src/mage/cards/g/GriffinAerie.java +++ b/Mage.Sets/src/mage/cards/g/GriffinAerie.java @@ -1,12 +1,10 @@ package mage.cards.g; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.YouGainedLifeCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.common.ControllerGainedLifeCount; import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.hint.ConditionHint; -import mage.abilities.hint.Hint; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -22,18 +20,13 @@ import java.util.UUID; public final class GriffinAerie extends CardImpl { private static final Condition condition = new YouGainedLifeCondition(ComparisonType.MORE_THAN, 2); - private static final Hint hint = new ConditionHint(condition, "You gained 3 or more life this turn"); public GriffinAerie(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); // At the beginning of your end step, if you gained 3 or more life this turn, create a 2/2 white Griffin creature token with flying. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - new CreateTokenEffect(new GriffinToken()) - ), condition, "At the beginning of your end step, " + - "if you gained 3 or more life this turn, create a 2/2 white Griffin creature token with flying." - ).addHint(hint), new PlayerGainedLifeWatcher()); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new CreateTokenEffect(new GriffinToken())) + .withInterveningIf(condition).addHint(ControllerGainedLifeCount.getHint()), new PlayerGainedLifeWatcher()); } private GriffinAerie(final GriffinAerie card) { diff --git a/Mage.Sets/src/mage/cards/g/GrimPoppet.java b/Mage.Sets/src/mage/cards/g/GrimPoppet.java index c55993e5700..dd090b52cb8 100644 --- a/Mage.Sets/src/mage/cards/g/GrimPoppet.java +++ b/Mage.Sets/src/mage/cards/g/GrimPoppet.java @@ -17,6 +17,7 @@ import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -42,7 +43,7 @@ public final class GrimPoppet extends CardImpl { // Remove a -1/-1 counter from Grim Poppet: Put a -1/-1 counter on another target creature. Ability ability = new SimpleActivatedAbility(new AddCountersTargetEffect(CounterType.M1M1.createInstance()), new RemoveCountersSourceCost(CounterType.M1M1.createInstance())); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GrimReminder.java b/Mage.Sets/src/mage/cards/g/GrimReminder.java index 3da95e7a63e..3a2c509bb2c 100644 --- a/Mage.Sets/src/mage/cards/g/GrimReminder.java +++ b/Mage.Sets/src/mage/cards/g/GrimReminder.java @@ -1,27 +1,15 @@ - package mage.cards.g; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; -import mage.abilities.effects.common.ReturnToHandSourceEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.PhaseStep; import mage.constants.WatcherScope; import mage.constants.Zone; import mage.filter.StaticFilters; @@ -31,8 +19,9 @@ import mage.players.Player; import mage.target.common.TargetCardInLibrary; import mage.watchers.Watcher; +import java.util.*; + /** - * * @author TheElk801 */ public final class GrimReminder extends CardImpl { @@ -45,12 +34,9 @@ public final class GrimReminder extends CardImpl { this.getSpellAbility().addWatcher(new GrimReminderWatcher()); // {B}{B}: Return Grim Reminder from your graveyard to your hand. Activate this ability only during your upkeep. - this.addAbility(new ConditionalActivatedAbility( - Zone.GRAVEYARD, - new ReturnSourceFromGraveyardToHandEffect(), - new ManaCostsImpl<>("{B}{B}"), - new IsStepCondition(PhaseStep.UPKEEP), - null + this.addAbility(new ActivateIfConditionActivatedAbility( + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), + new ManaCostsImpl<>("{B}{B}"), IsStepCondition.getMyUpkeep() )); } diff --git a/Mage.Sets/src/mage/cards/g/GrimgrinCorpseBorn.java b/Mage.Sets/src/mage/cards/g/GrimgrinCorpseBorn.java index b462f8fddc2..c84496798d5 100644 --- a/Mage.Sets/src/mage/cards/g/GrimgrinCorpseBorn.java +++ b/Mage.Sets/src/mage/cards/g/GrimgrinCorpseBorn.java @@ -20,6 +20,7 @@ import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; @@ -60,7 +61,7 @@ public final class GrimgrinCorpseBorn extends CardImpl { // Whenever Grimgrin attacks, destroy target creature defending player controls, then put a +1/+1 counter on Grimgrin. ability = new AttacksTriggeredAbility(new DestroyTargetEffect()); ability.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance()).concatBy(", then")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GrindDust.java b/Mage.Sets/src/mage/cards/g/GrindDust.java index 38b34a7fc46..7f11a2d869d 100644 --- a/Mage.Sets/src/mage/cards/g/GrindDust.java +++ b/Mage.Sets/src/mage/cards/g/GrindDust.java @@ -1,8 +1,5 @@ - package mage.cards.g; -import java.util.UUID; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.AftermathAbility; @@ -11,34 +8,40 @@ import mage.cards.SplitCard; import mage.constants.CardType; import mage.constants.SpellAbilityType; import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class GrindDust extends SplitCard { + private static final FilterPermanent filter = new FilterCreaturePermanent("creatures that have -1/-1 counters on them"); + + static { + filter.add(CounterType.M1M1.getPredicate()); + } + public GrindDust(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, new CardType[]{CardType.SORCERY}, "{1}{B}", "{3}{W}", SpellAbilityType.SPLIT_AFTERMATH); // Grind // Put a -1/-1 counter on each of up to two target creatures. - Effect effect = new AddCountersTargetEffect(CounterType.M1M1.createInstance()); - effect.setText("Put a -1/-1 counter on each of up to two target creatures"); - getLeftHalfCard().getSpellAbility().addEffect(effect); - getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2)); + this.getLeftHalfCard().getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.M1M1.createInstance()) + .setText("Put a -1/-1 counter on each of up to two target creatures")); + this.getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2)); // Dust // Aftermath - getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); - // Exile any number of target creatures that have -1/-1 counters on them. - getRightHalfCard().getSpellAbility().addEffect(new ExileTargetEffect()); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures that have -1/-1 counters on them"); - filter.add(CounterType.M1M1.getPredicate()); - getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, false)); + this.getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); + // Exile any number of target creatures that have -1/-1 counters on them. + this.getRightHalfCard().getSpellAbility().addEffect(new ExileTargetEffect()); + this.getRightHalfCard().getSpellAbility().addTarget(new TargetPermanent(0, Integer.MAX_VALUE, filter)); } private GrindDust(final GrindDust card) { diff --git a/Mage.Sets/src/mage/cards/g/GrotagSiegeRunner.java b/Mage.Sets/src/mage/cards/g/GrotagSiegeRunner.java index cde46db7dc5..83930a294c6 100644 --- a/Mage.Sets/src/mage/cards/g/GrotagSiegeRunner.java +++ b/Mage.Sets/src/mage/cards/g/GrotagSiegeRunner.java @@ -16,6 +16,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -44,7 +45,7 @@ public final class GrotagSiegeRunner extends CardImpl { Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{R}")); ability.addCost(new SacrificeSourceCost()); ability.addEffect(new DamageTargetControllerEffect(2)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GroundRift.java b/Mage.Sets/src/mage/cards/g/GroundRift.java index 7e355382293..b99262affd7 100644 --- a/Mage.Sets/src/mage/cards/g/GroundRift.java +++ b/Mage.Sets/src/mage/cards/g/GroundRift.java @@ -12,6 +12,7 @@ import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -31,7 +32,7 @@ public final class GroundRift extends CardImpl { // Target creature without flying can't block this turn. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new CantBlockTargetEffect(Duration.EndOfTurn)); // Storm this.addAbility(new StormAbility()); diff --git a/Mage.Sets/src/mage/cards/g/GroveOfTheBurnwillows.java b/Mage.Sets/src/mage/cards/g/GroveOfTheBurnwillows.java index 616a8ec8b8a..88f33581be5 100644 --- a/Mage.Sets/src/mage/cards/g/GroveOfTheBurnwillows.java +++ b/Mage.Sets/src/mage/cards/g/GroveOfTheBurnwillows.java @@ -1,37 +1,35 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GainLifeAllEffect; import mage.abilities.mana.ColorlessManaAbility; import mage.abilities.mana.GreenManaAbility; import mage.abilities.mana.RedManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.game.Game; -import mage.players.Player; +import mage.constants.TargetController; + +import java.util.UUID; /** - * * @author jonubuu */ public final class GroveOfTheBurnwillows extends CardImpl { public GroveOfTheBurnwillows(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // {tap}: Add {C}. this.addAbility(new ColorlessManaAbility()); + // {tap}: Add {R} or {G}. Each opponent gains 1 life. - Ability RedManaAbility = new RedManaAbility(); - RedManaAbility.addEffect(new GroveOfTheBurnwillowsEffect()); - this.addAbility(RedManaAbility); - Ability GreenManaAbility = new GreenManaAbility(); - GreenManaAbility.addEffect(new GroveOfTheBurnwillowsEffect()); - this.addAbility(GreenManaAbility); + Ability ability = new RedManaAbility(); + ability.addEffect(new GainLifeAllEffect(1, TargetController.OPPONENT)); + this.addAbility(ability); + ability = new GreenManaAbility(); + ability.addEffect(new GainLifeAllEffect(1, TargetController.OPPONENT)); + this.addAbility(ability); } private GroveOfTheBurnwillows(final GroveOfTheBurnwillows card) { @@ -43,31 +41,3 @@ public final class GroveOfTheBurnwillows extends CardImpl { return new GroveOfTheBurnwillows(this); } } - -class GroveOfTheBurnwillowsEffect extends OneShotEffect { - - GroveOfTheBurnwillowsEffect() { - super(Outcome.Benefit); - staticText = "Each opponent gains 1 life"; - } - - private GroveOfTheBurnwillowsEffect(final GroveOfTheBurnwillowsEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - for (UUID playerId : game.getOpponents(source.getControllerId())) { - Player player = game.getPlayer(playerId); - if(player != null) { - player.gainLife(1, game, source); - } - } - return true; - } - - @Override - public GroveOfTheBurnwillowsEffect copy() { - return new GroveOfTheBurnwillowsEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GroveOfTheGuardian.java b/Mage.Sets/src/mage/cards/g/GroveOfTheGuardian.java index d2623292303..1da7365b6c4 100644 --- a/Mage.Sets/src/mage/cards/g/GroveOfTheGuardian.java +++ b/Mage.Sets/src/mage/cards/g/GroveOfTheGuardian.java @@ -13,10 +13,8 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; +import mage.filter.StaticFilters; import mage.game.permanent.token.GreenAndWhiteElementalToken; -import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; @@ -25,12 +23,6 @@ import java.util.UUID; */ public final class GroveOfTheGuardian extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); - - static { - filter.add(TappedPredicate.UNTAPPED); - } - public GroveOfTheGuardian(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); @@ -40,7 +32,7 @@ public final class GroveOfTheGuardian extends CardImpl { // {3}{G}{W}, {T}, Tap two untapped creatures you control, Sacrifice Grove of the Guardian: Create an 8/8 green and white Elemental creature token with vigilance. Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new GreenAndWhiteElementalToken(), 1), new ManaCostsImpl<>("{3}{G}{W}")); ability.addCost(new TapSourceCost()); - ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(2, 2, filter, false))); + ability.addCost(new TapTargetCost(2, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES)); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GrowingRitesOfItlimoc.java b/Mage.Sets/src/mage/cards/g/GrowingRitesOfItlimoc.java index e4f6c554687..cbc80fc495e 100644 --- a/Mage.Sets/src/mage/cards/g/GrowingRitesOfItlimoc.java +++ b/Mage.Sets/src/mage/cards/g/GrowingRitesOfItlimoc.java @@ -1,24 +1,34 @@ package mage.cards.g; -import java.util.UUID; - -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.abilities.keyword.TransformAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.PutCards; +import mage.constants.SuperType; import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; + +import java.util.UUID; /** * @author JRHerlehy */ public final class GrowingRitesOfItlimoc extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledCreaturePermanent("you control four or more creatures"), + ComparisonType.MORE_THAN, 3 + ); + public GrowingRitesOfItlimoc(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); @@ -30,14 +40,13 @@ public final class GrowingRitesOfItlimoc extends CardImpl { // You may reveal a creature card from among them and put it into your hand. // Put the rest on the bottom of your library in any order. this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( - 4, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_ANY))); + 4, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_ANY + ))); // At the beginning of your end step, if you control four or more creatures, transform Growing Rites of Itlimoc. this.addAbility(new TransformAbility()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility(new TransformSourceEffect()), - new PermanentsOnTheBattlefieldCondition(StaticFilters.FILTER_CONTROLLED_A_CREATURE, ComparisonType.MORE_THAN, 3), - "At the beginning of your end step, if you control four or more creatures, transform {this}")); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new TransformSourceEffect()) + .withInterveningIf(condition).addHint(CreaturesYouControlHint.instance)); } private GrowingRitesOfItlimoc(final GrowingRitesOfItlimoc card) { diff --git a/Mage.Sets/src/mage/cards/g/GruffTriplets.java b/Mage.Sets/src/mage/cards/g/GruffTriplets.java index 3cc9396f980..134ab775e69 100644 --- a/Mage.Sets/src/mage/cards/g/GruffTriplets.java +++ b/Mage.Sets/src/mage/cards/g/GruffTriplets.java @@ -3,8 +3,8 @@ package mage.cards.g; import mage.MageInt; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.SourcePermanentPowerValue; import mage.abilities.effects.CreateTokenCopySourceEffect; import mage.abilities.effects.common.counter.AddCountersAllEffect; @@ -26,14 +26,16 @@ import java.util.UUID; */ public final class GruffTriplets extends CardImpl { - private static final FilterPermanent filterNonToken = new FilterPermanent("non-token permanent"); - private static final FilterControlledPermanent filterNamedGruffTriplets = new FilterControlledPermanent("creature you control named Gruff Triplets"); + private static final FilterPermanent filterNonToken = new FilterPermanent("it isn't a token"); + private static final FilterPermanent filterNamedGruffTriplets = new FilterControlledPermanent("creature you control named Gruff Triplets"); static { filterNonToken.add(TokenPredicate.FALSE); filterNamedGruffTriplets.add(new NamePredicate("Gruff Triplets")); } + private static final Condition condition = new SourceMatchesFilterCondition(filterNonToken); + public GruffTriplets(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}{G}"); @@ -46,20 +48,13 @@ public final class GruffTriplets extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // When Gruff Triplets enters the battlefield, if it isn't a token, create two tokens that are copies of it. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CreateTokenCopySourceEffect(2)), - new SourceMatchesFilterCondition(filterNonToken), - "When {this} enters, if it isn't a token, create two tokens that are copies of it." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenCopySourceEffect(2) + .setText("create two tokens that are copies of it")).withInterveningIf(condition)); // When Gruff Triplets dies, put a number of +1/+1 counters equal to its power on each creature you control named Gruff Triplets. - this.addAbility(new DiesSourceTriggeredAbility( - new AddCountersAllEffect( - CounterType.P1P1.createInstance(), - SourcePermanentPowerValue.NOT_NEGATIVE, - filterNamedGruffTriplets - ).setText("put a number of +1/+1 counters equal to its power on each creature you control named Gruff Triplets.") - )); + this.addAbility(new DiesSourceTriggeredAbility(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), SourcePermanentPowerValue.NOT_NEGATIVE, filterNamedGruffTriplets + ).setText("put a number of +1/+1 counters equal to its power on each creature you control named Gruff Triplets"))); } private GruffTriplets(final GruffTriplets card) { diff --git a/Mage.Sets/src/mage/cards/g/GuardianOfFaith.java b/Mage.Sets/src/mage/cards/g/GuardianOfFaith.java index 4d39ff349a1..52c49e1dd2a 100644 --- a/Mage.Sets/src/mage/cards/g/GuardianOfFaith.java +++ b/Mage.Sets/src/mage/cards/g/GuardianOfFaith.java @@ -1,27 +1,28 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.PhaseOutTargetEffect; -import mage.constants.SubType; import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author weirddan455 */ public final class GuardianOfFaith extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("other target creatures you control"); + static { filter.add(AnotherPredicate.instance); } @@ -42,7 +43,7 @@ public final class GuardianOfFaith extends CardImpl { // When Guardian of Faith enters the battlefield, any number of other target creatures you control phase out. Ability ability = new EntersBattlefieldTriggeredAbility(new PhaseOutTargetEffect()); - ability.addTarget(new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, false)); + ability.addTarget(new TargetPermanent(0, Integer.MAX_VALUE, filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GuardianOfTazeem.java b/Mage.Sets/src/mage/cards/g/GuardianOfTazeem.java index 686c6f475d8..e3591de4522 100644 --- a/Mage.Sets/src/mage/cards/g/GuardianOfTazeem.java +++ b/Mage.Sets/src/mage/cards/g/GuardianOfTazeem.java @@ -18,9 +18,12 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author fireshoes @@ -38,7 +41,7 @@ public final class GuardianOfTazeem extends CardImpl { // Landfall — Whenever a land enters the battlefield under you control, tap target creature an opponent controls. If that land is an Island, that creature doesn't untap during its controller's next untap step. Ability ability = new GuardianOfTazeemTriggeredAbility(); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GuardianShieldBearer.java b/Mage.Sets/src/mage/cards/g/GuardianShieldBearer.java index 949b4d244a8..7c8187d8ffd 100644 --- a/Mage.Sets/src/mage/cards/g/GuardianShieldBearer.java +++ b/Mage.Sets/src/mage/cards/g/GuardianShieldBearer.java @@ -1,6 +1,5 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.TurnedFaceUpSourceTriggeredAbility; @@ -13,16 +12,17 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class GuardianShieldBearer extends CardImpl { public GuardianShieldBearer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); this.power = new MageInt(2); @@ -33,9 +33,8 @@ public final class GuardianShieldBearer extends CardImpl { // When Guardian Shield-Bearer is turned face up, put a +1/+1 counter on another target creature you control. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false); - ability.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); this.addAbility(ability); - } private GuardianShieldBearer(final GuardianShieldBearer card) { diff --git a/Mage.Sets/src/mage/cards/g/GuardiansOfKoilos.java b/Mage.Sets/src/mage/cards/g/GuardiansOfKoilos.java index 56573bd9568..a2e3811ba4b 100644 --- a/Mage.Sets/src/mage/cards/g/GuardiansOfKoilos.java +++ b/Mage.Sets/src/mage/cards/g/GuardiansOfKoilos.java @@ -1,16 +1,19 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandChosenControlledPermanentEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.mageobject.HistoricPredicate; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.HistoricPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; /** * @@ -32,8 +35,11 @@ public final class GuardiansOfKoilos extends CardImpl { this.toughness = new MageInt(4); // When Guardians of Koilos enters the battlefield, you may return another target historic permanent you control to its owner's hand. - this.addAbility(new EntersBattlefieldTriggeredAbility(new ReturnToHandChosenControlledPermanentEffect(filter) - .setText("you may return another target historic permanent you control to its owner's hand. (Artifacts, legendaries, and Sagas are historic.)"), true)); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect() + .setText("you may return another target historic permanent you control to its owner's hand. (Artifacts, legendaries, and Sagas are historic.)"), + true); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); } private GuardiansOfKoilos(final GuardiansOfKoilos card) { diff --git a/Mage.Sets/src/mage/cards/g/GuildswornProwler.java b/Mage.Sets/src/mage/cards/g/GuildswornProwler.java index a7d63dbdbdc..6bafc744f30 100644 --- a/Mage.Sets/src/mage/cards/g/GuildswornProwler.java +++ b/Mage.Sets/src/mage/cards/g/GuildswornProwler.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.DeathtouchAbility; import mage.cards.CardImpl; @@ -35,10 +34,8 @@ public final class GuildswornProwler extends CardImpl { this.addAbility(DeathtouchAbility.getInstance()); // When Guildsworn Prowler dies, if it wasn't blocking, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(1)), - GuildswornProwlerCondition.instance, "When {this} dies, if it wasn't blocking, draw a card." - )); + this.addAbility(new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .withInterveningIf(GuildswornProwlerCondition.instance)); } private GuildswornProwler(final GuildswornProwler card) { @@ -61,4 +58,9 @@ enum GuildswornProwlerCondition implements Condition { .map(permanent -> !BlockingOrBlockedWatcher.check(permanent, game)) .orElse(false); } -} \ No newline at end of file + + @Override + public String toString() { + return "it wasn't blocking"; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GunnerConscript.java b/Mage.Sets/src/mage/cards/g/GunnerConscript.java index ecc84b5ad1a..a7f254b25e2 100644 --- a/Mage.Sets/src/mage/cards/g/GunnerConscript.java +++ b/Mage.Sets/src/mage/cards/g/GunnerConscript.java @@ -5,11 +5,8 @@ import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.dynamicvalue.AdditiveDynamicValue; import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.AuraAttachedCount; -import mage.abilities.dynamicvalue.common.EquipmentAttachedCount; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.TrampleAbility; @@ -18,7 +15,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.AttachedToSourcePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.JunkToken; @@ -31,6 +30,18 @@ import java.util.UUID; */ public final class GunnerConscript extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent("Aura and Equipment attached to it"); + + static { + filter.add(Predicates.or( + SubType.AURA.getPredicate(), + SubType.EQUIPMENT.getPredicate() + )); + filter.add(AttachedToSourcePredicate.instance); + } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + public GunnerConscript(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); @@ -43,20 +54,15 @@ public final class GunnerConscript extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Gunner Conscript gets +1/+1 for each Aura and Equipment attached to it. - DynamicValue totalAmount = new AdditiveDynamicValue(new AuraAttachedCount(), new EquipmentAttachedCount()); - this.addAbility(new SimpleStaticAbility( - new BoostSourceEffect(totalAmount, totalAmount, Duration.WhileOnBattlefield) - .setText("{this} gets +1/+1 for each Aura and Equipment attached to it"))); + this.addAbility(new SimpleStaticAbility(new BoostSourceEffect(xValue, xValue, Duration.WhileOnBattlefield))); // When Gunner Conscript dies, if it was enchanted, create a Junk token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new DiesSourceTriggeredAbility(new CreateTokenEffect(new JunkToken())), GunnerConscriptEnchantedCondition.instance, - "When Gunner Conscript dies, if it was enchanted, create a Junk token.")); + this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new JunkToken())) + .withInterveningIf(GunnerConscriptEnchantedCondition.instance)); // When Gunner Conscript dies, if it was equipped, create a Junk token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new DiesSourceTriggeredAbility(new CreateTokenEffect(new JunkToken())), GunnerConscriptEquippedCondition.instance, - "When Gunner Conscript dies, if it was equipped, create a Junk token.")); + this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new JunkToken())) + .withInterveningIf(GunnerConscriptEquippedCondition.instance)); } private GunnerConscript(final GunnerConscript card) { @@ -84,6 +90,11 @@ enum GunnerConscriptEnchantedCondition implements Condition { .filter(Objects::nonNull) .anyMatch(permanent -> permanent.isEnchantment(game)); } + + @Override + public String toString() { + return "it was enchanted"; + } } enum GunnerConscriptEquippedCondition implements Condition { @@ -98,4 +109,9 @@ enum GunnerConscriptEquippedCondition implements Condition { .filter(Objects::nonNull) .anyMatch(attachment -> attachment.hasSubtype(SubType.EQUIPMENT, game)); } + + @Override + public String toString() { + return "it was equipped"; + } } diff --git a/Mage.Sets/src/mage/cards/g/GutlessPlunderer.java b/Mage.Sets/src/mage/cards/g/GutlessPlunderer.java index 8614b3d54cf..7f89a39080e 100644 --- a/Mage.Sets/src/mage/cards/g/GutlessPlunderer.java +++ b/Mage.Sets/src/mage/cards/g/GutlessPlunderer.java @@ -1,10 +1,8 @@ package mage.cards.g; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.hint.common.RaidHint; import mage.abilities.keyword.DeathtouchAbility; @@ -19,14 +17,13 @@ import mage.watchers.common.PlayerAttackedWatcher; import java.util.UUID; /** - * * @author ciaccona007 */ public final class GutlessPlunderer extends CardImpl { public GutlessPlunderer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); - + this.subtype.add(SubType.SKELETON); this.subtype.add(SubType.PIRATE); this.power = new MageInt(2); @@ -36,17 +33,9 @@ public final class GutlessPlunderer extends CardImpl { this.addAbility(DeathtouchAbility.getInstance()); // Raid -- When this creature enters, if you attacked this turn, look at the top three cards of your library. You may put one of those cards back on top of your library. Put the rest into your graveyard. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( - new LookLibraryAndPickControllerEffect( - 3, 1, PutCards.TOP_ANY, PutCards.GRAVEYARD, true - ) - ), RaidCondition.instance, "When this creature enters, if you attacked this turn, " - + "look at the top three cards of your library. You may " - + "put one of those cards back on top of your library. Put the rest into your graveyard." - ); - ability.setAbilityWord(AbilityWord.RAID); - ability.addHint(RaidHint.instance); - this.addAbility(ability, new PlayerAttackedWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + 3, 1, PutCards.TOP_ANY, PutCards.GRAVEYARD, true + )).withInterveningIf(RaidCondition.instance).setAbilityWord(AbilityWord.RAID).addHint(RaidHint.instance), new PlayerAttackedWatcher()); } private GutlessPlunderer(final GutlessPlunderer card) { diff --git a/Mage.Sets/src/mage/cards/g/Gutterbones.java b/Mage.Sets/src/mage/cards/g/Gutterbones.java index b06f079c872..27615280382 100644 --- a/Mage.Sets/src/mage/cards/g/Gutterbones.java +++ b/Mage.Sets/src/mage/cards/g/Gutterbones.java @@ -7,7 +7,7 @@ import mage.abilities.condition.Condition; import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.condition.common.OpponentsLostLifeCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; import mage.abilities.hint.common.OpponentsLostLifeHint; import mage.cards.CardImpl; @@ -40,7 +40,7 @@ public final class Gutterbones extends CardImpl { this.addAbility(new EntersBattlefieldTappedAbility()); // {1}{B}: Return Gutterbones from your graveyard to your hand. Activate this ability only during your turn and only if an opponent lost life this turn. - this.addAbility(new ConditionalActivatedAbility( + this.addAbility(new ActivateIfConditionActivatedAbility( Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), new ManaCostsImpl<>("{1}{B}"), condition ).addHint(OpponentsLostLifeHint.instance)); diff --git a/Mage.Sets/src/mage/cards/g/GwafaHazidProfiteer.java b/Mage.Sets/src/mage/cards/g/GwafaHazidProfiteer.java index 874b272b4a3..598f25bf9f9 100644 --- a/Mage.Sets/src/mage/cards/g/GwafaHazidProfiteer.java +++ b/Mage.Sets/src/mage/cards/g/GwafaHazidProfiteer.java @@ -16,10 +16,13 @@ import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author jeffwadsworth */ @@ -37,7 +40,7 @@ public final class GwafaHazidProfiteer extends CardImpl { // {W}{U}, {tap}: Put a bribery counter on target creature you don't control. Its controller draws a card. Ability ability = new SimpleActivatedAbility(new AddCountersTargetEffect(CounterType.BRIBERY.createInstance()), new ManaCostsImpl<>("{W}{U}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); ability.addEffect(new DrawCardTargetControllerEffect(1)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/g/GwendlynDiCorci.java b/Mage.Sets/src/mage/cards/g/GwendlynDiCorci.java index 886dc073273..f57d54bd42d 100644 --- a/Mage.Sets/src/mage/cards/g/GwendlynDiCorci.java +++ b/Mage.Sets/src/mage/cards/g/GwendlynDiCorci.java @@ -6,13 +6,11 @@ import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.common.discard.DiscardTargetEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.target.TargetPlayer; import java.util.UUID; @@ -31,9 +29,10 @@ public final class GwendlynDiCorci extends CardImpl { this.toughness = new MageInt(5); // {T}: Target player discards a card at random. Activate this ability only during your turn. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new DiscardTargetEffect(1, true), new TapSourceCost(), MyTurnCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DiscardTargetEffect(1, true), new TapSourceCost(), MyTurnCondition.instance + ); ability.addTarget(new TargetPlayer()); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GwyllionHedgeMage.java b/Mage.Sets/src/mage/cards/g/GwyllionHedgeMage.java index 06071cbaadd..5c79ce47c72 100644 --- a/Mage.Sets/src/mage/cards/g/GwyllionHedgeMage.java +++ b/Mage.Sets/src/mage/cards/g/GwyllionHedgeMage.java @@ -3,8 +3,8 @@ package mage.cards.g; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.CardImpl; @@ -13,7 +13,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; import mage.counters.CounterType; -import mage.filter.common.FilterLandPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.game.permanent.token.KithkinSoldierToken; import mage.target.common.TargetCreaturePermanent; @@ -24,16 +24,14 @@ import java.util.UUID; */ public final class GwyllionHedgeMage extends CardImpl { - private static final FilterLandPermanent filter = new FilterLandPermanent("Plains"); - private static final FilterLandPermanent filter2 = new FilterLandPermanent("Swamps"); - - static { - filter.add(SubType.PLAINS.getPredicate()); - filter2.add(SubType.SWAMP.getPredicate()); - } - - private static final String rule1 = "When {this} enters, if you control two or more Plains, you may create a 1/1 white Kithkin Soldier creature token."; - private static final String rule2 = "When {this} enters, if you control two or more Swamps, you may put a -1/-1 counter on target creature."; + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.PLAINS, "you control two or more Plains"), + ComparisonType.MORE_THAN, 1 + ); + private static final Condition condition2 = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.SWAMP, "you control two or more Swamps"), + ComparisonType.MORE_THAN, 1 + ); public GwyllionHedgeMage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W/B}"); @@ -44,16 +42,12 @@ public final class GwyllionHedgeMage extends CardImpl { this.toughness = new MageInt(2); // When Gwyllion Hedge-Mage enters the battlefield, if you control two or more Plains, you may create a 1/1 white Kithkin Soldier creature token. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new KithkinSoldierToken()), true), new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1), rule1); - this.addAbility(ability); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new KithkinSoldierToken()), true).withInterveningIf(condition)); // When Gwyllion Hedge-Mage enters the battlefield, if you control two or more Swamps, you may put a -1/-1 counter on target creature. - Ability ability2 = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.M1M1.createInstance()), true), - new PermanentsOnTheBattlefieldCondition(filter2, ComparisonType.MORE_THAN, 1), - rule2); - ability2.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability2); + Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.M1M1.createInstance()), true).withInterveningIf(condition2); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HaazdaSnareSquad.java b/Mage.Sets/src/mage/cards/h/HaazdaSnareSquad.java index c86cdfc3a12..2f017e789b4 100644 --- a/Mage.Sets/src/mage/cards/h/HaazdaSnareSquad.java +++ b/Mage.Sets/src/mage/cards/h/HaazdaSnareSquad.java @@ -14,10 +14,13 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -37,7 +40,7 @@ public final class HaazdaSnareSquad extends CardImpl { // Whenever Haazda Snare Squad attacks you may pay {W}. If you do, tap target creature an opponent controls. Ability ability = new AttacksTriggeredAbility(new DoIfCostPaid(new TapTargetEffect(), new ManaCostsImpl<>("{W}")),false, "Whenever {this} attacks, you may pay {W}. If you do, tap target creature an opponent controls."); - Target target = new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE); + Target target = new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE); ability.addTarget(target); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/h/HagHedgeMage.java b/Mage.Sets/src/mage/cards/h/HagHedgeMage.java index 3b633432287..a15f4dfc892 100644 --- a/Mage.Sets/src/mage/cards/h/HagHedgeMage.java +++ b/Mage.Sets/src/mage/cards/h/HagHedgeMage.java @@ -1,12 +1,11 @@ package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.PutOnLibraryTargetEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.cards.CardImpl; @@ -14,30 +13,28 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.filter.common.FilterLandPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.target.TargetPlayer; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author jeffwadsworth - * */ public final class HagHedgeMage extends CardImpl { - private static final FilterLandPermanent filter = new FilterLandPermanent(); - private static final FilterLandPermanent filter2 = new FilterLandPermanent(); - - static { - filter.add(SubType.SWAMP.getPredicate()); - filter2.add(SubType.FOREST.getPredicate()); - } - - private static final String rule = "When {this} enters, if you control two or more Swamps, you may have target player discard a card."; - private static final String rule2 = "When {this} enters, if you control two or more Forests, you may put target card from your graveyard on top of your library."; + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.SWAMP, "you control two or more Swamps"), + ComparisonType.MORE_THAN, 1 + ); + private static final Condition condition2 = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.FOREST, "you control two or more Forests"), + ComparisonType.MORE_THAN, 1 + ); public HagHedgeMage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B/G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B/G}"); this.subtype.add(SubType.HAG); this.subtype.add(SubType.SHAMAN); @@ -45,12 +42,12 @@ public final class HagHedgeMage extends CardImpl { this.toughness = new MageInt(2); // When Hag Hedge-Mage enters the battlefield, if you control two or more Swamps, you may have target player discard a card. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(1), true), new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1), rule); + Ability ability = new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(1), true).withInterveningIf(condition); ability.addTarget(new TargetPlayer()); this.addAbility(ability); // When Hag Hedge-Mage enters the battlefield, if you control two or more Forests, you may put target card from your graveyard on top of your library. - Ability ability2 = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new PutOnLibraryTargetEffect(true), true), new PermanentsOnTheBattlefieldCondition(filter2, ComparisonType.MORE_THAN, 1), rule2); + Ability ability2 = new EntersBattlefieldTriggeredAbility(new PutOnLibraryTargetEffect(true), true).withInterveningIf(condition2); ability2.addTarget(new TargetCardInYourGraveyard()); this.addAbility(ability2); } diff --git a/Mage.Sets/src/mage/cards/h/HairStrungKoto.java b/Mage.Sets/src/mage/cards/h/HairStrungKoto.java index 9c339dd0103..01e67622f1e 100644 --- a/Mage.Sets/src/mage/cards/h/HairStrungKoto.java +++ b/Mage.Sets/src/mage/cards/h/HairStrungKoto.java @@ -1,39 +1,38 @@ package mage.cards.h; -import java.util.UUID; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapTargetCost; import mage.abilities.effects.common.MillCardsTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.target.TargetPlayer; -import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author LevelX */ public final class HairStrungKoto extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); + private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); static { filter.add(TappedPredicate.UNTAPPED); } - public HairStrungKoto (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{6}"); + public HairStrungKoto(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}"); - /* Tap an untapped creature you control: Target player puts the top - * card of their library into their graveyard. - */ + // Tap an untapped creature you control: Target player puts the top card of their library into their graveyard. SimpleActivatedAbility ability = new SimpleActivatedAbility( new MillCardsTargetEffect(1), - new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, false))); + new TapTargetCost(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE) + ); ability.addTarget(new TargetPlayer()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HakbalOfTheSurgingSoul.java b/Mage.Sets/src/mage/cards/h/HakbalOfTheSurgingSoul.java index 91580715647..16665e4b411 100644 --- a/Mage.Sets/src/mage/cards/h/HakbalOfTheSurgingSoul.java +++ b/Mage.Sets/src/mage/cards/h/HakbalOfTheSurgingSoul.java @@ -1,35 +1,35 @@ package mage.cards.h; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.keyword.ExploreSourceEffect; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.Card; -import mage.constants.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.*; import mage.filter.FilterCard; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetCardInHand; -import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.List; +import java.util.UUID; /** - * * @author Grath */ public final class HakbalOfTheSurgingSoul extends CardImpl { public HakbalOfTheSurgingSoul(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); - + this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.MERFOLK); this.subtype.add(SubType.SCOUT); @@ -55,24 +55,24 @@ public final class HakbalOfTheSurgingSoul extends CardImpl { class HakbalOfTheSurgingSoulExploreEffect extends OneShotEffect { - HakbalOfTheSurgingSoulExploreEffect( ) { + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(SubType.MERFOLK); + + HakbalOfTheSurgingSoulExploreEffect() { super(Outcome.Benefit); staticText = "each Merfolk creature you control explores"; } - HakbalOfTheSurgingSoulExploreEffect(HakbalOfTheSurgingSoulExploreEffect effect ) { + HakbalOfTheSurgingSoulExploreEffect(HakbalOfTheSurgingSoulExploreEffect effect) { super(effect); } @Override public boolean apply(Game game, Ability source) { - FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(SubType.MERFOLK); - List creatures = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); Player player = game.getPlayer(source.getControllerId()); if (player != null && player.chooseUse(Outcome.AIDontUseIt, "Choose order for Merfolk to explore? (Note: You will need to set \"Auto-choose targets for player:\" to \"Off\" in Preferences.)", source, game)) { - TargetPermanent target = new TargetControlledCreaturePermanent(creatures.size(), creatures.size(), filter, true); + TargetPermanent target = new TargetPermanent(creatures.size(), creatures.size(), filter, true); target.withChooseHint("the order in which to explore (first selected will explore first)"); player.choose(outcome, target, source, game); for (UUID targetId : target.getTargets()) { diff --git a/Mage.Sets/src/mage/cards/h/HakimLoreweaver.java b/Mage.Sets/src/mage/cards/h/HakimLoreweaver.java index 6ba435e5547..f971fa8440a 100644 --- a/Mage.Sets/src/mage/cards/h/HakimLoreweaver.java +++ b/Mage.Sets/src/mage/cards/h/HakimLoreweaver.java @@ -6,7 +6,7 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.keyword.FlyingAbility; @@ -53,11 +53,8 @@ public final class HakimLoreweaver extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // {U}{U}: Return target Aura card from your graveyard to the battlefield attached to Hakim, Loreweaver. Activate this ability only during your upkeep and only if Hakim isn't enchanted. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, - new HakimLoreweaverEffect(), - new ManaCostsImpl<>("{U}{U}"), - HakimLoreweaverCondition.instance + Ability ability = new ActivateIfConditionActivatedAbility( + new HakimLoreweaverEffect(), new ManaCostsImpl<>("{U}{U}"), HakimLoreweaverCondition.instance ); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/h/HaktosTheUnscarred.java b/Mage.Sets/src/mage/cards/h/HaktosTheUnscarred.java index dbea77aff18..170498ae371 100644 --- a/Mage.Sets/src/mage/cards/h/HaktosTheUnscarred.java +++ b/Mage.Sets/src/mage/cards/h/HaktosTheUnscarred.java @@ -106,7 +106,7 @@ enum HaktosTheUnscarredPredicate implements ObjectSourcePlayerPredicate { @Override public boolean apply(ObjectSourcePlayer input, Game game) { - Object obj = game.getState().getValue(input.getSourceId() + "" + input.getSource().getSourceObjectZoneChangeCounter() + "_haktos_number"); + Object obj = game.getState().getValue(input.getSourceId() + "" + input.getObject().getZoneChangeCounter(game) + "_haktos_number"); if (!(obj instanceof Integer)) { return false; } diff --git a/Mage.Sets/src/mage/cards/h/Halfdane.java b/Mage.Sets/src/mage/cards/h/Halfdane.java index 0271882d98f..322991b2baf 100644 --- a/Mage.Sets/src/mage/cards/h/Halfdane.java +++ b/Mage.Sets/src/mage/cards/h/Halfdane.java @@ -3,19 +3,18 @@ package mage.cards.h; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -25,12 +24,6 @@ import java.util.UUID; */ public final class Halfdane extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("target creature other than Halfdane"); - - static { - filter.add(AnotherPredicate.instance); - } - public Halfdane(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}{B}"); this.supertype.add(SuperType.LEGENDARY); @@ -40,7 +33,7 @@ public final class Halfdane extends CardImpl { // At the beginning of your upkeep, change Halfdane's base power and toughness to the power and toughness of target creature other than Halfdane until the end of your next upkeep. Ability ability = new BeginningOfUpkeepTriggeredAbility(new HalfdaneUpkeepEffect()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); } @@ -58,7 +51,7 @@ class HalfdaneUpkeepEffect extends OneShotEffect { HalfdaneUpkeepEffect() { super(Outcome.Detriment); - this.staticText = "change {this}'s base power and toughness to the power and toughness of target creature other than Halfdane until the end of your next upkeep"; + this.staticText = "change {this}'s base power and toughness to the power and toughness of target creature other than {this} until the end of your next upkeep"; } private HalfdaneUpkeepEffect(final HalfdaneUpkeepEffect effect) { diff --git a/Mage.Sets/src/mage/cards/h/HallOfOracles.java b/Mage.Sets/src/mage/cards/h/HallOfOracles.java index 6a502314ffa..39ecd74e32a 100644 --- a/Mage.Sets/src/mage/cards/h/HallOfOracles.java +++ b/Mage.Sets/src/mage/cards/h/HallOfOracles.java @@ -5,7 +5,7 @@ import mage.abilities.ActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.mana.AnyColorManaAbility; import mage.abilities.mana.ColorlessManaAbility; @@ -13,7 +13,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TimingRule; -import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; @@ -39,13 +38,11 @@ public final class HallOfOracles extends CardImpl { this.addAbility(ability); // {T}: Put a +1/+1 counter on target creature. Activate only as a sorcery and only if you've cast an instant or sorcery spell this turn. - ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new TapSourceCost(), - HallOfOraclesCondition.instance, "{T}: Put a +1/+1 counter on target creature. " + - "Activate only as a sorcery and only if you've cast an instant or sorcery spell this turn." - ); + ability = new ActivateIfConditionActivatedAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), + new TapSourceCost(), HallOfOraclesCondition.instance + ).setTiming(TimingRule.SORCERY); ability.addTarget(new TargetCreaturePermanent()); - ability.setTiming(TimingRule.SORCERY); this.addAbility(ability); } @@ -71,4 +68,9 @@ enum HallOfOraclesCondition implements Condition { .filter(Objects::nonNull) .anyMatch(spell -> spell.isInstantOrSorcery(game)); } + + @Override + public String toString() { + return "you've cast an instant or sorcery spell this turn"; + } } diff --git a/Mage.Sets/src/mage/cards/h/HallOfStormGiants.java b/Mage.Sets/src/mage/cards/h/HallOfStormGiants.java index 40150e6404e..28e9a107083 100644 --- a/Mage.Sets/src/mage/cards/h/HallOfStormGiants.java +++ b/Mage.Sets/src/mage/cards/h/HallOfStormGiants.java @@ -1,7 +1,5 @@ package mage.cards.h; -import java.util.UUID; - import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; @@ -14,13 +12,17 @@ import mage.abilities.keyword.WardAbility; import mage.abilities.mana.BlueManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.permanent.token.custom.CreatureToken; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class HallOfStormGiants extends CardImpl { @@ -51,10 +53,10 @@ public final class HallOfStormGiants extends CardImpl { .withSubType(SubType.GIANT) .withAbility(new WardAbility(new GenericManaCost(3))), CardType.LAND, Duration.EndOfTurn).setText( - "Until end of turn, Hall of Storm Giants becomes a 7/7 blue Giant creature with ward {3}. " + - "It's still a land. " + - "(Whenever it becomes the target of a spell or ability an opponent controls, " + - "counter it unless that player pays {3}.)"), + "Until end of turn, {this} becomes a 7/7 blue Giant creature with ward {3}. " + + "It's still a land. " + + "(Whenever it becomes the target of a spell or ability an opponent controls, " + + "counter it unless that player pays {3}.)"), new ManaCostsImpl<>("{5}{U}"))); } diff --git a/Mage.Sets/src/mage/cards/h/HallowedHealer.java b/Mage.Sets/src/mage/cards/h/HallowedHealer.java index 21a746202e7..5987a2c528e 100644 --- a/Mage.Sets/src/mage/cards/h/HallowedHealer.java +++ b/Mage.Sets/src/mage/cards/h/HallowedHealer.java @@ -5,7 +5,7 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.ThresholdCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.PreventDamageToTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -37,7 +37,7 @@ public final class HallowedHealer extends CardImpl { this.addAbility(ability); // Threshold - {tap}: Prevent the next 4 damage that would be dealt to any target this turn. Activate this ability only if seven or more cards are in your graveyard. - Ability thresholdAbility = new ConditionalActivatedAbility( + Ability thresholdAbility = new ActivateIfConditionActivatedAbility( new PreventDamageToTargetEffect(Duration.EndOfTurn, 4), new TapSourceCost(), ThresholdCondition.instance ); diff --git a/Mage.Sets/src/mage/cards/h/HallowedMoonlight.java b/Mage.Sets/src/mage/cards/h/HallowedMoonlight.java index 91b3fd9046a..21e73944f51 100644 --- a/Mage.Sets/src/mage/cards/h/HallowedMoonlight.java +++ b/Mage.Sets/src/mage/cards/h/HallowedMoonlight.java @@ -48,7 +48,7 @@ class HallowedMoonlightEffect extends ReplacementEffectImpl { HallowedMoonlightEffect() { super(Duration.EndOfTurn, Outcome.Exile); - staticText = "Until end of turn, if a creature would enter the battlefield and it wasn't cast, exile it instead"; + staticText = "Until end of turn, if a creature would enter and it wasn't cast, exile it instead"; } private HallowedMoonlightEffect(final HallowedMoonlightEffect effect) { diff --git a/Mage.Sets/src/mage/cards/h/HallowedRespite.java b/Mage.Sets/src/mage/cards/h/HallowedRespite.java index 62cc4fff36e..8097408ce27 100644 --- a/Mage.Sets/src/mage/cards/h/HallowedRespite.java +++ b/Mage.Sets/src/mage/cards/h/HallowedRespite.java @@ -17,6 +17,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class HallowedRespite extends CardImpl { // Exile target nonlegendary creature, then return it to the battlefield under its owner's control. If it entered under your control, put a +1/+1 counter on it. Otherwise, tap it. this.getSpellAbility().addEffect(new ExileThenReturnTargetEffect(false, false)); this.getSpellAbility().addEffect(new HallowedRespiteEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Flashback {1}{W}{U} this.addAbility(new FlashbackAbility(this, new ManaCostsImpl<>("{1}{W}{U}"))); diff --git a/Mage.Sets/src/mage/cards/h/HaloHunter.java b/Mage.Sets/src/mage/cards/h/HaloHunter.java index bb60c987e06..f57522afc48 100644 --- a/Mage.Sets/src/mage/cards/h/HaloHunter.java +++ b/Mage.Sets/src/mage/cards/h/HaloHunter.java @@ -12,6 +12,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -35,7 +36,7 @@ public final class HaloHunter extends CardImpl { this.addAbility(IntimidateAbility.getInstance()); Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HammerJammer.java b/Mage.Sets/src/mage/cards/h/HammerJammer.java index 03599290a08..41d3a1e146a 100644 --- a/Mage.Sets/src/mage/cards/h/HammerJammer.java +++ b/Mage.Sets/src/mage/cards/h/HammerJammer.java @@ -1,10 +1,9 @@ - package mage.cards.h; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.EntersBattlefieldWithXCountersEffect; import mage.cards.CardImpl; @@ -38,7 +37,7 @@ public final class HammerJammer extends CardImpl { this.toughness = new MageInt(0); // As Hammer Jammer enters the battlefield, roll a six-sided die. Hammer Jammer enters the battlefield with a number of +1/+1 counters on it equal to the result. - this.addAbility(new EntersBattlefieldAbility(new HammerJammerEntersEffect(CounterType.P1P1.createInstance()))); + this.addAbility(new AsEntersBattlefieldAbility(new HammerJammerEntersEffect(CounterType.P1P1.createInstance()))); // Whenever you roll a die, remove all +1/+1 counters from Hammer Jammer, then put a number of +1/+1 counters on it equal to the result. this.addAbility(new HammerJammerTriggeredAbility()); @@ -59,9 +58,10 @@ class HammerJammerEntersEffect extends EntersBattlefieldWithXCountersEffect { HammerJammerEntersEffect(Counter counter) { super(counter); + staticText = "roll a six-sided die. {this} enters with a number of +1/+1 counters on it equal to the result"; } - public HammerJammerEntersEffect(EntersBattlefieldWithXCountersEffect effect) { + private HammerJammerEntersEffect(EntersBattlefieldWithXCountersEffect effect) { super(effect); } @@ -86,7 +86,7 @@ class HammerJammerEntersEffect extends EntersBattlefieldWithXCountersEffect { class HammerJammerTriggeredAbility extends TriggeredAbilityImpl { - public HammerJammerTriggeredAbility() { + HammerJammerTriggeredAbility() { super(Zone.BATTLEFIELD, new HammerJammerEffect(), false); setTriggerPhrase("Whenever you roll a die, "); } diff --git a/Mage.Sets/src/mage/cards/h/HammerOfBogardan.java b/Mage.Sets/src/mage/cards/h/HammerOfBogardan.java index 5afd779f585..f79470a03de 100644 --- a/Mage.Sets/src/mage/cards/h/HammerOfBogardan.java +++ b/Mage.Sets/src/mage/cards/h/HammerOfBogardan.java @@ -1,37 +1,35 @@ - package mage.cards.h; -import java.util.UUID; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.PhaseStep; import mage.constants.Zone; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author jeffwadsworth - * */ public final class HammerOfBogardan extends CardImpl { public HammerOfBogardan(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{R}{R}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}{R}"); // Hammer of Bogardan deals 3 damage to any target. this.getSpellAbility().addEffect(new DamageTargetEffect(3)); this.getSpellAbility().addTarget(new TargetAnyTarget()); // {2}{R}{R}{R}: Return Hammer of Bogardan from your graveyard to your hand. Activate this ability only during your upkeep. - this.addAbility(new ConditionalActivatedAbility(Zone.GRAVEYARD, - new ReturnSourceFromGraveyardToHandEffect(), new ManaCostsImpl<>("{2}{R}{R}{R}"), new IsStepCondition(PhaseStep.UPKEEP), null)); + this.addAbility(new ActivateIfConditionActivatedAbility( + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), + new ManaCostsImpl<>("{2}{R}{R}{R}"), IsStepCondition.getMyUpkeep() + )); } private HammerOfBogardan(final HammerOfBogardan card) { diff --git a/Mage.Sets/src/mage/cards/h/HammerheadCorvette.java b/Mage.Sets/src/mage/cards/h/HammerheadCorvette.java index 15158821bf1..2d3bd991552 100644 --- a/Mage.Sets/src/mage/cards/h/HammerheadCorvette.java +++ b/Mage.Sets/src/mage/cards/h/HammerheadCorvette.java @@ -16,6 +16,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -47,7 +48,7 @@ public final class HammerheadCorvette extends CardImpl { Ability ability = new AttacksTriggeredAbility(effect1, true, "Whenever {this} attacks, you may uptap target Starship creature defending player controls and have that creature block {this} this turn if able"); ability.addEffect(effect2); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HammerheimDeadeye.java b/Mage.Sets/src/mage/cards/h/HammerheimDeadeye.java index fde29bbccc2..dcd68bafae4 100644 --- a/Mage.Sets/src/mage/cards/h/HammerheimDeadeye.java +++ b/Mage.Sets/src/mage/cards/h/HammerheimDeadeye.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class HammerheimDeadeye extends CardImpl { this.addAbility(new EchoAbility("{5}{R}")); // When Hammerheim Deadeye enters the battlefield, destroy target creature with flying. Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()); - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); ability.addTarget(target); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HanSolo.java b/Mage.Sets/src/mage/cards/h/HanSolo.java index fe7d6413af0..e8f427eb6e0 100644 --- a/Mage.Sets/src/mage/cards/h/HanSolo.java +++ b/Mage.Sets/src/mage/cards/h/HanSolo.java @@ -13,6 +13,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -46,7 +47,7 @@ public final class HanSolo extends CardImpl { effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); effect.setText("and gains haste until end of turn"); ability.addEffect(effect); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HanSoloScrumrat.java b/Mage.Sets/src/mage/cards/h/HanSoloScrumrat.java index b0b9a81407d..5baa79e3b64 100644 --- a/Mage.Sets/src/mage/cards/h/HanSoloScrumrat.java +++ b/Mage.Sets/src/mage/cards/h/HanSoloScrumrat.java @@ -1,33 +1,34 @@ package mage.cards.h; -import java.util.UUID; import mage.MageInt; -import mage.abilities.*; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.PartnerWithAbility; -import mage.constants.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.*; import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author NinthWorld */ public final class HanSoloScrumrat extends CardImpl { public HanSoloScrumrat(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); - + this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ROGUE); @@ -38,11 +39,13 @@ public final class HanSoloScrumrat extends CardImpl { this.addAbility(new PartnerWithAbility("Chewbacca, the Beast")); // R: Han Solo, Scrumrat gains first strike until end of turn. - this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{R}"))); + this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl<>("{R}"))); // Whenever Han Solo, Scrumrat deals damage during your turn, put a +1/+1 counter on another target creature you control. Ability ability = new HanSoloScrumratTriggeredAbility(); - ability.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); this.addAbility(ability); } @@ -75,7 +78,7 @@ class HanSoloScrumratTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.DAMAGED_PERMANENT - || event.getType() == GameEvent.EventType.DAMAGED_PLAYER; + || event.getType() == GameEvent.EventType.DAMAGED_PLAYER; } @Override diff --git a/Mage.Sets/src/mage/cards/h/HandOfDeath.java b/Mage.Sets/src/mage/cards/h/HandOfDeath.java index 91abfc5034b..7d3920722dd 100644 --- a/Mage.Sets/src/mage/cards/h/HandOfDeath.java +++ b/Mage.Sets/src/mage/cards/h/HandOfDeath.java @@ -6,8 +6,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author anonymous @@ -18,7 +21,7 @@ public final class HandOfDeath extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{B}"); // Destroy target nonblack creature. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/h/HandOfJustice.java b/Mage.Sets/src/mage/cards/h/HandOfJustice.java index 251edadb036..d3a534e4fb1 100644 --- a/Mage.Sets/src/mage/cards/h/HandOfJustice.java +++ b/Mage.Sets/src/mage/cards/h/HandOfJustice.java @@ -1,7 +1,5 @@ - package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -13,20 +11,20 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class HandOfJustice extends CardImpl { - - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped white creatures you control"); + + private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("untapped white creatures you control"); static { filter.add(new ColorPredicate(ObjectColor.WHITE)); @@ -34,14 +32,14 @@ public final class HandOfJustice extends CardImpl { } public HandOfJustice(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}"); this.subtype.add(SubType.AVATAR); this.power = new MageInt(2); this.toughness = new MageInt(6); // {tap}, Tap three untapped white creatures you control: Destroy target creature. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new TapSourceCost()); - ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(3, 3, filter, true))); + ability.addCost(new TapTargetCost(3, filter)); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HandsOfBinding.java b/Mage.Sets/src/mage/cards/h/HandsOfBinding.java index 78aa695dd1a..a66e57c01f7 100644 --- a/Mage.Sets/src/mage/cards/h/HandsOfBinding.java +++ b/Mage.Sets/src/mage/cards/h/HandsOfBinding.java @@ -8,8 +8,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author Plopman @@ -22,7 +25,7 @@ public final class HandsOfBinding extends CardImpl { //Tap target creature an opponent controls. That creature doesn't untap during its controller's next untap step. this.getSpellAbility().addEffect(new TapTargetEffect()); this.getSpellAbility().addEffect(new DontUntapInControllersNextUntapStepTargetEffect("that creature")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); //Cipher this.getSpellAbility().addEffect(new CipherEffect()); } diff --git a/Mage.Sets/src/mage/cards/h/HanweirBattlements.java b/Mage.Sets/src/mage/cards/h/HanweirBattlements.java index bbb155ab7fe..16d1e5b3881 100644 --- a/Mage.Sets/src/mage/cards/h/HanweirBattlements.java +++ b/Mage.Sets/src/mage/cards/h/HanweirBattlements.java @@ -2,11 +2,8 @@ package mage.cards.h; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.MeldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.MeldEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.HasteAbility; @@ -15,7 +12,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Zone; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -25,8 +21,6 @@ import java.util.UUID; */ public final class HanweirBattlements extends CardImpl { - private static final Condition condition = new MeldCondition("Hanweir Garrison"); - public HanweirBattlements(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); @@ -36,7 +30,7 @@ public final class HanweirBattlements extends CardImpl { // {T}: Add {C}. this.addAbility(new ColorlessManaAbility()); - // {R},{T}: Target creature gains haste until end of turn. + // {R}, {T}: Target creature gains haste until end of turn. Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect( HasteAbility.getInstance(), Duration.EndOfTurn ), new ManaCostsImpl<>("{R}")); @@ -44,11 +38,12 @@ public final class HanweirBattlements extends CardImpl { ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); - // {3}{R}{R},{T}: If you both own and control Hanweir Battlements and a creature named Hanweir Garrison, exile them, then meld them into Hanweir, the Writhing Township. - ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new MeldEffect("Hanweir Garrison", "Hanweir, the Writhing Township"), - new ManaCostsImpl<>("{3}{R}{R}"), condition, "{3}{R}{R}, {T}: If you both own and control {this} " + - "and a creature named Hanweir Garrison, exile them, then meld them into Hanweir, the Writhing Township." + // {3}{R}{R}, {T}: If you both own and control Hanweir Battlements and a creature named Hanweir Garrison, exile them, then meld them into Hanweir, the Writhing Township. + ability = new SimpleActivatedAbility( + new MeldEffect("Hanweir Garrison", "Hanweir, the Writhing Township") + .setText("if you both own and control {this} and a creature named Hanweir Garrison, " + + "exile them, then meld them into Hanweir, the Writhing Township"), + new ManaCostsImpl<>("{3}{R}{R}") ); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/h/HanweirMilitiaCaptain.java b/Mage.Sets/src/mage/cards/h/HanweirMilitiaCaptain.java index 2ae81956b58..a6bb769ba9c 100644 --- a/Mage.Sets/src/mage/cards/h/HanweirMilitiaCaptain.java +++ b/Mage.Sets/src/mage/cards/h/HanweirMilitiaCaptain.java @@ -1,27 +1,30 @@ - package mage.cards.h; -import java.util.UUID; - import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.abilities.keyword.TransformAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; +import mage.constants.SubType; import mage.filter.common.FilterControlledCreaturePermanent; +import java.util.UUID; + /** * @author fireshoes */ public final class HanweirMilitiaCaptain extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("if you control four or more creatures"); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledCreaturePermanent("you control four or more creatures"), + ComparisonType.MORE_THAN, 3 + ); public HanweirMilitiaCaptain(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); @@ -34,10 +37,8 @@ public final class HanweirMilitiaCaptain extends CardImpl { // At the beginning of your upkeep, if you control four or more creatures, transform Hanweir Militia Captain. this.addAbility(new TransformAbility()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()), - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 3), - "At the beginning of your upkeep, if you control four or more creatures, transform {this}")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()) + .withInterveningIf(condition).addHint(CreaturesYouControlHint.instance)); } private HanweirMilitiaCaptain(final HanweirMilitiaCaptain card) { diff --git a/Mage.Sets/src/mage/cards/h/HaphazardBombardment.java b/Mage.Sets/src/mage/cards/h/HaphazardBombardment.java index 8c64f38d7cb..6c4e09e2e5d 100644 --- a/Mage.Sets/src/mage/cards/h/HaphazardBombardment.java +++ b/Mage.Sets/src/mage/cards/h/HaphazardBombardment.java @@ -1,14 +1,12 @@ package mage.cards.h; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -25,12 +23,26 @@ import mage.players.Player; import mage.target.TargetPermanent; import mage.util.RandomUtil; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + /** - * * @author LevelX2 */ public final class HaphazardBombardment extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent("if two or more permanents you don't control have an aim counter on them"); + + static { + filter.add(TargetController.NOT_YOU.getControllerPredicate()); + filter.add(CounterType.AIM.getPredicate()); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); + public HaphazardBombardment(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{5}{R}"); @@ -38,12 +50,7 @@ public final class HaphazardBombardment extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new HaphazardBombardmentEffect(), false)); // At the beginning of your end step, if two or more permanents you don't control have an aim counter on them, destroy one of those permanents at random. - FilterPermanent filter = new FilterPermanent("if two or more permanents you don't control have an aim counter on them"); - filter.add(TargetController.NOT_YOU.getControllerPredicate()); - filter.add(CounterType.AIM.getPredicate()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new BeginningOfEndStepTriggeredAbility(new HaphazardBombardmentEndOfTurnEffect()), - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1, false), - "At the beginning of your end step, if two or more permanents you don't control have an aim counter on them, destroy one of those permanents at random")); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new HaphazardBombardmentEndOfTurnEffect()).withInterveningIf(condition)); } private HaphazardBombardment(final HaphazardBombardment card) { @@ -58,6 +65,13 @@ public final class HaphazardBombardment extends CardImpl { class HaphazardBombardmentEffect extends OneShotEffect { + private static final FilterPermanent filter = new FilterPermanent("nonenchantment permanents you don't control"); + + static { + filter.add(Predicates.not(CardType.ENCHANTMENT.getPredicate())); + filter.add(TargetController.NOT_YOU.getControllerPredicate()); + } + HaphazardBombardmentEffect() { super(Outcome.Benefit); this.staticText = "choose four nonenchantment permanents you don't control and put an aim counter on each of them"; @@ -75,34 +89,43 @@ class HaphazardBombardmentEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - FilterPermanent filter = new FilterPermanent("nonenchantment permanents you don't control"); - filter.add(Predicates.not(CardType.ENCHANTMENT.getPredicate())); - filter.add(TargetController.OPPONENT.getControllerPredicate()); - List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); - if (permanents.size() > 4) { - permanents.clear(); - TargetPermanent target = new TargetPermanent(4, 4, filter, true); - controller.chooseTarget(outcome, target, source, game); - for (UUID targetId : target.getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent != null) { - permanents.add(permanent); - } - } - } - for (Permanent permanent : permanents) { - permanent.addCounters(CounterType.AIM.createInstance(), source.getControllerId(), source, game); - } - return true; - + if (controller == null) { + return false; } - return false; + List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); + if (permanents.size() > 4) { + permanents.clear(); + TargetPermanent target = new TargetPermanent(4, 4, filter, true); + controller.chooseTarget(outcome, target, source, game); + permanents.addAll( + target.getTargets() + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()) + ); + } + for (Permanent permanent : permanents) { + permanent.addCounters(CounterType.AIM.createInstance(), source.getControllerId(), source, game); + } + return true; + } } class HaphazardBombardmentEndOfTurnEffect extends OneShotEffect { + private static final FilterPermanent filter = new FilterPermanent(); + + static { + filter.add(TargetController.NOT_YOU.getControllerPredicate()); + filter.add(CounterType.AIM.getPredicate()); + // 4/27/2018 If one or more of the permanents with aim counters on them have indestructible, + // select the permanent destroyed at random from among the permanents with aim counters + // that don't have indestructible. + filter.add(Predicates.not(new AbilityPredicate(IndestructibleAbility.class))); + } + HaphazardBombardmentEndOfTurnEffect() { super(Outcome.Benefit); this.staticText = "destroy one of those permanents at random"; @@ -119,21 +142,12 @@ class HaphazardBombardmentEndOfTurnEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - - // 4/27/2018 If one or more of the permanents with aim counters on them have indestructible, - // select the permanent destroyed at random from among the permanents with aim counters - // that don't have indestructible. - FilterPermanent filter = new FilterPermanent("if two or more permanents you don't control have an aim counter on them"); - filter.add(TargetController.NOT_YOU.getControllerPredicate()); - filter.add(CounterType.AIM.getPredicate()); - filter.add(Predicates.not(new AbilityPredicate(IndestructibleAbility.class))); - List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); - if (!permanents.isEmpty()) { - Permanent permanent = permanents.get(RandomUtil.nextInt(permanents.size())); - if (permanent != null) { - permanent.destroy(source, game, false); - } - } - return true; + return Optional.ofNullable( + game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game) + ) + .filter(p -> !p.isEmpty()) + .map(RandomUtil::randomFromCollection) + .filter(permanent -> permanent.destroy(source, game)) + .isPresent(); } } diff --git a/Mage.Sets/src/mage/cards/h/HappilyEverAfter.java b/Mage.Sets/src/mage/cards/h/HappilyEverAfter.java index 995c71abb29..544db48f69c 100644 --- a/Mage.Sets/src/mage/cards/h/HappilyEverAfter.java +++ b/Mage.Sets/src/mage/cards/h/HappilyEverAfter.java @@ -2,23 +2,21 @@ package mage.cards.h; import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardAllEffect; +import mage.abilities.effects.common.GainLifeAllEffect; import mage.abilities.effects.common.WinGameSourceControllerEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.HintUtils; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; import java.util.*; -import java.util.List; /** * @author TheElk801 @@ -29,20 +27,16 @@ public final class HappilyEverAfter extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); // When Happily Ever After enters the battlefield, each player gains 5 life and draws a card. - this.addAbility(new EntersBattlefieldTriggeredAbility(new HappilyEverAfterEffect())); + Ability ability = new EntersBattlefieldTriggeredAbility(new GainLifeAllEffect(5)); + ability.addEffect(new DrawCardAllEffect(1).setText("and draws a card")); + this.addAbility(ability); // At the beginning of your upkeep, if there are five colors among permanents you control, there are six or more card types among permanents you control and/or cards in your graveyard, and your life total is greater than or equal to your starting life total, you win the game. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - new WinGameSourceControllerEffect(), false - ), HappilyEverAfterCondition.instance, "At the beginning of your upkeep, " + - "if there are five colors among permanents you control, there are six or more card types " + - "among permanents you control and/or cards in your graveyard, and your life total is " + - "greater than or equal to your starting life total, you win the game.") + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect()) + .withInterveningIf(HappilyEverAfterCondition.instance) .addHint(HappilyEverAfterColorHint.instance) .addHint(HappilyEverAfterCardTypeHint.instance) - .addHint(HappilyEverAfterLifeHint.instance) - ); + .addHint(HappilyEverAfterLifeHint.instance)); } private HappilyEverAfter(final HappilyEverAfter card) { @@ -55,37 +49,6 @@ public final class HappilyEverAfter extends CardImpl { } } -class HappilyEverAfterEffect extends OneShotEffect { - - HappilyEverAfterEffect() { - super(Outcome.GainLife); - staticText = "each player gains 5 life and draws a card"; - } - - private HappilyEverAfterEffect(final HappilyEverAfterEffect effect) { - super(effect); - } - - @Override - public HappilyEverAfterEffect copy() { - return new HappilyEverAfterEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - game.getState() - .getPlayersInRange(source.getControllerId(), game) - .stream() - .map(game::getPlayer) - .filter(Objects::nonNull) - .forEachOrdered(player -> { - player.gainLife(5, game, source); - player.drawCards(1, source, game); - }); - return true; - } -} - enum HappilyEverAfterCondition implements Condition { instance; @@ -122,6 +85,13 @@ enum HappilyEverAfterCondition implements Condition { .forEach(cardTypeEnumSet::add); return cardTypeEnumSet.size() >= 6; } + + @Override + public String toString() { + return "there are five colors among permanents you control, " + + "there are six or more card types among permanents you control and/or cards in your graveyard, " + + "and your life total is greater than or equal to your starting life total"; + } } enum HappilyEverAfterColorHint implements Hint { diff --git a/Mage.Sets/src/mage/cards/h/HarbingerOfTheTides.java b/Mage.Sets/src/mage/cards/h/HarbingerOfTheTides.java index 3f6d28d94fa..64fde8b543d 100644 --- a/Mage.Sets/src/mage/cards/h/HarbingerOfTheTides.java +++ b/Mage.Sets/src/mage/cards/h/HarbingerOfTheTides.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -42,7 +43,7 @@ public final class HarbingerOfTheTides extends CardImpl { // When Harbinger of the Tides enters the battlefield, you may return target tapped creature an opponent controls to its owner's hand. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HarmoniousGrovestrider.java b/Mage.Sets/src/mage/cards/h/HarmoniousGrovestrider.java new file mode 100644 index 00000000000..1c233b124ec --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HarmoniousGrovestrider.java @@ -0,0 +1,44 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.LandsYouControlCount; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; +import mage.abilities.keyword.WardAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HarmoniousGrovestrider extends CardImpl { + + public HarmoniousGrovestrider(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Ward {2} + this.addAbility(new WardAbility(new ManaCostsImpl<>("{2}"))); + + // This creature's power and toughness are each equal to the number of lands you control. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(LandsYouControlCount.instance))); + } + + private HarmoniousGrovestrider(final HarmoniousGrovestrider card) { + super(card); + } + + @Override + public HarmoniousGrovestrider copy() { + return new HarmoniousGrovestrider(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java b/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java index 2f5fe12510c..a6c20b27723 100644 --- a/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java +++ b/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java @@ -1,38 +1,43 @@ package mage.cards.h; -import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.MayCastTargetCardEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; +import mage.constants.SetTargetPointer; +import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.common.FilterInstantOrSorcerySpell; +import mage.filter.StaticFilters; import mage.filter.predicate.mageobject.NamePredicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.stack.Spell; -import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; -import mage.watchers.common.CastFromHandWatcher; +import mage.target.targetadjustment.TargetAdjuster; +import mage.target.targetpointer.FirstTargetPointer; import java.util.UUID; /** - * * @author LevelX2 */ public final class HarnessTheStorm extends CardImpl { + private static final FilterCard filter = new FilterCard("card with the same name as that spell from your graveyard"); + public HarnessTheStorm(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); // Whenever you cast an instant or sorcery spell from your hand, you may cast // target card with the same name as that spell from your graveyard. - this.addAbility(new HarnessTheStormTriggeredAbility(), new CastFromHandWatcher()); + Ability ability = new SpellCastControllerTriggeredAbility( + Zone.BATTLEFIELD, new MayCastTargetCardEffect(false), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, + false, SetTargetPointer.SPELL, Zone.HAND + ); + ability.addTarget(new TargetCardInYourGraveyard(filter)); // Only used for text generation + ability.setTargetAdjuster(HarnessTheStormAdjuster.instance); + this.addAbility(ability); } private HarnessTheStorm(final HarnessTheStorm card) { @@ -46,77 +51,21 @@ public final class HarnessTheStorm extends CardImpl { } -class HarnessTheStormTriggeredAbility extends SpellCastControllerTriggeredAbility { - - private static final FilterInstantOrSorcerySpell filterSpell = new FilterInstantOrSorcerySpell("an instant or sorcery spell from your hand"); - - HarnessTheStormTriggeredAbility() { - super(new HarnessTheStormEffect(), filterSpell, false); - } - - private HarnessTheStormTriggeredAbility(final HarnessTheStormTriggeredAbility ability) { - super(ability); - } +enum HarnessTheStormAdjuster implements TargetAdjuster { + instance; @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (super.checkTrigger(event, game)) { - CastFromHandWatcher watcher = game.getState().getWatcher(CastFromHandWatcher.class); - if (watcher != null && watcher.spellWasCastFromHand(event.getSourceId())) { - Spell spell = game.getState().getStack().getSpell(event.getSourceId()); - if (spell != null) { - FilterCard filterCard = new FilterCard("a card named " + spell.getName() + " in your graveyard"); - filterCard.add(new NamePredicate(spell.getName())); - this.getTargets().clear(); - this.getTargets().add(new TargetCardInYourGraveyard(filterCard)); - return true; - } - } + public void adjustTargets(Ability ability, Game game) { + UUID spellId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability); + ability.getTargets().clear(); + ability.getAllEffects().setTargetPointer(new FirstTargetPointer()); + + Spell spell = game.getSpellOrLKIStack(spellId); + if (spell == null) { + return; } - return false; - } - - @Override - public HarnessTheStormTriggeredAbility copy() { - return new HarnessTheStormTriggeredAbility(this); - } - -} - -class HarnessTheStormEffect extends OneShotEffect { - - HarnessTheStormEffect() { - super(Outcome.Benefit); - this.staticText = "you may cast target card with the same name as that " - + "spell from your graveyard. (You still pay its costs.)"; - } - - private HarnessTheStormEffect(final HarnessTheStormEffect effect) { - super(effect); - } - - @Override - public HarnessTheStormEffect copy() { - return new HarnessTheStormEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - Card card = controller.getGraveyard().get(getTargetPointer().getFirst(game, source), game); - if (card == null) { - return false; - } - if (controller.chooseUse(outcome, "Cast " + card.getIdName() + " from your graveyard?", source, game)) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - controller.cast(controller.chooseAbilityForCast(card, game, false), - game, false, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - } - return true; - + FilterCard filter = new FilterCard("a card named " + spell.getName() + " in your graveyard"); + filter.add(new NamePredicate(spell.getName())); + ability.addTarget(new TargetCardInYourGraveyard(filter)); } } diff --git a/Mage.Sets/src/mage/cards/h/HarvesttideSentry.java b/Mage.Sets/src/mage/cards/h/HarvesttideSentry.java index cfb0164577f..6d63232e5ac 100644 --- a/Mage.Sets/src/mage/cards/h/HarvesttideSentry.java +++ b/Mage.Sets/src/mage/cards/h/HarvesttideSentry.java @@ -1,11 +1,10 @@ package mage.cards.h; import mage.MageInt; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.common.CovenCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; import mage.abilities.hint.common.CovenHint; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -19,7 +18,7 @@ import java.util.UUID; */ public final class HarvesttideSentry extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures with power 2 or less"); static { filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); @@ -34,13 +33,9 @@ public final class HarvesttideSentry extends CardImpl { this.toughness = new MageInt(1); // Coven — At the beginning of combat on your turn, if you control three or more creatures with different powers, Harvesttide Sentry can't be blocked by creatures with power 2 or less this turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - new CantBeBlockedByCreaturesSourceEffect(filter, Duration.EndOfTurn) - ), CovenCondition.instance, "At the beginning of combat on your turn, " + - "if you control three or more creatures with different powers, " + - "{this} can't be blocked by creatures with power 2 or less this turn." - ).addHint(CovenHint.instance).setAbilityWord(AbilityWord.COVEN)); + this.addAbility(new BeginningOfCombatTriggeredAbility( + new CantBeBlockedByCreaturesSourceEffect(filter, Duration.EndOfTurn) + ).withInterveningIf(CovenCondition.instance).addHint(CovenHint.instance).setAbilityWord(AbilityWord.COVEN)); } private HarvesttideSentry(final HarvesttideSentry card) { diff --git a/Mage.Sets/src/mage/cards/h/HateWeaver.java b/Mage.Sets/src/mage/cards/h/HateWeaver.java index feccdddab81..362ea023329 100644 --- a/Mage.Sets/src/mage/cards/h/HateWeaver.java +++ b/Mage.Sets/src/mage/cards/h/HateWeaver.java @@ -17,6 +17,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -41,7 +42,7 @@ public final class HateWeaver extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(1); Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(1, 0, Duration.EndOfTurn), new GenericManaCost(2)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HauntOfTheDeadMarshes.java b/Mage.Sets/src/mage/cards/h/HauntOfTheDeadMarshes.java index 8d38f3ac5d6..f587b2cfd43 100644 --- a/Mage.Sets/src/mage/cards/h/HauntOfTheDeadMarshes.java +++ b/Mage.Sets/src/mage/cards/h/HauntOfTheDeadMarshes.java @@ -5,7 +5,7 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; import mage.abilities.effects.keyword.ScryEffect; import mage.abilities.hint.ConditionHint; @@ -48,7 +48,7 @@ public final class HauntOfTheDeadMarshes extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(1, false))); // {2}{B}: Return Haunt of the Dead Marshes from your graveyard to the battlefield tapped. Activate only if you control a legendary creature. - this.addAbility(new ConditionalActivatedAbility( + this.addAbility(new ActivateIfConditionActivatedAbility( Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(true, false), new ManaCostsImpl<>("{2}{B}"), condition ).addHint(hint)); diff --git a/Mage.Sets/src/mage/cards/h/HauntedPlateMail.java b/Mage.Sets/src/mage/cards/h/HauntedPlateMail.java index 4fdf4194e4b..1905df694d5 100644 --- a/Mage.Sets/src/mage/cards/h/HauntedPlateMail.java +++ b/Mage.Sets/src/mage/cards/h/HauntedPlateMail.java @@ -1,47 +1,46 @@ - package mage.cards.h; -import java.util.UUID; -import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.keyword.EquipAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.ComparisonType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.StaticFilters; -import mage.game.permanent.token.TokenImpl; +import mage.constants.*; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.game.permanent.token.custom.CreatureToken; + +import java.util.UUID; /** - * * @author Plopman */ public final class HauntedPlateMail extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledCreaturePermanent("you control no creatures"), ComparisonType.EQUAL_TO, 0 + ); + public HauntedPlateMail(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); this.subtype.add(SubType.EQUIPMENT); // Equipped creature gets +4/+4. this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(4, 4))); + // {0}: Until end of turn, Haunted Plate Mail becomes a 4/4 Spirit artifact creature that's no longer an Equipment. Activate this ability only if you control no creatures. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, - new BecomesCreatureSourceEffect(new HauntedPlateMailToken(), CardType.ARTIFACT, Duration.EndOfTurn).andNotEquipment(true), - new ManaCostsImpl<>("{0}"), - new PermanentsOnTheBattlefieldCondition(StaticFilters.FILTER_PERMANENT_CREATURE, ComparisonType.EQUAL_TO, 0), - "{0}: Until end of turn, Haunted Plate Mail becomes a 4/4 Spirit artifact creature that's no longer an Equipment. Activate only if you control no creatures."); - this.addAbility(ability); + this.addAbility(new ActivateIfConditionActivatedAbility(new BecomesCreatureSourceEffect( + new CreatureToken( + 4, 4, "4/4 Spirit artifact " + + "creature that's no longer an Equipment", SubType.SPIRIT + ).withType(CardType.ARTIFACT), CardType.ARTIFACT, Duration.EndOfTurn + ).andNotEquipment(true).withDurationRuleAtStart(true), new GenericManaCost(0), condition)); + // Equip {4} this.addAbility(new EquipAbility(Outcome.BoostCreature, new ManaCostsImpl<>("{4}"))); } @@ -55,22 +54,3 @@ public final class HauntedPlateMail extends CardImpl { return new HauntedPlateMail(this); } } - -class HauntedPlateMailToken extends TokenImpl { - - public HauntedPlateMailToken() { - super("Spirit", "4/4 Spirit artifact creature that's no longer an Equipment"); - cardType.add(CardType.ARTIFACT); - cardType.add(CardType.CREATURE); - subtype.add(SubType.SPIRIT); - power = new MageInt(4); - toughness = new MageInt(4); - } - private HauntedPlateMailToken(final HauntedPlateMailToken token) { - super(token); - } - - public HauntedPlateMailToken copy() { - return new HauntedPlateMailToken(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HavengulSkaab.java b/Mage.Sets/src/mage/cards/h/HavengulSkaab.java index fcdede83ef3..445ced869f9 100644 --- a/Mage.Sets/src/mage/cards/h/HavengulSkaab.java +++ b/Mage.Sets/src/mage/cards/h/HavengulSkaab.java @@ -1,27 +1,23 @@ package mage.cards.h; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.ReturnToHandChosenControlledPermanentEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author noxx */ public final class HavengulSkaab extends CardImpl { public HavengulSkaab(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.HORROR); @@ -29,7 +25,7 @@ public final class HavengulSkaab extends CardImpl { this.toughness = new MageInt(5); // Whenever Havengul Skaab attacks, return another creature you control to its owner's hand. - this.addAbility(new HavengulSkaabAbility()); + this.addAbility(new AttacksTriggeredAbility(new ReturnToHandChosenControlledPermanentEffect(StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL))); } private HavengulSkaab(final HavengulSkaab card) { @@ -41,39 +37,3 @@ public final class HavengulSkaab extends CardImpl { return new HavengulSkaab(this); } } - -class HavengulSkaabAbility extends TriggeredAbilityImpl { - - public HavengulSkaabAbility() { - super(Zone.BATTLEFIELD, new ReturnToHandTargetEffect()); - } - - private HavengulSkaabAbility(final HavengulSkaabAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ATTACKER_DECLARED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getSourceId().equals(this.getSourceId())) { - TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(1, 1, StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL, true); - this.addTarget(target); - return true; - } - return false; - } - - @Override - public String getRule() { - return "Whenever {this} attacks, return another creature you control to its owner's hand."; - } - - @Override - public HavengulSkaabAbility copy() { - return new HavengulSkaabAbility(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HazduhrTheAbbot.java b/Mage.Sets/src/mage/cards/h/HazduhrTheAbbot.java index cc5bae4eb23..24692c5aced 100644 --- a/Mage.Sets/src/mage/cards/h/HazduhrTheAbbot.java +++ b/Mage.Sets/src/mage/cards/h/HazduhrTheAbbot.java @@ -1,4 +1,3 @@ - package mage.cards.h; import mage.MageInt; @@ -10,25 +9,27 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.RedirectionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; -import mage.target.common.TargetControlledCreaturePermanent; import mage.util.CardUtil; import java.util.UUID; /** - * * @author TheElk801 & L_J */ public final class HazduhrTheAbbot extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("white creature you control"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("white creature you control"); static { filter.add(new ColorPredicate(ObjectColor.WHITE)); @@ -45,7 +46,7 @@ public final class HazduhrTheAbbot extends CardImpl { // {X}, {T}: The next X damage that would be dealt this turn to target white creature you control is dealt to Hazduhr the Abbot instead. Ability ability = new SimpleActivatedAbility(new HazduhrTheAbbotRedirectDamageEffect(Duration.EndOfTurn), new ManaCostsImpl<>("{X}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetControlledCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } @@ -61,8 +62,6 @@ public final class HazduhrTheAbbot extends CardImpl { class HazduhrTheAbbotRedirectDamageEffect extends RedirectionEffect { - private static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); - public HazduhrTheAbbotRedirectDamageEffect(Duration duration) { super(duration, 0, UsageType.ACCORDING_DURATION); this.staticText = "The next X damage that would be dealt this turn to target white creature you control is dealt to {this} instead"; @@ -85,19 +84,15 @@ class HazduhrTheAbbotRedirectDamageEffect extends RedirectionEffect { @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - if (filter.match(permanent, permanent.getControllerId(), source, game)) { - if (event.getTargetId().equals(getTargetPointer().getFirst(game, source))) { - if (event.getTargetId() != null) { - TargetPermanent target = new TargetPermanent(); - target.add(source.getSourceId(), game); - redirectTarget = target; - return true; - } - } - } + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null + || !event.getTargetId().equals(getTargetPointer().getFirst(game, source)) + || event.getTargetId() == null) { + return false; } - return false; + TargetPermanent target = new TargetPermanent(); + target.add(source.getSourceId(), game); + redirectTarget = target; + return true; } } diff --git a/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java b/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java index 2355abcea95..4bd75592ac4 100644 --- a/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java +++ b/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java @@ -79,6 +79,8 @@ class HazoretsUndyingFuryEffect extends OneShotEffect { // move cards from library to exile Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 4)); controller.moveCards(cards, Zone.EXILED, source, game); + game.processAction(); + cards.retainZone(Zone.EXILED, game); // cast the possible cards without paying the mana CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, filter); return true; diff --git a/Mage.Sets/src/mage/cards/h/HeadlessSpecter.java b/Mage.Sets/src/mage/cards/h/HeadlessSpecter.java index 37de60a499f..064186332db 100644 --- a/Mage.Sets/src/mage/cards/h/HeadlessSpecter.java +++ b/Mage.Sets/src/mage/cards/h/HeadlessSpecter.java @@ -3,11 +3,11 @@ package mage.cards.h; import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.condition.common.HellbentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; @@ -29,12 +29,9 @@ public final class HeadlessSpecter extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Hellbent — Whenever Headless Specter deals combat damage to a player, if you have no cards in hand, that player discards a card at random. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new DealsCombatDamageToAPlayerTriggeredAbility( - new DiscardTargetEffect(1, true), false, true - ), HellbentCondition.instance, "Hellbent — Whenever {this} deals combat damage " + - "to a player, if you have no cards in hand, that player discards a card at random." - )); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new DiscardTargetEffect(1, true), false, true + ).withInterveningIf(HellbentCondition.instance).setAbilityWord(AbilityWord.HELLBENT)); } private HeadlessSpecter(final HeadlessSpecter card) { diff --git a/Mage.Sets/src/mage/cards/h/HeartPiercerBow.java b/Mage.Sets/src/mage/cards/h/HeartPiercerBow.java index 72b32c2cd14..52cb3ab0a6d 100644 --- a/Mage.Sets/src/mage/cards/h/HeartPiercerBow.java +++ b/Mage.Sets/src/mage/cards/h/HeartPiercerBow.java @@ -12,6 +12,7 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.DefendingPlayerControlsAttachedAttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -33,7 +34,7 @@ public final class HeartPiercerBow extends CardImpl { // Whenever equipped creature attacks, Heart-Piercer Bow deals 1 damage to target creature defending player controls. Ability ability = new AttacksAttachedTriggeredAbility(new DamageTargetEffect(1)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Equip {1} diff --git a/Mage.Sets/src/mage/cards/h/HeartPiercerManticore.java b/Mage.Sets/src/mage/cards/h/HeartPiercerManticore.java index 0a17b5860db..9e9efc8e9f2 100644 --- a/Mage.Sets/src/mage/cards/h/HeartPiercerManticore.java +++ b/Mage.Sets/src/mage/cards/h/HeartPiercerManticore.java @@ -1,9 +1,11 @@ package mage.cards.h; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; @@ -15,11 +17,7 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.Target; -import mage.target.common.TargetAnyTarget; -import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; @@ -36,7 +34,7 @@ public final class HeartPiercerManticore extends CardImpl { this.toughness = new MageInt(3); // When Heart-Piercer Manticore enters the battlefield, you may sacrifice another creature. When you do, Heart-Piercer Manticore deals damage equal to that creature's power to any target. - this.addAbility(new EntersBattlefieldTriggeredAbility(new HeartPiercerManticoreSacrificeEffect(), true)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new HeartPiercerManticoreEffect())); // Embalm {5}{R} this.addAbility(new EmbalmAbility(new ManaCostsImpl<>("{5}{R}"), this)); @@ -52,21 +50,21 @@ public final class HeartPiercerManticore extends CardImpl { } } -class HeartPiercerManticoreSacrificeEffect extends OneShotEffect { +class HeartPiercerManticoreEffect extends OneShotEffect { - HeartPiercerManticoreSacrificeEffect() { + HeartPiercerManticoreEffect() { super(Outcome.Damage); - this.staticText = "sacrifice another creature. When you do, " + this.staticText = "you may sacrifice another creature. When you do, " + "{this} deals damage equal to that creature's power to any target"; } - private HeartPiercerManticoreSacrificeEffect(final HeartPiercerManticoreSacrificeEffect effect) { + private HeartPiercerManticoreEffect(final HeartPiercerManticoreEffect effect) { super(effect); } @Override - public HeartPiercerManticoreSacrificeEffect copy() { - return new HeartPiercerManticoreSacrificeEffect(this); + public HeartPiercerManticoreEffect copy() { + return new HeartPiercerManticoreEffect(this); } @Override @@ -75,26 +73,22 @@ class HeartPiercerManticoreSacrificeEffect extends OneShotEffect { if (controller == null) { return false; } - Target target = new TargetControlledCreaturePermanent( - 1, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, true - ); - if (!controller.choose(outcome, target, source, game)) { - return false; - } - Permanent toSacrifice = game.getPermanent(target.getFirstTarget()); - if (toSacrifice == null) { - return false; - } - int power = toSacrifice.getPower().getValue(); - if (!toSacrifice.sacrifice(source, game)) { + SacrificeTargetCost cost = new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE); + if (!cost.canPay(source, source, source.getControllerId(), game) + || !controller.chooseUse(outcome, "Sacrifice another creature?", source, game) + || !cost.pay(source, game, source, source.getControllerId(), false)) { return false; } + int power = cost + .getPermanents() + .stream() + .map(MageObject::getPower) + .mapToInt(MageInt::getValue) + .sum(); ReflexiveTriggeredAbility trigger = new ReflexiveTriggeredAbility( new DamageTargetEffect(power), false, "{this} deals damage equal to that creature's power to any target." ); - trigger.addTarget(new TargetAnyTarget()); - game.fireReflexiveTriggeredAbility(trigger, source); return true; } } diff --git a/Mage.Sets/src/mage/cards/h/HeartWolf.java b/Mage.Sets/src/mage/cards/h/HeartWolf.java index 3ec610c1759..abf8410c7e6 100644 --- a/Mage.Sets/src/mage/cards/h/HeartWolf.java +++ b/Mage.Sets/src/mage/cards/h/HeartWolf.java @@ -1,28 +1,30 @@ package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.IsPhaseCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.constants.*; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author noahg */ public final class HeartWolf extends CardImpl { @@ -33,9 +35,11 @@ public final class HeartWolf extends CardImpl { filter.add(SubType.DWARF.getPredicate()); } + private static final Condition condition = new IsPhaseCondition(TurnPhase.COMBAT); + public HeartWolf(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); - + this.subtype.add(SubType.WOLF); this.power = new MageInt(2); this.toughness = new MageInt(2); @@ -44,11 +48,14 @@ public final class HeartWolf extends CardImpl { this.addAbility(FirstStrikeAbility.getInstance()); // {tap}: Target Dwarf creature gets +2/+0 and gains first strike until end of turn. When that creature leaves the battlefield this turn, sacrifice Heart Wolf. Activate this ability only during combat. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(2, 0, Duration.EndOfTurn) - .setText("Target Dwarf creature gets +2/+0"), new TapSourceCost(), new IsPhaseCondition(TurnPhase.COMBAT)); + Ability ability = new ActivateIfConditionActivatedAbility( + new BoostTargetEffect(2, 0, Duration.EndOfTurn) + .setText("Target Dwarf creature gets +2/+0"), + new TapSourceCost(), condition + ); ability.addEffect(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn).setText("and gains first strike until end of turn")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new HeartWolfDelayedTriggeredAbility(), true)); this.addAbility(ability); } @@ -97,4 +104,4 @@ class HeartWolfDelayedTriggeredAbility extends DelayedTriggeredAbility { public String getRule() { return "When that creature leaves the battlefield this turn, sacrifice {this}."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/h/HearthCharm.java b/Mage.Sets/src/mage/cards/h/HearthCharm.java index 427b8409585..af2c34646a0 100644 --- a/Mage.Sets/src/mage/cards/h/HearthCharm.java +++ b/Mage.Sets/src/mage/cards/h/HearthCharm.java @@ -13,8 +13,11 @@ import mage.constants.Duration; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE; + /** * * @author LoneFox @@ -32,13 +35,13 @@ public final class HearthCharm extends CardImpl { // Choose one - Destroy target artifact creature this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_ARTIFACT_CREATURE)); // or attacking creatures get +1/+0 until end of turn Mode mode = new Mode(new BoostAllEffect(1, 0, Duration.EndOfTurn, StaticFilters.FILTER_ATTACKING_CREATURES, false)); this.getSpellAbility().addMode(mode); // or target creature with power 2 or less is unblockable this turn. mode = new Mode(new CantBeBlockedTargetEffect()); - mode.addTarget(new TargetCreaturePermanent(filter)); + mode.addTarget(new TargetPermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/h/HearthcageGiant.java b/Mage.Sets/src/mage/cards/h/HearthcageGiant.java index dc2d93b9588..3b6988d9bc3 100644 --- a/Mage.Sets/src/mage/cards/h/HearthcageGiant.java +++ b/Mage.Sets/src/mage/cards/h/HearthcageGiant.java @@ -18,6 +18,7 @@ import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.game.permanent.token.ElementalShamanToken; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; @@ -48,7 +49,7 @@ public final class HearthcageGiant extends CardImpl { //Sacrifice an Elemental: Target Giant creature gets +3/+1 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(3, 1, Duration.EndOfTurn), new SacrificeTargetCost(filterElemental)); - ability.addTarget(new TargetCreaturePermanent(filterGiant)); + ability.addTarget(new TargetPermanent(filterGiant)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HeartstabberMosquito.java b/Mage.Sets/src/mage/cards/h/HeartstabberMosquito.java index 93ee5757008..d91b07cf385 100644 --- a/Mage.Sets/src/mage/cards/h/HeartstabberMosquito.java +++ b/Mage.Sets/src/mage/cards/h/HeartstabberMosquito.java @@ -1,11 +1,9 @@ - package mage.cards.h; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.KickerAbility; @@ -15,14 +13,15 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class HeartstabberMosquito extends CardImpl { public HeartstabberMosquito(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.subtype.add(SubType.INSECT); this.power = new MageInt(2); @@ -31,14 +30,13 @@ public final class HeartstabberMosquito extends CardImpl { // Kicker {2}{B} (You may pay an additional {2}{B} as you cast this spell.) this.addAbility(new KickerAbility("{2}{B}")); - // Flying this.addAbility(FlyingAbility.getInstance()); // When Heartstabber Mosquito enters the battlefield, if it was kicked, destroy target creature. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), false); + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), false).withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.ONCE, "When {this} enters, if it was kicked, destroy target creature.")); + this.addAbility(ability); } private HeartstabberMosquito(final HeartstabberMosquito card) { diff --git a/Mage.Sets/src/mage/cards/h/HeavyInfantry.java b/Mage.Sets/src/mage/cards/h/HeavyInfantry.java index 4ee8a10b8c1..acab80545c4 100644 --- a/Mage.Sets/src/mage/cards/h/HeavyInfantry.java +++ b/Mage.Sets/src/mage/cards/h/HeavyInfantry.java @@ -11,8 +11,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -28,7 +31,7 @@ public final class HeavyInfantry extends CardImpl { // When Heavy Infantry enters the battlefield, tap target creature an opponent controls. Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HeidarRimewindMaster.java b/Mage.Sets/src/mage/cards/h/HeidarRimewindMaster.java index 227e47fc90b..6f9b7c9ac05 100644 --- a/Mage.Sets/src/mage/cards/h/HeidarRimewindMaster.java +++ b/Mage.Sets/src/mage/cards/h/HeidarRimewindMaster.java @@ -1,10 +1,9 @@ - package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; @@ -12,27 +11,30 @@ import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; +import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class HeidarRimewindMaster extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("you control four or more snow permanents"); + private static final FilterPermanent filter = new FilterControlledPermanent("you control four or more snow permanents"); static { filter.add(SuperType.SNOW.getPredicate()); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 3); + public HeidarRimewindMaster(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); @@ -40,10 +42,9 @@ public final class HeidarRimewindMaster extends CardImpl { this.toughness = new MageInt(3); // {2}, {tap}: Return target permanent to its owner's hand. Activate this ability only if you control four or more snow permanents. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new ReturnToHandTargetEffect(), - new GenericManaCost(2), - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 3)); + Ability ability = new ActivateIfConditionActivatedAbility( + new ReturnToHandTargetEffect(), new GenericManaCost(2), condition + ); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetPermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/h/HeirOfTheWilds.java b/Mage.Sets/src/mage/cards/h/HeirOfTheWilds.java index 50d3890ca83..18ebc9a2b6f 100644 --- a/Mage.Sets/src/mage/cards/h/HeirOfTheWilds.java +++ b/Mage.Sets/src/mage/cards/h/HeirOfTheWilds.java @@ -1,15 +1,14 @@ package mage.cards.h; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.FerociousCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.hint.common.FerociousHint; import mage.abilities.keyword.DeathtouchAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; @@ -31,15 +30,11 @@ public final class HeirOfTheWilds extends CardImpl { // Deathtouch this.addAbility(DeathtouchAbility.getInstance()); - // Ferocious - Whenever Heir of the Wilds attacks, if you control a creature with power 4 or greater, Heir of the Wilds gets +1/+1 until end of turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn), false), - FerociousCondition.instance, - "Ferocious — Whenever {this} attacks, if you control a creature with power 4 or greater, {this} gets +1/+1 until end of turn." - ); - ability.addHint(FerociousHint.instance); - this.addAbility(ability); + // Ferocious - Whenever Heir of the Wilds attacks, if you control a creature with power 4 or greater, Heir of the Wilds gets +1/+1 until end of turn. + this.addAbility(new AttacksTriggeredAbility( + new BoostSourceEffect(1, 1, Duration.EndOfTurn), false + ).withInterveningIf(FerociousCondition.instance).addHint(FerociousHint.instance).setAbilityWord(AbilityWord.FEROCIOUS)); } private HeirOfTheWilds(final HeirOfTheWilds card) { diff --git a/Mage.Sets/src/mage/cards/h/HeliodsEmissary.java b/Mage.Sets/src/mage/cards/h/HeliodsEmissary.java index 39c1aac2ece..18f4430cf9d 100644 --- a/Mage.Sets/src/mage/cards/h/HeliodsEmissary.java +++ b/Mage.Sets/src/mage/cards/h/HeliodsEmissary.java @@ -19,8 +19,11 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.StaticFilters; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -38,11 +41,11 @@ public final class HeliodsEmissary extends CardImpl { this.addAbility(new BestowAbility(this, "{6}{W}")); // Whenever Heliod's Emissary or enchanted creature attacks, tap target creature an opponent controls. Ability ability = new AttacksTriggeredAbility(new TapTargetEffect(), false); - Target target = new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE); + Target target = new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE); ability.addTarget(target); this.addAbility(ability); ability = new AttacksAttachedTriggeredAbility(new TapTargetEffect(), AttachmentType.AURA, false); - target = new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE); + target = new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE); ability.addTarget(target); this.addAbility(ability); // Enchanted creature gets +3/+3. diff --git a/Mage.Sets/src/mage/cards/h/HeliumSquirter.java b/Mage.Sets/src/mage/cards/h/HeliumSquirter.java index edb6b49f36e..cf8c96e33cf 100644 --- a/Mage.Sets/src/mage/cards/h/HeliumSquirter.java +++ b/Mage.Sets/src/mage/cards/h/HeliumSquirter.java @@ -16,8 +16,11 @@ import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_CREATURE_P1P1; + /** * * @author JotaPeRL @@ -36,7 +39,7 @@ public final class HeliumSquirter extends CardImpl { // {1}: Target creature with a +1/+1 counter on it gains flying until end of turn. Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), new GenericManaCost(1)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_P1P1)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_P1P1)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/Helldozer.java b/Mage.Sets/src/mage/cards/h/Helldozer.java index df448a2acd9..8358a6d1b46 100644 --- a/Mage.Sets/src/mage/cards/h/Helldozer.java +++ b/Mage.Sets/src/mage/cards/h/Helldozer.java @@ -1,6 +1,5 @@ package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -10,15 +9,15 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetLandPermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class Helldozer extends CardImpl { @@ -55,7 +54,7 @@ class HelldozerEffect extends OneShotEffect { HelldozerEffect() { super(Outcome.DestroyPermanent); - this.staticText = "Destroy target land. If that land was nonbasic, untap Helldozer"; + this.staticText = "Destroy target land. If that land was nonbasic, untap {this}"; } private HelldozerEffect(final HelldozerEffect effect) { diff --git a/Mage.Sets/src/mage/cards/h/HellfireMongrel.java b/Mage.Sets/src/mage/cards/h/HellfireMongrel.java index df2bad6a1d6..527669c7bd4 100644 --- a/Mage.Sets/src/mage/cards/h/HellfireMongrel.java +++ b/Mage.Sets/src/mage/cards/h/HellfireMongrel.java @@ -1,13 +1,11 @@ package mage.cards.h; -import java.util.UUID; import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.condition.common.CardsInHandCondition; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.CardsInHandCondition; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -15,14 +13,17 @@ import mage.constants.ComparisonType; import mage.constants.SubType; import mage.constants.TargetController; +import java.util.UUID; + /** - * * @author North */ public final class HellfireMongrel extends CardImpl { + private static final Condition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 3, TargetController.ACTIVE); + public HellfireMongrel(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); this.subtype.add(SubType.ELEMENTAL); this.subtype.add(SubType.DOG); @@ -30,11 +31,11 @@ public final class HellfireMongrel extends CardImpl { this.toughness = new MageInt(2); // At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, Hellfire Mongrel deals 2 damage to that player. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(TargetController.OPPONENT, new DamageTargetEffect(2), false), - (Condition)new CardsInHandCondition(ComparisonType.FEWER_THAN, 3, TargetController.ACTIVE), - "At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, {this} deals 2 damage to that player." - )); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.OPPONENT, + new DamageTargetEffect(2, true, "that player"), + false + ).withInterveningIf(condition)); } private HellfireMongrel(final HellfireMongrel card) { diff --git a/Mage.Sets/src/mage/cards/h/HellkiteTyrant.java b/Mage.Sets/src/mage/cards/h/HellkiteTyrant.java index 2fca3826bd8..a4eae8d7156 100644 --- a/Mage.Sets/src/mage/cards/h/HellkiteTyrant.java +++ b/Mage.Sets/src/mage/cards/h/HellkiteTyrant.java @@ -2,17 +2,15 @@ package mage.cards.h; import mage.MageInt; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.WinGameSourceControllerEffect; import mage.abilities.effects.common.continuous.GainControlAllControlledTargetEffect; -import mage.abilities.hint.ValueHint; +import mage.abilities.hint.common.ArtifactYouControlHint; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -28,6 +26,10 @@ import java.util.UUID; */ public final class HellkiteTyrant extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterArtifactPermanent("you control twenty or more artifacts"), ComparisonType.MORE_THAN, 19 + ); + public HellkiteTyrant(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}{R}"); this.subtype.add(SubType.DRAGON); @@ -37,8 +39,10 @@ public final class HellkiteTyrant extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); + // Trample this.addAbility(TrampleAbility.getInstance()); + // Whenever Hellkite Tyrant deals combat damage to a player, gain control of all artifacts that player controls. this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( new GainControlAllControlledTargetEffect(StaticFilters.FILTER_PERMANENT_ARTIFACTS) @@ -46,12 +50,8 @@ public final class HellkiteTyrant extends CardImpl { false, true)); // At the beginning of your upkeep, if you control twenty or more artifacts, you win the game. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - ability, - new PermanentsOnTheBattlefieldCondition(new FilterArtifactPermanent(), ComparisonType.MORE_THAN, 19), - "At the beginning of your upkeep, if you control twenty or more artifacts, you win the game." - ).addHint(new ValueHint("Artifacts you control", new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT)))); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect()) + .withInterveningIf(condition).addHint(ArtifactYouControlHint.instance)); } private HellkiteTyrant(final HellkiteTyrant card) { diff --git a/Mage.Sets/src/mage/cards/h/HellsCaretaker.java b/Mage.Sets/src/mage/cards/h/HellsCaretaker.java index 39466c7193c..9ad03a7e746 100644 --- a/Mage.Sets/src/mage/cards/h/HellsCaretaker.java +++ b/Mage.Sets/src/mage/cards/h/HellsCaretaker.java @@ -1,25 +1,22 @@ - package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.PhaseStep; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author fireshoes */ public final class HellsCaretaker extends CardImpl { @@ -31,10 +28,10 @@ public final class HellsCaretaker extends CardImpl { this.toughness = new MageInt(1); // {tap}, Sacrifice a creature: Return target creature card from your graveyard to the battlefield. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, + Ability ability = new ActivateIfConditionActivatedAbility( new ReturnFromGraveyardToBattlefieldTargetEffect(), - new TapSourceCost(), - new IsStepCondition(PhaseStep.UPKEEP)); + new TapSourceCost(), IsStepCondition.getMyUpkeep() + ); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE)); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/h/HellsThunder.java b/Mage.Sets/src/mage/cards/h/HellsThunder.java index fc671208711..ad6c9aa47dc 100644 --- a/Mage.Sets/src/mage/cards/h/HellsThunder.java +++ b/Mage.Sets/src/mage/cards/h/HellsThunder.java @@ -1,29 +1,27 @@ - - package mage.cards.h; -import java.util.UUID; import mage.MageInt; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.UnearthAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.events.GameEvent.EventType; +import mage.constants.TargetController; + +import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com */ public final class HellsThunder extends CardImpl { public HellsThunder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(4); @@ -31,9 +29,10 @@ public final class HellsThunder extends CardImpl { this.addAbility(FlyingAbility.getInstance()); this.addAbility(HasteAbility.getInstance()); - this.addAbility(new OnEventTriggeredAbility(EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new SacrificeSourceEffect())); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.NEXT, new SacrificeSourceEffect(), false + )); this.addAbility(new UnearthAbility(new ManaCostsImpl<>("{4}{R}"))); - } private HellsThunder(final HellsThunder card) { diff --git a/Mage.Sets/src/mage/cards/h/HellsparkElemental.java b/Mage.Sets/src/mage/cards/h/HellsparkElemental.java index ef3573fb740..314a3909c4d 100644 --- a/Mage.Sets/src/mage/cards/h/HellsparkElemental.java +++ b/Mage.Sets/src/mage/cards/h/HellsparkElemental.java @@ -1,21 +1,19 @@ - - package mage.cards.h; -import java.util.UUID; import mage.MageInt; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.UnearthAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.events.GameEvent.EventType; +import mage.constants.TargetController; +import java.util.UUID; /** * @author BetaSteward_at_googlemail.com @@ -23,7 +21,7 @@ import mage.game.events.GameEvent.EventType; public final class HellsparkElemental extends CardImpl { public HellsparkElemental(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(3); @@ -34,7 +32,9 @@ public final class HellsparkElemental extends CardImpl { this.addAbility(HasteAbility.getInstance()); // At the beginning of the end step, sacrifice Hellspark Elemental. - this.addAbility(new OnEventTriggeredAbility(EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new SacrificeSourceEffect())); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.NEXT, new SacrificeSourceEffect(), false + )); // Unearth {1}{R}: Return this card from your graveyard to the battlefield. It gains haste. Exile it at the beginning of the next end step or if it would leave the battlefield. Unearth only as a sorcery.) this.addAbility(new UnearthAbility(new ManaCostsImpl<>("{1}{R}"))); diff --git a/Mage.Sets/src/mage/cards/h/HelmOfKaldra.java b/Mage.Sets/src/mage/cards/h/HelmOfKaldra.java index b8b92c6c6b9..092f50e31f2 100644 --- a/Mage.Sets/src/mage/cards/h/HelmOfKaldra.java +++ b/Mage.Sets/src/mage/cards/h/HelmOfKaldra.java @@ -1,16 +1,10 @@ - package mage.cards.h; -import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.Condition; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EquipAbility; import mage.abilities.keyword.FirstStrikeAbility; @@ -19,51 +13,48 @@ import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate; +import mage.game.Controllable; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.KaldraToken; +import mage.game.permanent.token.Token; +import mage.target.TargetPermanent; +import mage.util.RandomUtil; + +import java.util.*; +import java.util.stream.Collectors; /** - * * @author LevelX2 */ public final class HelmOfKaldra extends CardImpl { - static final FilterControlledArtifactPermanent filterHelm = new FilterControlledArtifactPermanent(); - static final FilterControlledArtifactPermanent filterShield = new FilterControlledArtifactPermanent(); - static final FilterControlledArtifactPermanent filterSword = new FilterControlledArtifactPermanent(); - - static { - filterHelm.add(new NamePredicate("Helm of Kaldra")); - filterShield.add(new NamePredicate("Shield of Kaldra")); - filterSword.add(new NamePredicate("Sword of Kaldra")); - } - public HelmOfKaldra(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.EQUIPMENT); // Equipped creature has first strike, trample, and haste. - Ability ability = new SimpleStaticAbility(new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.EQUIPMENT)); - Effect effect = new GainAbilityAttachedEffect(TrampleAbility.getInstance(), AttachmentType.EQUIPMENT); - effect.setText(", trample"); - ability.addEffect(effect); - effect = new GainAbilityAttachedEffect(HasteAbility.getInstance(), AttachmentType.EQUIPMENT); - effect.setText(", and haste"); - ability.addEffect(effect); + Ability ability = new SimpleStaticAbility(new GainAbilityAttachedEffect( + FirstStrikeAbility.getInstance(), AttachmentType.EQUIPMENT + )); + ability.addEffect(new GainAbilityAttachedEffect( + TrampleAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText(", trample")); + ability.addEffect(new GainAbilityAttachedEffect( + HasteAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText(", and haste")); this.addAbility(ability); + // {1}: If you control Equipment named Helm of Kaldra, Sword of Kaldra, and Shield of Kaldra, create a legendary 4/4 colorless Avatar creature token named Kaldra and attach those Equipment to it. - this.addAbility(new ConditionalActivatedAbility( - Zone.BATTLEFIELD, - new HelmOfKaldraEffect(), - new GenericManaCost(1), - new HelmOfKaldraCondition(), - "{1}: If you control Equipment named Helm of Kaldra, Sword of Kaldra, and Shield of Kaldra, create Kaldra, a legendary 4/4 colorless Avatar creature token. Attach those Equipment to it.")); + this.addAbility(new SimpleActivatedAbility(new HelmOfKaldraEffect(), new GenericManaCost(1))); + // Equip {2} - this.addAbility(new EquipAbility(Outcome.Benefit, new ManaCostsImpl<>("{2}"), false)); + this.addAbility(new EquipAbility(2, false)); } private HelmOfKaldra(final HelmOfKaldra card) { @@ -76,26 +67,22 @@ public final class HelmOfKaldra extends CardImpl { } } -class HelmOfKaldraCondition implements Condition { - - @Override - public boolean apply(Game game, Ability source) { - if (game.getBattlefield().count(HelmOfKaldra.filterHelm, source.getControllerId(), source, game) < 1) { - return false; - } - if (game.getBattlefield().count(HelmOfKaldra.filterSword, source.getControllerId(), source, game) < 1) { - return false; - } - return game.getBattlefield().count(HelmOfKaldra.filterShield, source.getControllerId(), source, game) >= 1; - } - -} - class HelmOfKaldraEffect extends OneShotEffect { + private static final FilterPermanent filterHelm = new FilterControlledPermanent(SubType.EQUIPMENT); + private static final FilterPermanent filterSword = new FilterControlledPermanent(SubType.EQUIPMENT); + private static final FilterPermanent filterShield = new FilterControlledPermanent(SubType.EQUIPMENT); + + static { + filterHelm.add(new NamePredicate("Helm of Kaldra")); + filterSword.add(new NamePredicate("Sword of Kaldra")); + filterShield.add(new NamePredicate("Shield of Kaldra")); + } + HelmOfKaldraEffect() { super(Outcome.Benefit); - this.staticText = "if you control Equipment named Helm of Kaldra, Sword of Kaldra, and Shield of Kaldra, create Kaldra, a legendary 4/4 colorless Avatar creature token. Attach those Equipment to it"; + this.staticText = "if you control Equipment named Helm of Kaldra, Sword of Kaldra, and Shield of Kaldra, " + + "create Kaldra, a legendary 4/4 colorless Avatar creature token. Attach those Equipment to it"; } private HelmOfKaldraEffect(final HelmOfKaldraEffect effect) { @@ -109,32 +96,48 @@ class HelmOfKaldraEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - if (new HelmOfKaldraCondition().apply(game, source)) { - CreateTokenEffect effect = new CreateTokenEffect(new KaldraToken()); - effect.apply(game, source); - for (UUID tokenId : effect.getLastAddedTokenIds()) { - Permanent kaldra = game.getPermanent(tokenId); - if (kaldra != null) { - // Attach helm to the token - for (Permanent kaldrasHelm : game.getBattlefield().getAllActivePermanents(HelmOfKaldra.filterHelm, source.getControllerId(), game)) { - kaldra.addAttachment(kaldrasHelm.getId(), source, game); - break; - } - // Attach shield to the token - for (Permanent kaldrasShield : game.getBattlefield().getAllActivePermanents(HelmOfKaldra.filterShield, source.getControllerId(), game)) { - kaldra.addAttachment(kaldrasShield.getId(), source, game); - break; - } - // Attach sword to the token - for (Permanent kaldrasSword : game.getBattlefield().getAllActivePermanents(HelmOfKaldra.filterSword, source.getControllerId(), game)) { - kaldra.addAttachment(kaldrasSword.getId(), source, game); - break; - } - - } - return true; - } + if (!game.getBattlefield().contains(filterHelm, source, game, 1) + || !game.getBattlefield().contains(filterSword, source, game, 1) + || !game.getBattlefield().contains(filterShield, source, game, 1)) { + return false; } - return false; + Token token = new KaldraToken(); + token.putOntoBattlefield(1, game, source); + Set permanents = token + .getLastAddedTokenIds() + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + Permanent permanent; + switch (permanents.size()) { + case 0: + return true; + case 1: + permanent = RandomUtil.randomFromCollection(permanents); + break; + default: + FilterPermanent filter = new FilterPermanent(); + filter.add(new PermanentReferenceInCollectionPredicate(permanents, game)); + TargetPermanent target = new TargetPermanent(filter); + target.withNotTarget(true); + target.withChooseHint("to equip"); + Optional.ofNullable(source) + .map(Controllable::getControllerId) + .map(game::getPlayer) + .ifPresent(player -> player.choose(outcome, target, source, game)); + permanent = game.getPermanent(target.getFirstTarget()); + } + if (permanent == null) { + return true; + } + Set equipments = new HashSet<>(); + equipments.addAll(game.getBattlefield().getActivePermanents(filterHelm, source.getControllerId(), source, game)); + equipments.addAll(game.getBattlefield().getActivePermanents(filterSword, source.getControllerId(), source, game)); + equipments.addAll(game.getBattlefield().getActivePermanents(filterShield, source.getControllerId(), source, game)); + for (Permanent equipment : equipments) { + permanent.addAttachment(equipment.getId(), source, game); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/h/Helvault.java b/Mage.Sets/src/mage/cards/h/Helvault.java index 2e5d365b095..42eb33d43a2 100644 --- a/Mage.Sets/src/mage/cards/h/Helvault.java +++ b/Mage.Sets/src/mage/cards/h/Helvault.java @@ -12,11 +12,14 @@ import mage.constants.CardType; import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author North */ @@ -35,7 +38,7 @@ public final class Helvault extends CardImpl { // {7}, {T}: Exile target creature you don't control. ability = new SimpleActivatedAbility(new ExileTargetForSourceEffect(), new GenericManaCost(7)); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.addAbility(ability); // When Helvault is put into a graveyard from the battlefield, return all cards exiled with it to the battlefield under their owners' control. diff --git a/Mage.Sets/src/mage/cards/h/HeraldOfTheForgotten.java b/Mage.Sets/src/mage/cards/h/HeraldOfTheForgotten.java index 0bbb6d8dd8b..4a8f1a33701 100644 --- a/Mage.Sets/src/mage/cards/h/HeraldOfTheForgotten.java +++ b/Mage.Sets/src/mage/cards/h/HeraldOfTheForgotten.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.keyword.CyclingAbility; import mage.abilities.keyword.FlyingAbility; @@ -43,11 +42,8 @@ public final class HeraldOfTheForgotten extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Herald of the Forgotten enters the battlefield, if you cast it, return any number of target permanent cards with cycling abilities from your graveyard to the battlefield. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()), - CastFromEverywhereSourceCondition.instance, "When {this} enters, if you cast it, " + - "return any number of target permanent cards with cycling abilities from your graveyard to the battlefield." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()) + .withInterveningIf(CastFromEverywhereSourceCondition.instance); ability.addTarget(new TargetCardInYourGraveyard(0, Integer.MAX_VALUE, filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HerosDemise.java b/Mage.Sets/src/mage/cards/h/HerosDemise.java index f44114f97d2..bec797fc7c3 100644 --- a/Mage.Sets/src/mage/cards/h/HerosDemise.java +++ b/Mage.Sets/src/mage/cards/h/HerosDemise.java @@ -8,6 +8,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SuperType; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -27,7 +28,7 @@ public final class HerosDemise extends CardImpl { // Destroy target legendary creature. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private HerosDemise(final HerosDemise card) { diff --git a/Mage.Sets/src/mage/cards/h/Hexavus.java b/Mage.Sets/src/mage/cards/h/Hexavus.java index 950797b7b41..d8d53b76ee3 100644 --- a/Mage.Sets/src/mage/cards/h/Hexavus.java +++ b/Mage.Sets/src/mage/cards/h/Hexavus.java @@ -21,6 +21,8 @@ import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * @author PurpleCrowbar */ @@ -45,7 +47,7 @@ public final class Hexavus extends CardImpl { new AddCountersTargetEffect(CounterType.FLYING.createInstance()), new GenericManaCost(1) ); ability.addCost(new RemoveCountersSourceCost(CounterType.P1P1.createInstance())); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); // {1}, Remove a counter from another creature you control: Put a +1/+1 counter on Hexavus. diff --git a/Mage.Sets/src/mage/cards/h/HexplateWallbreaker.java b/Mage.Sets/src/mage/cards/h/HexplateWallbreaker.java index 3ad31995635..86a32669d45 100644 --- a/Mage.Sets/src/mage/cards/h/HexplateWallbreaker.java +++ b/Mage.Sets/src/mage/cards/h/HexplateWallbreaker.java @@ -5,7 +5,6 @@ import mage.abilities.common.AttacksAttachedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.FirstCombatPhaseCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.AdditionalCombatPhaseEffect; import mage.abilities.effects.common.UntapAllEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; @@ -16,7 +15,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; import java.util.UUID; @@ -38,12 +36,8 @@ public final class HexplateWallbreaker extends CardImpl { // Whenever equipped creature attacks, if it's the first combat phase of the turn, untap // each attacking creature. After this phase, there is an additional combat phase. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksAttachedTriggeredAbility(new UntapAllEffect(StaticFilters.FILTER_ATTACKING_CREATURES)), - FirstCombatPhaseCondition.instance, - "Whenever equipped creature attacks, if it's the first combat phase of the turn, untap " + - "each attacking creature. After this phase, there is an additional combat phase" - ); + Ability ability = new AttacksAttachedTriggeredAbility(new UntapAllEffect(StaticFilters.FILTER_ATTACKING_CREATURE) + .setText("untap each attacking creature")).withInterveningIf(FirstCombatPhaseCondition.instance); ability.addEffect(new AdditionalCombatPhaseEffect()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/h/HiddenAncients.java b/Mage.Sets/src/mage/cards/h/HiddenAncients.java index 72cd3429781..693e2c71a84 100644 --- a/Mage.Sets/src/mage/cards/h/HiddenAncients.java +++ b/Mage.Sets/src/mage/cards/h/HiddenAncients.java @@ -1,44 +1,35 @@ - package mage.cards.h; -import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.SpellCastOpponentTriggeredAbility; -import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.filter.FilterSpell; +import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; import java.util.UUID; /** - * * @author LoneFox - * */ public final class HiddenAncients extends CardImpl { - private static final FilterSpell filter = new FilterSpell("enchantment spell"); - - static { - filter.add(CardType.ENCHANTMENT.getPredicate()); - } - public HiddenAncients(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); // When an opponent casts an enchantment spell, if Hidden Ancients is an enchantment, Hidden Ancients becomes a 5/5 Treefolk creature. - TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new HiddenAncientsTreefolkToken(), null, Duration.WhileOnBattlefield), - filter, false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), - "When an opponent casts an enchantment spell, if {this} is an enchantment, {this} becomes a 5/5 Treefolk creature.")); + this.addAbility(new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect( + new CreatureToken( + 5, 5, "5/5 Treefolk creature", SubType.TREEFOLK + ), null, Duration.WhileOnBattlefield + ), StaticFilters.FILTER_SPELL_AN_ENCHANTMENT, false) + .withInterveningIf(SourceIsEnchantmentCondition.instance) + .withRuleTextReplacement(true) + .setTriggerPhrase("When an opponent casts an enchantment spell, ")); } private HiddenAncients(final HiddenAncients card) { @@ -50,21 +41,3 @@ public final class HiddenAncients extends CardImpl { return new HiddenAncients(this); } } - -class HiddenAncientsTreefolkToken extends TokenImpl { - - public HiddenAncientsTreefolkToken() { - super("Treefolk", "5/5 Treefolk creature"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.TREEFOLK); - power = new MageInt(5); - toughness = new MageInt(5); - } - private HiddenAncientsTreefolkToken(final HiddenAncientsTreefolkToken token) { - super(token); - } - - public HiddenAncientsTreefolkToken copy() { - return new HiddenAncientsTreefolkToken(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HiddenDragonslayer.java b/Mage.Sets/src/mage/cards/h/HiddenDragonslayer.java index 075c3fe919d..0d09b0e3d84 100644 --- a/Mage.Sets/src/mage/cards/h/HiddenDragonslayer.java +++ b/Mage.Sets/src/mage/cards/h/HiddenDragonslayer.java @@ -17,6 +17,7 @@ import mage.constants.ComparisonType; import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -47,7 +48,7 @@ public final class HiddenDragonslayer extends CardImpl { // When Hidden Dragonslayer is turned face up, destroy target creature with power 4 or greater an opponent controls. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new DestroyTargetEffect(), false, false); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HiddenGibbons.java b/Mage.Sets/src/mage/cards/h/HiddenGibbons.java index aa9fea88e83..2fd9309b0d0 100644 --- a/Mage.Sets/src/mage/cards/h/HiddenGibbons.java +++ b/Mage.Sets/src/mage/cards/h/HiddenGibbons.java @@ -1,44 +1,40 @@ - package mage.cards.h; -import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.SpellCastOpponentTriggeredAbility; -import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.FilterSpell; -import mage.filter.StaticFilters; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; import java.util.UUID; /** - * * @author LoneFox - * */ public final class HiddenGibbons extends CardImpl { - private static final FilterSpell filter = new FilterSpell("instant spell"); + private static final FilterSpell filter = new FilterSpell("an instant spell"); static { filter.add(CardType.INSTANT.getPredicate()); } public HiddenGibbons(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}"); // When an opponent casts an instant spell, if Hidden Gibbons is an enchantment, Hidden Gibbons becomes a 4/4 Ape creature. - TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new HiddenGibbonsApe(), null, Duration.WhileOnBattlefield), - filter, false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), - "When an opponent casts an instant spell, if {this} is an enchantment, {this} becomes a 4/4 Ape creature.")); + this.addAbility(new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect( + new CreatureToken(4, 4, "4/4 Ape creature", SubType.APE), + null, Duration.WhileOnBattlefield + ), filter, false) + .withInterveningIf(SourceIsEnchantmentCondition.instance) + .withRuleTextReplacement(true) + .setTriggerPhrase("When an opponent casts an instant spell, ")); } private HiddenGibbons(final HiddenGibbons card) { @@ -50,21 +46,3 @@ public final class HiddenGibbons extends CardImpl { return new HiddenGibbons(this); } } - -class HiddenGibbonsApe extends TokenImpl { - - public HiddenGibbonsApe() { - super("Ape", "4/4 Ape creature"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.APE); - power = new MageInt(4); - toughness = new MageInt(4); - } - private HiddenGibbonsApe(final HiddenGibbonsApe token) { - super(token); - } - - public HiddenGibbonsApe copy() { - return new HiddenGibbonsApe(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HiddenGuerrillas.java b/Mage.Sets/src/mage/cards/h/HiddenGuerrillas.java index 04110c2ed4d..df33a20de37 100644 --- a/Mage.Sets/src/mage/cards/h/HiddenGuerrillas.java +++ b/Mage.Sets/src/mage/cards/h/HiddenGuerrillas.java @@ -1,10 +1,7 @@ package mage.cards.h; -import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.SpellCastOpponentTriggeredAbility; -import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; @@ -12,33 +9,28 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.filter.FilterSpell; import mage.filter.StaticFilters; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; import java.util.UUID; /** - * * @author LoneFox - * */ public final class HiddenGuerrillas extends CardImpl { - - private static final FilterSpell filter = new FilterSpell("an artifact spell"); - static { - filter.add(CardType.ARTIFACT.getPredicate()); - } - public HiddenGuerrillas(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}"); // When an opponent casts an artifact spell, if Hidden Guerrillas is an enchantment, Hidden Guerrillas becomes a 5/3 Soldier creature with trample. - TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new HiddenGuerrillasSoldier(), null, Duration.WhileOnBattlefield), - filter, false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), - "When an opponent casts an artifact spell, if {this} is an enchantment, {this} becomes a 5/3 Soldier creature with trample.")); + this.addAbility(new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect( + new CreatureToken( + 5, 3, "5/3 Soldier creature with trample", SubType.SOLDIER + ).withAbility(TrampleAbility.getInstance()), null, Duration.WhileOnBattlefield + ), StaticFilters.FILTER_SPELL_AN_ARTIFACT, false) + .withInterveningIf(SourceIsEnchantmentCondition.instance) + .withRuleTextReplacement(true) + .setTriggerPhrase("When an opponent casts an artifact spell, ")); } private HiddenGuerrillas(final HiddenGuerrillas card) { @@ -50,22 +42,3 @@ public final class HiddenGuerrillas extends CardImpl { return new HiddenGuerrillas(this); } } - -class HiddenGuerrillasSoldier extends TokenImpl { - - public HiddenGuerrillasSoldier() { - super("Soldier", "5/3 Soldier creature with trample"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.SOLDIER); - power = new MageInt(5); - toughness = new MageInt(3); - this.addAbility(TrampleAbility.getInstance()); - } - private HiddenGuerrillasSoldier(final HiddenGuerrillasSoldier token) { - super(token); - } - - public HiddenGuerrillasSoldier copy() { - return new HiddenGuerrillasSoldier(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HiddenHerd.java b/Mage.Sets/src/mage/cards/h/HiddenHerd.java index 076cdbdeff3..643b6a624a4 100644 --- a/Mage.Sets/src/mage/cards/h/HiddenHerd.java +++ b/Mage.Sets/src/mage/cards/h/HiddenHerd.java @@ -1,11 +1,7 @@ - package mage.cards.h; -import java.util.UUID; -import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -13,14 +9,14 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class HiddenHerd extends CardImpl { @@ -29,11 +25,7 @@ public final class HiddenHerd extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}"); // When an opponent plays a nonbasic land, if Hidden Herd is an enchantment, Hidden Herd becomes a 3/3 Beast creature. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new HiddenHerdAbility(), - new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), - "When an opponent plays a nonbasic land, if {this} is an enchantment, {this} becomes a 3/3 Beast creature." - )); + this.addAbility(new HiddenHerdAbility()); } private HiddenHerd(final HiddenHerd card) { @@ -49,7 +41,13 @@ public final class HiddenHerd extends CardImpl { class HiddenHerdAbility extends TriggeredAbilityImpl { public HiddenHerdAbility() { - super(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new HiddenHerdBeast(), null, Duration.WhileOnBattlefield), false); + super(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect( + new CreatureToken(3, 3, "3/3 Beast creature", SubType.BEAST), + null, Duration.WhileOnBattlefield + ), false); + this.withInterveningIf(SourceIsEnchantmentCondition.instance); + this.withRuleTextReplacement(true); + this.setTriggerPhrase("When an opponent plays a nonbasic land, "); } private HiddenHerdAbility(final HiddenHerdAbility ability) { @@ -69,29 +67,6 @@ class HiddenHerdAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent land = game.getPermanentOrLKIBattlefield(event.getTargetId()); - return game.getOpponents(controllerId).contains(event.getPlayerId()) && !land.isBasic(game); - } - - @Override - public String getRule() { - return "When an opponent plays a nonbasic land, if {this} is an enchantment, {this} becomes a 3/3 Beast creature."; - } -} - -class HiddenHerdBeast extends TokenImpl { - - public HiddenHerdBeast() { - super("Beast", "3/3 Beast creature"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.BEAST); - power = new MageInt(3); - toughness = new MageInt(3); - } - private HiddenHerdBeast(final HiddenHerdBeast token) { - super(token); - } - - public HiddenHerdBeast copy() { - return new HiddenHerdBeast(this); + return land != null && game.getOpponents(getControllerId()).contains(event.getPlayerId()) && !land.isBasic(game); } } diff --git a/Mage.Sets/src/mage/cards/h/HiddenPredators.java b/Mage.Sets/src/mage/cards/h/HiddenPredators.java index 6a2027e90fe..474268107a1 100644 --- a/Mage.Sets/src/mage/cards/h/HiddenPredators.java +++ b/Mage.Sets/src/mage/cards/h/HiddenPredators.java @@ -1,7 +1,7 @@ package mage.cards.h; -import mage.MageInt; import mage.abilities.StateTriggeredAbility; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -10,7 +10,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; import java.util.UUID; @@ -46,9 +46,10 @@ class HiddenPredatorsStateTriggeredAbility extends StateTriggeredAbility { } public HiddenPredatorsStateTriggeredAbility() { - super(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new HiddenPredatorsToken(), null, Duration.Custom)); - this.withRuleTextReplacement(false); - setTriggerPhrase("When an opponent controls a creature with power 4 or greater, if {this} is an enchantment, "); + super(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new CreatureToken(4, 4, "4/4 Beast creature", SubType.BEAST), null, Duration.Custom)); + this.withInterveningIf(SourceIsEnchantmentCondition.instance); + this.withRuleTextReplacement(true); + this.setTriggerPhrase("When an opponent controls a creature with power 4 or greater, "); } private HiddenPredatorsStateTriggeredAbility(final HiddenPredatorsStateTriggeredAbility ability) { @@ -64,32 +65,4 @@ class HiddenPredatorsStateTriggeredAbility extends StateTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { return !game.getBattlefield().getActivePermanents(filter, game.getControllerId(getSourceId()), game).isEmpty(); } - - @Override - public boolean checkInterveningIfClause(Game game) { - if (getSourcePermanentIfItStillExists(game) != null) { - return getSourcePermanentIfItStillExists(game).isEnchantment(game); - } - return false; - } - -} - -class HiddenPredatorsToken extends TokenImpl { - - public HiddenPredatorsToken() { - super("Beast", "4/4 Beast creature"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.BEAST); - power = new MageInt(4); - toughness = new MageInt(4); - } - - private HiddenPredatorsToken(final HiddenPredatorsToken token) { - super(token); - } - - public HiddenPredatorsToken copy() { - return new HiddenPredatorsToken(this); - } } diff --git a/Mage.Sets/src/mage/cards/h/HiddenSpider.java b/Mage.Sets/src/mage/cards/h/HiddenSpider.java index 411be9b6210..4152cf08d32 100644 --- a/Mage.Sets/src/mage/cards/h/HiddenSpider.java +++ b/Mage.Sets/src/mage/cards/h/HiddenSpider.java @@ -1,30 +1,23 @@ - package mage.cards.h; -import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.SpellCastOpponentTriggeredAbility; -import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.ReachAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.filter.StaticFilters; +import mage.constants.SubType; import mage.filter.common.FilterCreatureSpell; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; import java.util.UUID; /** - * * @author LoneFox - * */ public final class HiddenSpider extends CardImpl { @@ -35,13 +28,17 @@ public final class HiddenSpider extends CardImpl { } public HiddenSpider(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}"); // When an opponent casts a creature spell with flying, if Hidden Spider is an enchantment, Hidden Spider becomes a 3/5 Spider creature with reach. - TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new HiddenSpiderToken(), null, Duration.WhileOnBattlefield), - filter, false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), - "When an opponent casts a creature spell with flying, if {this} is an enchantment, {this} becomes a 3/5 Spider creature with reach.")); + this.addAbility(new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect( + new CreatureToken( + 3, 5, "3/5 Spider creature with reach", SubType.SPIDER + ).withAbility(ReachAbility.getInstance()), null, Duration.WhileOnBattlefield + ), filter, false) + .withInterveningIf(SourceIsEnchantmentCondition.instance) + .withRuleTextReplacement(true) + .setTriggerPhrase("When an opponent casts a creature spell with flying, ")); } private HiddenSpider(final HiddenSpider card) { @@ -53,22 +50,3 @@ public final class HiddenSpider extends CardImpl { return new HiddenSpider(this); } } - -class HiddenSpiderToken extends TokenImpl { - - public HiddenSpiderToken() { - super("Spider", "3/5 Spider creature with reach"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.SPIDER); - power = new MageInt(3); - toughness = new MageInt(5); - this.addAbility(ReachAbility.getInstance()); - } - private HiddenSpiderToken(final HiddenSpiderToken token) { - super(token); - } - - public HiddenSpiderToken copy() { - return new HiddenSpiderToken(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HiddenStag.java b/Mage.Sets/src/mage/cards/h/HiddenStag.java index 6533d548937..7b4764c98e1 100644 --- a/Mage.Sets/src/mage/cards/h/HiddenStag.java +++ b/Mage.Sets/src/mage/cards/h/HiddenStag.java @@ -1,13 +1,11 @@ package mage.cards.h; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.ControllerPlaysLandTriggeredAbility; import mage.abilities.common.OpponentPlaysLandTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.effects.common.continuous.BecomesEnchantmentSourceEffect; import mage.cards.CardImpl; @@ -18,28 +16,33 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class HiddenStag extends CardImpl { + private static final Condition condition = new SourceMatchesFilterCondition( + "this permanent is a creature", StaticFilters.FILTER_PERMANENT_CREATURE + ); + public HiddenStag(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); // Whenever an opponent plays a land, if Hidden Stag is an enchantment, Hidden Stag becomes a 3/2 Elk Beast creature. - Effect effect = new BecomesCreatureSourceEffect(new ElkBeastToken(), null, Duration.WhileOnBattlefield); - TriggeredAbility ability = new OpponentPlaysLandTriggeredAbility(Zone.BATTLEFIELD, effect, false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), - "Whenever an opponent plays a land, if Hidden Stag is an enchantment, Hidden Stag becomes a 3/2 Elk Beast creature.")); + this.addAbility(new OpponentPlaysLandTriggeredAbility(new BecomesCreatureSourceEffect( + new CreatureToken( + 3, 2, "3/2 Elk Beast creature", SubType.ELK, SubType.BEAST + ), null, Duration.WhileOnBattlefield + ), false).withInterveningIf(SourceIsEnchantmentCondition.instance).withRuleTextReplacement(true)); // Whenever you play a land, if Hidden Stag is a creature, Hidden Stag becomes an enchantment. - Effect effect2 = new BecomesEnchantmentSourceEffect(); - TriggeredAbility ability2 = new ControllerPlaysLandTriggeredAbility(Zone.BATTLEFIELD, effect2, false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability2, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_CREATURE), - "Whenever you play a land, if Hidden Stag is a creature, Hidden Stag becomes an enchantment.")); - + this.addAbility(new ControllerPlaysLandTriggeredAbility( + Zone.BATTLEFIELD, new BecomesEnchantmentSourceEffect(), false + ).withInterveningIf(condition).withRuleTextReplacement(true)); } private HiddenStag(final HiddenStag card) { diff --git a/Mage.Sets/src/mage/cards/h/HideousEnd.java b/Mage.Sets/src/mage/cards/h/HideousEnd.java index 49c15b446f2..d6f7654d76a 100644 --- a/Mage.Sets/src/mage/cards/h/HideousEnd.java +++ b/Mage.Sets/src/mage/cards/h/HideousEnd.java @@ -7,8 +7,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author North @@ -19,7 +22,7 @@ public final class HideousEnd extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}{B}"); // Destroy target nonblack creature. Its controller loses 2 life. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addEffect(new LoseLifeTargetControllerEffect(2)); } diff --git a/Mage.Sets/src/mage/cards/h/HighFaeNegotiator.java b/Mage.Sets/src/mage/cards/h/HighFaeNegotiator.java index 2d2a92c6cd6..babd14b39ab 100644 --- a/Mage.Sets/src/mage/cards/h/HighFaeNegotiator.java +++ b/Mage.Sets/src/mage/cards/h/HighFaeNegotiator.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.BargainedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.abilities.keyword.BargainAbility; @@ -36,12 +35,9 @@ public final class HighFaeNegotiator extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When High Fae Negotiator enters the battlefield, if it was bargained, each opponent loses 3 life and you gain 3 life. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new LoseLifeOpponentsEffect(3)), - BargainedCondition.instance, "When {this} enters, " + - "if it was bargained, each opponent loses 3 life and you gain 3 life." - ); - ability.addEffect(new GainLifeEffect(3)); + Ability ability = new EntersBattlefieldTriggeredAbility(new LoseLifeOpponentsEffect(3)) + .withInterveningIf(BargainedCondition.instance); + ability.addEffect(new GainLifeEffect(3).concatBy("and")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HigureTheStillWind.java b/Mage.Sets/src/mage/cards/h/HigureTheStillWind.java index d04baeffddf..5336720e886 100644 --- a/Mage.Sets/src/mage/cards/h/HigureTheStillWind.java +++ b/Mage.Sets/src/mage/cards/h/HigureTheStillWind.java @@ -18,6 +18,7 @@ import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCreaturePermanent; @@ -52,7 +53,7 @@ public final class HigureTheStillWind extends CardImpl { // {2}: Target Ninja creature can't be blocked this turn. Ability ability = new SimpleActivatedAbility(new CantBeBlockedTargetEffect(), new GenericManaCost(2)); - ability.addTarget(new TargetCreaturePermanent(filterCreature)); + ability.addTarget(new TargetPermanent(filterCreature)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HiredHexblade.java b/Mage.Sets/src/mage/cards/h/HiredHexblade.java index 14f5eebe5a3..520aa5b3e35 100644 --- a/Mage.Sets/src/mage/cards/h/HiredHexblade.java +++ b/Mage.Sets/src/mage/cards/h/HiredHexblade.java @@ -4,14 +4,12 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.TreasureSpentToCastCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.watchers.common.ManaPaidSourceWatcher; import java.util.UUID; @@ -29,12 +27,9 @@ public final class HiredHexblade extends CardImpl { this.toughness = new MageInt(2); // When Hired Hexblade enters the battlefield, if mana from a Treasure was spent to cast it, you draw a card and you lose 1 life. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)), - TreasureSpentToCastCondition.instance, "When {this} enters, " + - "if mana from a Treasure was spent to cast it, you draw a card and you lose 1 life." - ); - ability.addEffect(new LoseLifeSourceControllerEffect(1)); + Ability ability = new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1, true)) + .withInterveningIf(TreasureSpentToCastCondition.instance); + ability.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HistorianOfZhalfir.java b/Mage.Sets/src/mage/cards/h/HistorianOfZhalfir.java index 1891f27128a..9a2553851e5 100644 --- a/Mage.Sets/src/mage/cards/h/HistorianOfZhalfir.java +++ b/Mage.Sets/src/mage/cards/h/HistorianOfZhalfir.java @@ -4,13 +4,11 @@ import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPlaneswalkerPermanent; import java.util.UUID; @@ -20,8 +18,9 @@ import java.util.UUID; */ public final class HistorianOfZhalfir extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPlaneswalkerPermanent(SubType.TEFERI); - private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPlaneswalkerPermanent(SubType.TEFERI, "you control a Teferi planeswalker") + ); public HistorianOfZhalfir(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); @@ -32,10 +31,7 @@ public final class HistorianOfZhalfir extends CardImpl { this.toughness = new MageInt(3); // Whenever Historian of Zhalfir attacks, if you control a Teferi planeswalker, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new DrawCardSourceControllerEffect(1), false), - condition, "Whenever {this} attacks, if you control a Teferi planeswalker, draw a card." - )); + this.addAbility(new AttacksTriggeredAbility(new DrawCardSourceControllerEffect(1), false).withInterveningIf(condition)); } private HistorianOfZhalfir(final HistorianOfZhalfir card) { diff --git a/Mage.Sets/src/mage/cards/h/HistoriansWisdom.java b/Mage.Sets/src/mage/cards/h/HistoriansWisdom.java index c618a02cc7a..62a78cb5fde 100644 --- a/Mage.Sets/src/mage/cards/h/HistoriansWisdom.java +++ b/Mage.Sets/src/mage/cards/h/HistoriansWisdom.java @@ -1,33 +1,32 @@ package mage.cards.h; -import java.util.UUID; - +import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.AttachedToMatchesFilterCondition; import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.common.GreatestAmongPermanentsValue; +import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; -import mage.constants.ComparisonType; -import mage.constants.SubType; -import mage.abilities.effects.common.AttachEffect; -import mage.constants.Outcome; -import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.PowerPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.TargetPermanent; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +import java.util.Optional; +import java.util.UUID; /** - * * @author weirddan455 */ public final class HistoriansWisdom extends CardImpl { @@ -46,17 +45,13 @@ public final class HistoriansWisdom extends CardImpl { this.addAbility(new EnchantAbility(auraTarget)); // When Historian's Wisdom enters the battlefield, if enchanted permanent is a creature with the greatest power among creatures on the battlefield, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)), - HistoriansWisdomCondition.instance, - "When {this} enters, if enchanted permanent is a creature with the greatest power among creatures on the battlefield, draw a card." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .withInterveningIf(HistoriansWisdomCondition.instance).addHint(GreatestAmongPermanentsValue.POWER_ALL_CREATURES.getHint())); // As long as enchanted permanent is a creature, it gets +2/+1. this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( - new BoostEnchantedEffect(2, 1), - creatureCondition, - "As long as enchanted permanent is a creature, it gets +2/+1" + new BoostEnchantedEffect(2, 1), creatureCondition, + "as long as enchanted permanent is a creature, it gets +2/+1" ))); } @@ -75,21 +70,19 @@ enum HistoriansWisdomCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - //game.applyEffects(); // Make sure +2/+1 buff gets applied first - // TODO: not appropriate to call here - investigate where in the engine to apply effects to solve bug - Permanent enchantment = source.getSourcePermanentIfItStillExists(game); - if (enchantment == null) { - return false; - } - Permanent creature = game.getPermanent(enchantment.getAttachedTo()); - if (creature == null) { - return false; - } - if (!creature.isCreature(game)) { - return false; - } - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - filter.add(new PowerPredicate(ComparisonType.MORE_THAN, creature.getPower().getValue())); - return game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game).isEmpty(); + return Optional + .ofNullable(source.getSourcePermanentIfItStillExists(game)) + .map(Permanent::getAttachedTo) + .map(game::getPermanent) + .filter(permanent -> permanent.isCreature(game)) + .map(MageObject::getPower) + .map(MageInt::getValue) + .filter(x -> x >= GreatestAmongPermanentsValue.POWER_ALL_CREATURES.calculate(game, source, null)) + .isPresent(); + } + + @Override + public String toString() { + return "enchanted permanent is a creature with the greatest power among creatures on the battlefield"; } } diff --git a/Mage.Sets/src/mage/cards/h/HitRun.java b/Mage.Sets/src/mage/cards/h/HitRun.java index d919874b146..22a49b8fb56 100644 --- a/Mage.Sets/src/mage/cards/h/HitRun.java +++ b/Mage.Sets/src/mage/cards/h/HitRun.java @@ -12,13 +12,10 @@ import mage.constants.Outcome; import mage.constants.SpellAbilityType; import mage.filter.StaticFilters; import mage.filter.common.FilterAttackingCreature; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPlayer; -import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetSacrifice; import mage.target.targetpointer.FixedTarget; @@ -57,7 +54,7 @@ class HitEffect extends OneShotEffect { HitEffect() { super(Outcome.DestroyPermanent); - this.staticText = "Target player sacrifices an artifact or creature. Hit deals damage to that player equal to that permanent's mana value"; + this.staticText = "Target player sacrifices an artifact or creature. {this} deals damage to that player equal to that permanent's mana value"; } private HitEffect(final HitEffect effect) { diff --git a/Mage.Sets/src/mage/cards/h/HixusPrisonWarden.java b/Mage.Sets/src/mage/cards/h/HixusPrisonWarden.java index 4fe5e3243fa..2146bba744b 100644 --- a/Mage.Sets/src/mage/cards/h/HixusPrisonWarden.java +++ b/Mage.Sets/src/mage/cards/h/HixusPrisonWarden.java @@ -3,7 +3,6 @@ package mage.cards.h; import mage.MageInt; import mage.abilities.common.DealsDamageToYouAllTriggeredAbility; import mage.abilities.condition.common.SourceEnteredThisTurnCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; import mage.abilities.keyword.FlashAbility; import mage.cards.CardImpl; @@ -16,13 +15,12 @@ import mage.filter.StaticFilters; import java.util.UUID; /** - * * @author LevelX2 */ public final class HixusPrisonWarden extends CardImpl { public HixusPrisonWarden(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); @@ -33,11 +31,9 @@ public final class HixusPrisonWarden extends CardImpl { this.addAbility(FlashAbility.getInstance()); // Whenever a creature deals combat damage to you, if Hixus, Prison Warden entered the battlefield this turn, exile that creature until Hixus leaves the battlefield. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new DealsDamageToYouAllTriggeredAbility( + this.addAbility(new DealsDamageToYouAllTriggeredAbility( StaticFilters.FILTER_PERMANENT_CREATURE, new ExileUntilSourceLeavesEffect(), true - ).setTriggerPhrase("Whenever a creature deals combat damage to you, if {this} entered the battlefield this turn, "), - SourceEnteredThisTurnCondition.DID, null - )); + ).withInterveningIf(SourceEnteredThisTurnCondition.DID)); } private HixusPrisonWarden(final HixusPrisonWarden card) { diff --git a/Mage.Sets/src/mage/cards/h/HoldForRansom.java b/Mage.Sets/src/mage/cards/h/HoldForRansom.java index 705da1e0c95..c03c39ae508 100644 --- a/Mage.Sets/src/mage/cards/h/HoldForRansom.java +++ b/Mage.Sets/src/mage/cards/h/HoldForRansom.java @@ -1,26 +1,29 @@ package mage.cards.h; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.combat.CantAttackBlockAttachedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.constants.*; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; -import mage.abilities.effects.common.AttachEffect; -import mage.target.TargetPermanent; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** * * @author weirddan455 @@ -81,7 +84,7 @@ class HoldForRansomSacrificeEffect extends OneShotEffect { HoldForRansomSacrificeEffect() { super(Outcome.Sacrifice); - this.staticText = "Hold for Ransom's controller sacrifices it and draws a card"; + this.staticText = "{this}'s controller sacrifices it and draws a card"; } private HoldForRansomSacrificeEffect(final HoldForRansomSacrificeEffect effect) { diff --git a/Mage.Sets/src/mage/cards/h/HollowbornBarghest.java b/Mage.Sets/src/mage/cards/h/HollowbornBarghest.java index a693c55dce1..9ce3f80da92 100644 --- a/Mage.Sets/src/mage/cards/h/HollowbornBarghest.java +++ b/Mage.Sets/src/mage/cards/h/HollowbornBarghest.java @@ -1,35 +1,27 @@ package mage.cards.h; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInHandCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.condition.common.HellbentCondition; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.players.Player; -import mage.target.targetpointer.FixedTarget; +import mage.constants.SubType; +import mage.constants.TargetController; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class HollowbornBarghest extends CardImpl { - private static final String rule = "At the beginning of your upkeep, if you have no cards in hand, each opponent loses 2 life."; + private static final Condition condition = new CardsInHandCondition(ComparisonType.EQUAL_TO, 0, TargetController.ACTIVE); public HollowbornBarghest(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}"); @@ -40,17 +32,13 @@ public final class HollowbornBarghest extends CardImpl { this.toughness = new MageInt(6); // At the beginning of your upkeep, if you have no cards in hand, each opponent loses 2 life. - Condition condition = new CardsInHandCondition(ComparisonType.EQUAL_TO, 0); - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility( - new HollowbornBarghestEffect() - ); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - ability, - condition, - rule)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new LoseLifeOpponentsEffect(2)) + .withInterveningIf(HellbentCondition.instance)); // At the beginning of each opponent's upkeep, if that player has no cards in hand, they lose 2 life. - this.addAbility(new HollowbornBarghestTriggeredAbility()); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.OPPONENT, new LoseLifeTargetEffect(2).setText("they lose 2 life"), false + ).withInterveningIf(condition)); } private HollowbornBarghest(final HollowbornBarghest card) { @@ -62,70 +50,3 @@ public final class HollowbornBarghest extends CardImpl { return new HollowbornBarghest(this); } } - -class HollowbornBarghestEffect extends OneShotEffect { - - HollowbornBarghestEffect() { - super(Outcome.Benefit); - staticText = "Each opponent loses 2 life"; - } - - private HollowbornBarghestEffect(final HollowbornBarghestEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - for (UUID opponentId : game.getOpponents(source.getControllerId())) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null) { - game.getPlayer(opponentId).loseLife(2, game, source, false); - } - } - return true; - } - - @Override - public HollowbornBarghestEffect copy() { - return new HollowbornBarghestEffect(this); - } - -} - -class HollowbornBarghestTriggeredAbility extends TriggeredAbilityImpl { - - public HollowbornBarghestTriggeredAbility() { - super(Zone.BATTLEFIELD, new LoseLifeTargetEffect(2)); - } - - private HollowbornBarghestTriggeredAbility(final HollowbornBarghestTriggeredAbility ability) { - super(ability); - } - - @Override - public HollowbornBarghestTriggeredAbility copy() { - return new HollowbornBarghestTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE - && game.getOpponents(controllerId).contains(event.getPlayerId()); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Player opponent = game.getPlayer(event.getPlayerId()); - if (opponent != null - && opponent.getHand().isEmpty()) { - this.getEffects().get(0).setTargetPointer(new FixedTarget(opponent.getId())); - return true; - } - return false; - } - - @Override - public String getRule() { - return "At the beginning of each opponent's upkeep, if that player has no cards in hand, they lose 2 life."; - } -} diff --git a/Mage.Sets/src/mage/cards/h/HollowhengeScavenger.java b/Mage.Sets/src/mage/cards/h/HollowhengeScavenger.java index 0f617393711..50d49eb4428 100644 --- a/Mage.Sets/src/mage/cards/h/HollowhengeScavenger.java +++ b/Mage.Sets/src/mage/cards/h/HollowhengeScavenger.java @@ -1,37 +1,33 @@ - package mage.cards.h; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.MorbidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.hint.common.MorbidHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** - * * @author nantuko */ public final class HollowhengeScavenger extends CardImpl { - private static final String staticText = "Morbid — When {this} enters, if a creature died this turn, you gain 5 life."; - public HollowhengeScavenger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); this.color.setGreen(true); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(4); this.toughness = new MageInt(5); // Morbid — When Hollowhenge Scavenger enters the battlefield, if a creature died this turn, you gain 5 life. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new GainLifeEffect(5)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, MorbidCondition.instance, staticText).addHint(MorbidHint.instance)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(5)) + .withInterveningIf(MorbidCondition.instance).setAbilityWord(AbilityWord.MORBID).addHint(MorbidHint.instance)); } private HollowhengeScavenger(final HollowhengeScavenger card) { diff --git a/Mage.Sets/src/mage/cards/h/HomaridShaman.java b/Mage.Sets/src/mage/cards/h/HomaridShaman.java index e954f1ed0da..c49b89824b4 100644 --- a/Mage.Sets/src/mage/cards/h/HomaridShaman.java +++ b/Mage.Sets/src/mage/cards/h/HomaridShaman.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class HomaridShaman extends CardImpl { // {U}: Tap target green creature. Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new ManaCostsImpl<>("{U}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HomicidalBrute.java b/Mage.Sets/src/mage/cards/h/HomicidalBrute.java index 8fbe94b9423..e9a45b2582c 100644 --- a/Mage.Sets/src/mage/cards/h/HomicidalBrute.java +++ b/Mage.Sets/src/mage/cards/h/HomicidalBrute.java @@ -1,28 +1,32 @@ package mage.cards.h; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.TriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.AttackedThisTurnSourceCondition; import mage.abilities.effects.common.TapSourceEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.WatcherScope; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.watchers.Watcher; + +import java.util.UUID; /** * @author nantuko */ public final class HomicidalBrute extends CardImpl { + private static final Condition condition = new InvertCondition( + AttackedThisTurnSourceCondition.instance, "{this} didn't attack this turn" + ); + public HomicidalBrute(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.MUTANT); @@ -34,7 +38,9 @@ public final class HomicidalBrute extends CardImpl { this.toughness = new MageInt(1); // At the beginning of your end step, if Homicidal Brute didn't attack this turn, tap Homicidal Brute, then transform it. - this.addAbility(new HomicidalBruteTriggeredAbility(), new HomicidalBruteWatcher()); + TriggeredAbility ability = new BeginningOfEndStepTriggeredAbility(new TapSourceEffect()); + ability.addEffect(new TransformSourceEffect().setText(", then transform it")); + this.addAbility(ability.withInterveningIf(condition)); } private HomicidalBrute(final HomicidalBrute card) { @@ -47,58 +53,3 @@ public final class HomicidalBrute extends CardImpl { } } - -class HomicidalBruteTriggeredAbility extends TriggeredAbilityImpl { - - public HomicidalBruteTriggeredAbility() { - super(Zone.BATTLEFIELD, new TapSourceEffect(), false); - addEffect(new TransformSourceEffect()); - } - - private HomicidalBruteTriggeredAbility(final HomicidalBruteTriggeredAbility ability) { - super(ability); - } - - @Override - public HomicidalBruteTriggeredAbility copy() { - return new HomicidalBruteTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.END_TURN_STEP_PRE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getPlayerId().equals(this.controllerId)) { - Watcher watcher = game.getState().getWatcher(HomicidalBruteWatcher.class, sourceId); - if (watcher == null || !watcher.conditionMet()) { - return true; - } - } - return false; - } - - @Override - public String getRule() { - return "At the beginning of your end step, if {this} didn't attack this turn, tap {this}, then transform it."; - } -} - -class HomicidalBruteWatcher extends Watcher { - - public HomicidalBruteWatcher() { - super(WatcherScope.CARD); - } - - @Override - public void watch(GameEvent event, Game game) { - if (condition) { - return; - } - if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED && event.getSourceId().equals(sourceId)) { - condition = true; - } - } -} diff --git a/Mage.Sets/src/mage/cards/h/HonoredHierarch.java b/Mage.Sets/src/mage/cards/h/HonoredHierarch.java index ee5d1b50931..ce7bd5aecf2 100644 --- a/Mage.Sets/src/mage/cards/h/HonoredHierarch.java +++ b/Mage.Sets/src/mage/cards/h/HonoredHierarch.java @@ -1,13 +1,10 @@ - package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.RenownedSourceCondition; import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.RenownAbility; import mage.abilities.keyword.VigilanceAbility; @@ -15,18 +12,18 @@ import mage.abilities.mana.AnyColorManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class HonoredHierarch extends CardImpl { public HonoredHierarch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.DRUID); this.power = new MageInt(1); @@ -36,18 +33,15 @@ public final class HonoredHierarch extends CardImpl { this.addAbility(new RenownAbility(1)); // As long as Honored Hierarch is renowned, it has vigilance and "{T}: Add one mana of any color." - Effect effect = new ConditionalContinuousEffect( + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( new GainAbilitySourceEffect(VigilanceAbility.getInstance(), Duration.WhileOnBattlefield), - RenownedSourceCondition.instance, - "As long as {this} is renowned, it has vigilance"); - Ability ability = new SimpleStaticAbility(effect); - effect = new ConditionalContinuousEffect( + RenownedSourceCondition.THIS, "as long as {this} is renowned, it has vigilance" + )); + ability.addEffect(new ConditionalContinuousEffect( new GainAbilitySourceEffect(new AnyColorManaAbility(), Duration.WhileOnBattlefield), - RenownedSourceCondition.instance, - "and \"{T}: Add one mana of any color.\""); - ability.addEffect(effect); - this.addAbility(ability); - + RenownedSourceCondition.THIS, "and \"{T}: Add one mana of any color.\"" + )); + this.addAbility(ability); } private HonoredHierarch(final HonoredHierarch card) { diff --git a/Mage.Sets/src/mage/cards/h/HoofSkulkin.java b/Mage.Sets/src/mage/cards/h/HoofSkulkin.java index 8f333f5b79b..1807ef2ff62 100644 --- a/Mage.Sets/src/mage/cards/h/HoofSkulkin.java +++ b/Mage.Sets/src/mage/cards/h/HoofSkulkin.java @@ -16,6 +16,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -36,7 +37,7 @@ public final class HoofSkulkin extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(1, 1, Duration.EndOfTurn), new GenericManaCost(3)); - ability.addTarget(new TargetCreaturePermanent(filterGreenCreature)); + ability.addTarget(new TargetPermanent(filterGreenCreature)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HoofprintsOfTheStag.java b/Mage.Sets/src/mage/cards/h/HoofprintsOfTheStag.java index 3c7458d5d71..88615cac9b5 100644 --- a/Mage.Sets/src/mage/cards/h/HoofprintsOfTheStag.java +++ b/Mage.Sets/src/mage/cards/h/HoofprintsOfTheStag.java @@ -8,12 +8,10 @@ import mage.abilities.costs.common.RemoveCountersSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.game.permanent.token.WhiteElementalToken; @@ -29,12 +27,16 @@ public final class HoofprintsOfTheStag extends CardImpl { this.subtype.add(SubType.ELEMENTAL); // Whenever you draw a card, you may put a hoofprint counter on Hoofprints of the Stag. - this.addAbility(new DrawCardControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.HOOFPRINT.createInstance(1)), true)); + this.addAbility(new DrawCardControllerTriggeredAbility( + new AddCountersSourceEffect(CounterType.HOOFPRINT.createInstance(1)), true + )); // {2}{w}, Remove four hoofprint counters from Hoofprints of the Stag: Create a 4/4 white Elemental creature token with flying. Activate this ability only during your turn. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new WhiteElementalToken(), 1), new ManaCostsImpl<>("{2}{W}"), MyTurnCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new CreateTokenEffect(new WhiteElementalToken(), 1), + new ManaCostsImpl<>("{2}{W}"), MyTurnCondition.instance + ); ability.addCost(new RemoveCountersSourceCost(CounterType.HOOFPRINT.createInstance(4))); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HopeAndGlory.java b/Mage.Sets/src/mage/cards/h/HopeAndGlory.java index 5beaad2d784..2eaaebf0829 100644 --- a/Mage.Sets/src/mage/cards/h/HopeAndGlory.java +++ b/Mage.Sets/src/mage/cards/h/HopeAndGlory.java @@ -1,7 +1,5 @@ - package mage.cards.h; -import java.util.UUID; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; @@ -10,15 +8,15 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Plopman */ public final class HopeAndGlory extends CardImpl { public HopeAndGlory(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); // Untap two target creatures. Each of them gets +1/+1 until end of turn. this.getSpellAbility().addEffect(new UntapTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/h/HopeEstheim.java b/Mage.Sets/src/mage/cards/h/HopeEstheim.java index 0b53b059cb2..e0fa4b4199c 100644 --- a/Mage.Sets/src/mage/cards/h/HopeEstheim.java +++ b/Mage.Sets/src/mage/cards/h/HopeEstheim.java @@ -11,6 +11,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.TargetController; +import mage.watchers.common.PlayerGainedLifeWatcher; import java.util.UUID; @@ -34,7 +35,7 @@ public final class HopeEstheim extends CardImpl { // At the beginning of your end step, each opponent mills X cards, where X is the amount of life you gained this turn. this.addAbility(new BeginningOfEndStepTriggeredAbility(new MillCardsEachPlayerEffect( ControllerGainedLifeCount.instance, TargetController.OPPONENT - ))); + )), new PlayerGainedLifeWatcher()); } private HopeEstheim(final HopeEstheim card) { diff --git a/Mage.Sets/src/mage/cards/h/HopefulInitiate.java b/Mage.Sets/src/mage/cards/h/HopefulInitiate.java index 01197fc5adf..9a2d8e2e2b7 100644 --- a/Mage.Sets/src/mage/cards/h/HopefulInitiate.java +++ b/Mage.Sets/src/mage/cards/h/HopefulInitiate.java @@ -1,24 +1,24 @@ package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.RemoveCounterCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DestroyTargetEffect; -import mage.constants.SubType; import mage.abilities.keyword.TrainingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class HopefulInitiate extends CardImpl { @@ -37,8 +37,7 @@ public final class HopefulInitiate extends CardImpl { // {2}{W}, Remove two +1/+1 counters from among creatures you control: Destroy target artifact or enchantment. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{2}{W}")); ability.addCost(new RemoveCounterCost( - new TargetControlledCreaturePermanent(1, 2, StaticFilters.FILTER_CONTROLLED_CREATURES, true), - CounterType.P1P1, 2 + new TargetControlledCreaturePermanent(1, 2), CounterType.P1P1, 2 ).setText("Remove two +1/+1 counters from among creatures you control")); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/h/HornOfTheMark.java b/Mage.Sets/src/mage/cards/h/HornOfTheMark.java index 5b171cc7533..b59d54fb0bf 100644 --- a/Mage.Sets/src/mage/cards/h/HornOfTheMark.java +++ b/Mage.Sets/src/mage/cards/h/HornOfTheMark.java @@ -1,18 +1,14 @@ package mage.cards.h; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.AttacksPlayerWithCreaturesTriggeredAbility; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.PutCards; +import mage.constants.SetTargetPointer; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.game.Controllable; -import mage.game.Game; -import mage.game.events.DefenderAttackedEvent; -import mage.game.events.GameEvent; import java.util.UUID; @@ -27,7 +23,9 @@ public final class HornOfTheMark extends CardImpl { this.supertype.add(SuperType.LEGENDARY); // Whenever two or more creatures you control attack a player, look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. - this.addAbility(new HornOfTheMarkTriggeredAbility()); + this.addAbility(new AttacksPlayerWithCreaturesTriggeredAbility( + new LookLibraryAndPickControllerEffect(5, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_RANDOM), + 2, StaticFilters.FILTER_CONTROLLED_CREATURES, SetTargetPointer.NONE, false)); } private HornOfTheMark(final HornOfTheMark card) { @@ -39,39 +37,3 @@ public final class HornOfTheMark extends CardImpl { return new HornOfTheMark(this); } } - -class HornOfTheMarkTriggeredAbility extends TriggeredAbilityImpl { - - HornOfTheMarkTriggeredAbility() { - super(Zone.BATTLEFIELD, new LookLibraryAndPickControllerEffect( - 5, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_RANDOM - )); - this.setTriggerPhrase("Whenever two or more creatures you control attack a player, "); - } - - private HornOfTheMarkTriggeredAbility(final HornOfTheMarkTriggeredAbility ability) { - super(ability); - } - - @Override - public HornOfTheMarkTriggeredAbility copy() { - return new HornOfTheMarkTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DEFENDER_ATTACKED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - DefenderAttackedEvent dEvent = ((DefenderAttackedEvent) event); - return game.getPlayer(dEvent.getTargetId()) != null - && dEvent - .getAttackers(game) - .stream() - .map(Controllable::getControllerId) - .filter(this::isControlledBy) - .count() >= 2; - } -} diff --git a/Mage.Sets/src/mage/cards/h/HorobisWhisper.java b/Mage.Sets/src/mage/cards/h/HorobisWhisper.java index f26312d400b..70c2b4cc48d 100644 --- a/Mage.Sets/src/mage/cards/h/HorobisWhisper.java +++ b/Mage.Sets/src/mage/cards/h/HorobisWhisper.java @@ -12,11 +12,14 @@ import mage.constants.SubType; import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.common.FilterLandPermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author LevelX2 @@ -36,7 +39,7 @@ public final class HorobisWhisper extends CardImpl { // If you control a Swamp, destroy target nonblack creature. this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new DestroyTargetEffect(), new PermanentsOnTheBattlefieldCondition(filterCondition),"If you control a Swamp, destroy target nonblack creature")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK).withChooseHint("destroy if you control a Swamp")); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK).withChooseHint("destroy if you control a Swamp")); // Splice onto Arcane-Exile four cards from your graveyard. this.addAbility(new SpliceAbility(SpliceAbility.ARCANE, new ExileFromGraveCost(new TargetCardInYourGraveyard(4,4, new FilterCard("cards"))))); diff --git a/Mage.Sets/src/mage/cards/h/HorrorOfHorrors.java b/Mage.Sets/src/mage/cards/h/HorrorOfHorrors.java index 989f256ab96..5e2b61d33a8 100644 --- a/Mage.Sets/src/mage/cards/h/HorrorOfHorrors.java +++ b/Mage.Sets/src/mage/cards/h/HorrorOfHorrors.java @@ -15,6 +15,7 @@ import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; @@ -38,7 +39,7 @@ public final class HorrorOfHorrors extends CardImpl { // Sacrifice a Swamp: Regenerate target black creature. Ability ability = new SimpleActivatedAbility(new RegenerateTargetEffect(), new SacrificeTargetCost(filter1)); - ability.addTarget(new TargetCreaturePermanent(filter2)); + ability.addTarget(new TargetPermanent(filter2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HostileTakeover.java b/Mage.Sets/src/mage/cards/h/HostileTakeover.java index 1f46d00b90b..58bc4554208 100644 --- a/Mage.Sets/src/mage/cards/h/HostileTakeover.java +++ b/Mage.Sets/src/mage/cards/h/HostileTakeover.java @@ -1,7 +1,5 @@ package mage.cards.h; -import java.util.UUID; - import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.continuous.SetBasePowerToughnessTargetEffect; import mage.cards.CardImpl; @@ -9,41 +7,33 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.other.AnotherTargetPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.SecondTargetPointer; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class HostileTakeover extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other target creature"); - - static { - filter.add(new AnotherTargetPredicate(2)); - } - public HostileTakeover(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}{B}{R}"); // Up to one target creature has base power and toughness 1/1 until end of turn. Up to one other target creature has base power and toughness 4/4 until end of turn. Then Hostile Takeover deals 3 damage to each creature. this.getSpellAbility().addEffect(new SetBasePowerToughnessTargetEffect(1, 1, Duration.EndOfTurn)); - TargetCreaturePermanent target1 = new TargetCreaturePermanent(0, 1); - target1.setTargetTag(1); - this.getSpellAbility().addTarget(target1.withChooseHint("1/1")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1).setTargetTag(1).withChooseHint("1/1")); this.getSpellAbility().addEffect(new SetBasePowerToughnessTargetEffect(4, 4, Duration.EndOfTurn) .setTargetPointer(new SecondTargetPointer()) .setText("up to one other target creature has base power and toughness 4/4 until end of turn")); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(0, 1, filter, false); - target2.setTargetTag(2); - this.getSpellAbility().addTarget(target2.withChooseHint("4/4")); - - this.getSpellAbility().addEffect(new DamageAllEffect(3, StaticFilters.FILTER_PERMANENT_CREATURE) - .concatBy("Then")); + this.getSpellAbility().addTarget(new TargetPermanent( + 0, 1, StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2 + ).setTargetTag(2).withChooseHint("4/4")); + this.getSpellAbility().addEffect(new DamageAllEffect( + 3, StaticFilters.FILTER_PERMANENT_CREATURE + ).concatBy("Then")); } private HostileTakeover(final HostileTakeover card) { diff --git a/Mage.Sets/src/mage/cards/h/HowlOfTheHunt.java b/Mage.Sets/src/mage/cards/h/HowlOfTheHunt.java index ee56e741fcd..85745107d0d 100644 --- a/Mage.Sets/src/mage/cards/h/HowlOfTheHunt.java +++ b/Mage.Sets/src/mage/cards/h/HowlOfTheHunt.java @@ -4,7 +4,7 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.AttachedToMatchesFilterCondition; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.UntapAttachedEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; @@ -14,9 +14,12 @@ import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; @@ -27,6 +30,17 @@ import java.util.UUID; */ public final class HowlOfTheHunt extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent("enchanted creature is a Wolf or Werewolf"); + + static { + filter.add(Predicates.or( + SubType.WOLF.getPredicate(), + SubType.WEREWOLF.getPredicate() + )); + } + + private static final Condition condition = new AttachedToMatchesFilterCondition(filter); + public HowlOfTheHunt(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); @@ -39,20 +53,17 @@ public final class HowlOfTheHunt extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget)); // When Howl of the Hunt enters the battlefield, if enchanted creature is a Wolf or Werewolf, untap that creature. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new UntapAttachedEffect()), - HowlOfTheHuntCondition.instance, "When {this} enters, " + - "if enchanted creature is a Wolf or Werewolf, untap that creature." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new UntapAttachedEffect().setText("untap that creature") + ).withInterveningIf(condition)); // Enchanted creature gets +2/+2 and has vigilance. - ability = new SimpleStaticAbility(new BoostEnchantedEffect(2, 2)); + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(2, 2)); ability.addEffect(new GainAbilityAttachedEffect( - VigilanceAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield + VigilanceAbility.getInstance(), AttachmentType.AURA ).setText("and has vigilance")); this.addAbility(ability); } @@ -66,22 +77,3 @@ public final class HowlOfTheHunt extends CardImpl { return new HowlOfTheHunt(this); } } - -enum HowlOfTheHuntCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - Permanent enchantment = source.getSourcePermanentIfItStillExists(game); - if (enchantment == null) { - return false; - } - Permanent creature = game.getPermanent(enchantment.getAttachedTo()); - return creature != null && creature.hasSubtype(SubType.WOLF, game) || creature.hasSubtype(SubType.WEREWOLF, game); - } - - @Override - public String toString() { - return ""; - } -} diff --git a/Mage.Sets/src/mage/cards/h/HuaTuoHonoredPhysician.java b/Mage.Sets/src/mage/cards/h/HuaTuoHonoredPhysician.java index 9b62ed46a62..173ab53fb89 100644 --- a/Mage.Sets/src/mage/cards/h/HuaTuoHonoredPhysician.java +++ b/Mage.Sets/src/mage/cards/h/HuaTuoHonoredPhysician.java @@ -1,7 +1,5 @@ - package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -13,12 +11,12 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class HuaTuoHonoredPhysician extends CardImpl { @@ -32,7 +30,10 @@ public final class HuaTuoHonoredPhysician extends CardImpl { this.toughness = new MageInt(2); // {tap}: Put target creature card from your graveyard on top of your library. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new PutOnLibraryTargetEffect(true), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new PutOnLibraryTargetEffect(true), new TapSourceCost(), + MyTurnBeforeAttackersDeclaredCondition.instance + ); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HuatliDinosaurKnight.java b/Mage.Sets/src/mage/cards/h/HuatliDinosaurKnight.java index 32a647c58cf..904d47ffe53 100644 --- a/Mage.Sets/src/mage/cards/h/HuatliDinosaurKnight.java +++ b/Mage.Sets/src/mage/cards/h/HuatliDinosaurKnight.java @@ -7,27 +7,29 @@ import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author TheElk801 */ public final class HuatliDinosaurKnight extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Dinosaur you control"); - private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("Dinosaurs"); - - static { - filter.add(SubType.DINOSAUR.getPredicate()); - filter.add(TargetController.YOU.getControllerPredicate()); - filter2.add(SubType.DINOSAUR.getPredicate()); - } + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.DINOSAUR); + private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent(SubType.DINOSAUR, "Dinosaurs"); public HuatliDinosaurKnight(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}{R}{W}"); @@ -41,13 +43,13 @@ public final class HuatliDinosaurKnight extends CardImpl { Ability ability = new LoyaltyAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)) .setText("Put two +1/+1 counters on up to one target Dinosaur you control."), 2 ); - ability.addTarget(new TargetCreaturePermanent(0, 1, filter, false)); + ability.addTarget(new TargetPermanent(0, 1, filter)); this.addAbility(ability); // -3: Target Dinosaur you control deals damage equal to its power to target creature you don't control. ability = new LoyaltyAbility(new DamageWithPowerFromOneToAnotherTargetEffect(), -3); - ability.addTarget(new TargetCreaturePermanent(filter)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + ability.addTarget(new TargetPermanent(filter)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.addAbility(ability); // -7: Dinosaurs you control get +4/+4 until end of turn. diff --git a/Mage.Sets/src/mage/cards/h/HumbleDefector.java b/Mage.Sets/src/mage/cards/h/HumbleDefector.java index c647ca1a29a..c09f361f792 100644 --- a/Mage.Sets/src/mage/cards/h/HumbleDefector.java +++ b/Mage.Sets/src/mage/cards/h/HumbleDefector.java @@ -7,12 +7,10 @@ import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.TargetPlayerGainControlSourceEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.target.common.TargetOpponent; import java.util.UUID; @@ -30,13 +28,12 @@ public final class HumbleDefector extends CardImpl { this.toughness = new MageInt(1); // {T}: Draw two cards. Target opponent gains control of Humble Defector. Activate this ability only during your turn. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new DrawCardSourceControllerEffect(2), new TapSourceCost(), MyTurnCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DrawCardSourceControllerEffect(2), new TapSourceCost(), MyTurnCondition.instance + ); ability.addEffect(new TargetPlayerGainControlSourceEffect()); ability.addTarget(new TargetOpponent()); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); - } private HumbleDefector(final HumbleDefector card) { diff --git a/Mage.Sets/src/mage/cards/h/HumbleTheBrute.java b/Mage.Sets/src/mage/cards/h/HumbleTheBrute.java index be68937a031..4a3d0de5d16 100644 --- a/Mage.Sets/src/mage/cards/h/HumbleTheBrute.java +++ b/Mage.Sets/src/mage/cards/h/HumbleTheBrute.java @@ -10,6 +10,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class HumbleTheBrute extends CardImpl { // Destroy target creature with power 4 or greater. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Investigate. this.getSpellAbility().addEffect(new InvestigateEffect().concatBy("
")); diff --git a/Mage.Sets/src/mage/cards/h/HundredHandedOne.java b/Mage.Sets/src/mage/cards/h/HundredHandedOne.java index 2ce2d04b673..5fd007c5523 100644 --- a/Mage.Sets/src/mage/cards/h/HundredHandedOne.java +++ b/Mage.Sets/src/mage/cards/h/HundredHandedOne.java @@ -1,7 +1,6 @@ package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -15,9 +14,10 @@ import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** * @@ -40,11 +40,11 @@ public final class HundredHandedOne extends CardImpl { // As long as Hundred-Handed One is monstrous, it has reach and can block an additional ninety-nine creatures each combat. ConditionalContinuousEffect effect1 = new ConditionalContinuousEffect( - new GainAbilitySourceEffect(ReachAbility.getInstance(), Duration.WhileOnBattlefield), + new GainAbilitySourceEffect(ReachAbility.getInstance(), Duration.WhileOnBattlefield), MonstrousCondition.instance, - "As long as Hundred-Handed One is monstrous, it has reach"); + "As long as {this} is monstrous, it has reach"); ConditionalContinuousEffect effect2 = new ConditionalContinuousEffect( - new CanBlockAdditionalCreatureEffect(99), + new CanBlockAdditionalCreatureEffect(99), MonstrousCondition.instance, "and can block an additional ninety-nine creatures each combat"); Ability ability = new SimpleStaticAbility(effect1); diff --git a/Mage.Sets/src/mage/cards/h/HundredTalonStrike.java b/Mage.Sets/src/mage/cards/h/HundredTalonStrike.java index 2868cdbf4c6..8eee68b787e 100644 --- a/Mage.Sets/src/mage/cards/h/HundredTalonStrike.java +++ b/Mage.Sets/src/mage/cards/h/HundredTalonStrike.java @@ -2,7 +2,6 @@ package mage.cards.h; import mage.ObjectColor; import mage.abilities.costs.common.TapTargetCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.FirstStrikeAbility; @@ -13,40 +12,40 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** - * * @author LevelX2 */ public final class HundredTalonStrike extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped white creature you control"); + private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("untapped white creature you control"); + static { filter.add(TappedPredicate.UNTAPPED); filter.add(new ColorPredicate(ObjectColor.WHITE)); } public HundredTalonStrike(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); this.subtype.add(SubType.ARCANE); // Target creature gets +1/+0 and gains first strike until end of turn. - Effect effect = new BoostTargetEffect(1,0, Duration.EndOfTurn); - effect.setText("Target creature gets +1/+0"); - this.getSpellAbility().addEffect(effect); - effect = new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn); - effect.setText("and gains first strike until end of turn"); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(new BoostTargetEffect(1, 0).setText("Target creature gets +1/+0")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains first strike until end of turn")); this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("+1/+0 and first strike")); + // Splice onto Arcane-Tap an untapped white creature you control. - this.addAbility(new SpliceAbility(SpliceAbility.ARCANE, new TapTargetCost(new TargetControlledCreaturePermanent(1,1,filter,false)))); + this.addAbility(new SpliceAbility(SpliceAbility.ARCANE, new TapTargetCost(new TargetControlledPermanent(filter)))); } private HundredTalonStrike(final HundredTalonStrike card) { diff --git a/Mage.Sets/src/mage/cards/h/HuntDown.java b/Mage.Sets/src/mage/cards/h/HuntDown.java index 7aacfd24871..d66059f3131 100644 --- a/Mage.Sets/src/mage/cards/h/HuntDown.java +++ b/Mage.Sets/src/mage/cards/h/HuntDown.java @@ -11,6 +11,7 @@ import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.watchers.common.BlockedAttackerWatcher; @@ -31,8 +32,8 @@ public final class HuntDown extends CardImpl { // Target creature blocks target creature this turn if able. this.getSpellAbility().addEffect(new HuntDownEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterMustBlock)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterToBeBlocked)); + this.getSpellAbility().addTarget(new TargetPermanent(filterMustBlock)); + this.getSpellAbility().addTarget(new TargetPermanent(filterToBeBlocked)); } diff --git a/Mage.Sets/src/mage/cards/h/HuntTheHunter.java b/Mage.Sets/src/mage/cards/h/HuntTheHunter.java index 8e17f86a2b8..dcaad9da873 100644 --- a/Mage.Sets/src/mage/cards/h/HuntTheHunter.java +++ b/Mage.Sets/src/mage/cards/h/HuntTheHunter.java @@ -1,35 +1,30 @@ - package mage.cards.h; -import java.util.UUID; import mage.ObjectColor; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.FightTargetsEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.TargetController; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterOpponentsCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; -import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class HuntTheHunter extends CardImpl { - private static final FilterControlledCreaturePermanent filterControlledGreen = new FilterControlledCreaturePermanent("green creature you control"); - private static final FilterCreaturePermanent filterOpponentGreen = new FilterCreaturePermanent("green creature an opponent controls"); + private static final FilterControlledPermanent filterControlledGreen = new FilterControlledCreaturePermanent("green creature you control"); + private static final FilterPermanent filterOpponentGreen = new FilterOpponentsCreaturePermanent("green creature an opponent controls"); static { filterControlledGreen.add(new ColorPredicate(ObjectColor.GREEN)); - filterOpponentGreen.add(TargetController.OPPONENT.getControllerPredicate()); filterOpponentGreen.add(new ColorPredicate(ObjectColor.GREEN)); } @@ -37,15 +32,10 @@ public final class HuntTheHunter extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}"); // Target green creature you control gets +2/+2 until end of turn. It fights target green creature an opponent controls. - Effect effect = new BoostTargetEffect(2, 2, Duration.EndOfTurn); - this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(1, 1, filterControlledGreen, false)); - - effect = new FightTargetsEffect(); - effect.setText("It fights target green creature an opponent controls"); - this.getSpellAbility().addEffect(effect); - Target target = new TargetCreaturePermanent(filterOpponentGreen); - this.getSpellAbility().addTarget(target); + this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2)); + this.getSpellAbility().addTarget(new TargetPermanent(filterControlledGreen)); + this.getSpellAbility().addEffect(new FightTargetsEffect().setText("It fights target green creature an opponent controls")); + this.getSpellAbility().addTarget(new TargetPermanent(filterOpponentGreen)); } private HuntTheHunter(final HuntTheHunter card) { diff --git a/Mage.Sets/src/mage/cards/h/HuntTheWeak.java b/Mage.Sets/src/mage/cards/h/HuntTheWeak.java index 7243ab70a31..e678cede5d2 100644 --- a/Mage.Sets/src/mage/cards/h/HuntTheWeak.java +++ b/Mage.Sets/src/mage/cards/h/HuntTheWeak.java @@ -7,11 +7,14 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.counters.CounterType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author LevelX2 */ @@ -27,7 +30,7 @@ public final class HuntTheWeak extends CardImpl { "(Each deals damage equal to its power to the other.)" )); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); } private HuntTheWeak(final HuntTheWeak card) { diff --git a/Mage.Sets/src/mage/cards/h/HunterOfEyeblights.java b/Mage.Sets/src/mage/cards/h/HunterOfEyeblights.java index 1656e05c8a3..a73d454e339 100644 --- a/Mage.Sets/src/mage/cards/h/HunterOfEyeblights.java +++ b/Mage.Sets/src/mage/cards/h/HunterOfEyeblights.java @@ -16,10 +16,13 @@ import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.CounterAnyPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author Styxo */ @@ -40,13 +43,13 @@ public final class HunterOfEyeblights extends CardImpl { // When Hunter of Eyeblights enters the battlefield, put a +1/+1 counter on target creature you don't control Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.addAbility(ability); //{B}{2},{T}: Destroy target creature with a counter on it. Ability ability2 = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{2}{B}")); ability2.addCost(new TapSourceCost()); - ability2.addTarget(new TargetCreaturePermanent(filter)); + ability2.addTarget(new TargetPermanent(filter)); this.addAbility(ability2); } diff --git a/Mage.Sets/src/mage/cards/h/HuntingDrake.java b/Mage.Sets/src/mage/cards/h/HuntingDrake.java index 2cf3e212de2..6e102407b8c 100644 --- a/Mage.Sets/src/mage/cards/h/HuntingDrake.java +++ b/Mage.Sets/src/mage/cards/h/HuntingDrake.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class HuntingDrake extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Hunting Drake enters the battlefield, put target red or green creature on top of its owner's library. Ability ability = new EntersBattlefieldTriggeredAbility(new PutOnLibraryTargetEffect(true)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HuntingKavu.java b/Mage.Sets/src/mage/cards/h/HuntingKavu.java index 071d00b2bfc..42c90188b4d 100644 --- a/Mage.Sets/src/mage/cards/h/HuntingKavu.java +++ b/Mage.Sets/src/mage/cards/h/HuntingKavu.java @@ -18,6 +18,7 @@ import mage.constants.Zone; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.filter.common.FilterCreatureAttackingYou; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -43,7 +44,7 @@ public final class HuntingKavu extends CardImpl { Ability ability = new SimpleActivatedAbility(new ExileSourceEffect(), new ManaCostsImpl<>("{1}{R}{G}")); ability.addCost(new TapSourceCost()); ability.addEffect(new ExileTargetEffect().setText("and target creature without flying that's attacking you")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/Hydradoodle.java b/Mage.Sets/src/mage/cards/h/Hydradoodle.java index 2ac9d494f88..7b7d35c0bb2 100644 --- a/Mage.Sets/src/mage/cards/h/Hydradoodle.java +++ b/Mage.Sets/src/mage/cards/h/Hydradoodle.java @@ -1,9 +1,8 @@ - package mage.cards.h; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.ReachAbility; import mage.abilities.keyword.TrampleAbility; @@ -13,8 +12,6 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.counters.CounterType; -import mage.filter.FilterPermanent; -import mage.filter.predicate.permanent.CounterAnyPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -38,10 +35,8 @@ public final class Hydradoodle extends CardImpl { this.toughness = new MageInt(0); // As Hydradoodle enters the battlefield, roll X six-sided dice. Hydradoodle enters the battlefield with a number of +1/+1 counters on it equal to the total of those results. - this.addAbility(new EntersBattlefieldAbility(new HydradoodleEffect(), - null, - "As {this} enters, roll X six-sided dice. {this} enters with a number of +1/+1 counters on it equal to the total of those results", - null)); + this.addAbility(new AsEntersBattlefieldAbility(new HydradoodleEffect())); + // Reach this.addAbility(ReachAbility.getInstance()); @@ -61,12 +56,6 @@ public final class Hydradoodle extends CardImpl { class HydradoodleEffect extends OneShotEffect { - private static final FilterPermanent filter = new FilterPermanent("permanent with a counter"); - - static { - filter.add(CounterAnyPredicate.instance); - } - HydradoodleEffect() { super(Outcome.BoostCreature); this.staticText = "roll X six-sided dice. {this} enters with a number of +1/+1 counters on it equal to the total of those results"; diff --git a/Mage.Sets/src/mage/cards/h/Hypnox.java b/Mage.Sets/src/mage/cards/h/Hypnox.java index 2c35fc0b52d..8f3ebd248db 100644 --- a/Mage.Sets/src/mage/cards/h/Hypnox.java +++ b/Mage.Sets/src/mage/cards/h/Hypnox.java @@ -5,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromHandSourcePermanentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnFromExileForSourceEffect; import mage.abilities.keyword.FlyingAbility; @@ -39,11 +38,8 @@ public final class Hypnox extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Hypnox enters the battlefield, if you cast it from your hand, exile all cards from target opponent's hand. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new HypnoxExileEffect()), - CastFromHandSourcePermanentCondition.instance, "When {this} enters, " + - "if you cast it from your hand, exile all cards from target opponent's hand." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new HypnoxExileEffect()) + .withInterveningIf(CastFromHandSourcePermanentCondition.instance); ability.addTarget(new TargetOpponent()); this.addAbility(ability, new CastFromHandWatcher()); @@ -66,7 +62,7 @@ class HypnoxExileEffect extends OneShotEffect { HypnoxExileEffect() { super(Outcome.Exile); - staticText = "Exile all cards from target opponent's hand"; + staticText = "exile all cards from target opponent's hand"; } private HypnoxExileEffect(final HypnoxExileEffect effect) { diff --git a/Mage.Sets/src/mage/cards/i/IanTheReckless.java b/Mage.Sets/src/mage/cards/i/IanTheReckless.java index 7375f219b0f..f809522becf 100644 --- a/Mage.Sets/src/mage/cards/i/IanTheReckless.java +++ b/Mage.Sets/src/mage/cards/i/IanTheReckless.java @@ -1,11 +1,10 @@ package mage.cards.i; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.SourcePermanentPowerValue; import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.DamageTargetEffect; @@ -25,7 +24,7 @@ import java.util.UUID; */ public final class IanTheReckless extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent(); + private static final FilterPermanent filter = new FilterPermanent("it's modified"); static { filter.add(ModifiedPredicate.instance); @@ -43,12 +42,11 @@ public final class IanTheReckless extends CardImpl { this.toughness = new MageInt(1); // Whenever Ian the Reckless attacks, if it's modified, you may have it deal damage equal to its power to you and any target. - TriggeredAbility ability = new AttacksTriggeredAbility(new DamageControllerEffect( - SourcePermanentPowerValue.NOT_NEGATIVE).setText("have it deal damage equal to its power to you"), true); + Ability ability = new AttacksTriggeredAbility(new DamageControllerEffect(SourcePermanentPowerValue.NOT_NEGATIVE) + .setText("have it deal damage equal to its power to you"), true).withInterveningIf(condition); ability.addEffect(new DamageTargetEffect(SourcePermanentPowerValue.NOT_NEGATIVE).setText("and any target")); ability.addTarget(new TargetAnyTarget()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, condition, - "Whenever {this} attacks, if it's modified, you may have it deal damage equal to its power to you and any target.")); + this.addAbility(ability); } private IanTheReckless(final IanTheReckless card) { diff --git a/Mage.Sets/src/mage/cards/i/IcatianLieutenant.java b/Mage.Sets/src/mage/cards/i/IcatianLieutenant.java index c86b7a5b6e2..31c9d479699 100644 --- a/Mage.Sets/src/mage/cards/i/IcatianLieutenant.java +++ b/Mage.Sets/src/mage/cards/i/IcatianLieutenant.java @@ -14,6 +14,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class IcatianLieutenant extends CardImpl { // {1}{W}: Target Soldier creature gets +1/+0 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl<>("{1}{W}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/IcatianMoneychanger.java b/Mage.Sets/src/mage/cards/i/IcatianMoneychanger.java index 3c26f0ea22b..6be449221af 100644 --- a/Mage.Sets/src/mage/cards/i/IcatianMoneychanger.java +++ b/Mage.Sets/src/mage/cards/i/IcatianMoneychanger.java @@ -1,55 +1,53 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.SacrificeSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.dynamicvalue.common.CountersSourceCount; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.PhaseStep; -import mage.constants.Zone; import mage.counters.CounterType; +import java.util.UUID; + /** - * * @author fireshoes */ public final class IcatianMoneychanger extends CardImpl { public IcatianMoneychanger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); this.subtype.add(SubType.HUMAN); this.power = new MageInt(0); this.toughness = new MageInt(2); // Icatian Moneychanger enters the battlefield with three credit counters on it. - Effect effect = new AddCountersSourceEffect(CounterType.CREDIT.createInstance(3)); - effect.setText("with three credit counters on it"); - this.addAbility(new EntersBattlefieldAbility(effect)); - + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.CREDIT.createInstance(3)) + .setText("with three credit counters on it") + )); + // When Icatian Moneychanger enters the battlefield, it deals 3 damage to you. - effect = new DamageControllerEffect(3); - effect.setText("it deals 3 damage to you"); - this.addAbility(new EntersBattlefieldTriggeredAbility(effect, false)); - + this.addAbility(new EntersBattlefieldTriggeredAbility(new DamageControllerEffect(3, "it"))); + // At the beginning of your upkeep, put a credit counter on Icatian Moneychanger. this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.CREDIT.createInstance()))); - + // Sacrifice Icatian Moneychanger: You gain 1 life for each credit counter on Icatian Moneychanger. Activate this ability only during your upkeep. - this.addAbility(new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new GainLifeEffect(new CountersSourceCount(CounterType.CREDIT)), new SacrificeSourceCost(), new IsStepCondition(PhaseStep.UPKEEP))); + this.addAbility(new ActivateIfConditionActivatedAbility( + new GainLifeEffect(new CountersSourceCount(CounterType.CREDIT)) + .setText("you gain 1 life for each credit counter on this creature"), + new SacrificeSourceCost(), IsStepCondition.getMyUpkeep() + )); } private IcatianMoneychanger(final IcatianMoneychanger card) { diff --git a/Mage.Sets/src/mage/cards/i/IceCauldron.java b/Mage.Sets/src/mage/cards/i/IceCauldron.java index 5e85395a159..1980a525c01 100644 --- a/Mage.Sets/src/mage/cards/i/IceCauldron.java +++ b/Mage.Sets/src/mage/cards/i/IceCauldron.java @@ -10,7 +10,7 @@ import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.costs.common.RemoveCountersSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.AsThoughEffect; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.OneShotEffect; @@ -44,8 +44,8 @@ public final class IceCauldron extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // {X}, {T}: Put a charge counter on Ice Cauldron and exile a nonland card from your hand. You may cast that card for as long as it remains exiled. Note the type and amount of mana spent to pay this activation cost. Activate this ability only if there are no charge counters on Ice Cauldron. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new IceCauldronExileEffect(), new ManaCostsImpl<>("{X}"), condition + Ability ability = new ActivateIfConditionActivatedAbility( + new IceCauldronExileEffect(), new ManaCostsImpl<>("{X}"), condition ); ability.addEffect(new AddCountersSourceEffect(CounterType.CHARGE.createInstance(), true)); ability.addEffect(new IceCauldronNoteManaEffect()); @@ -78,7 +78,7 @@ class IceCauldronExileEffect extends OneShotEffect { public IceCauldronExileEffect() { super(Outcome.Benefit); - this.staticText = "and exile a nonland card from your hand. You may cast that card for as long as it remains exiled"; + this.staticText = "you may exile a nonland card from your hand. You may cast that card for as long as it remains exiled"; } private IceCauldronExileEffect(final IceCauldronExileEffect effect) { @@ -157,7 +157,7 @@ class IceCauldronNoteManaEffect extends OneShotEffect { public IceCauldronNoteManaEffect() { super(Outcome.Benefit); - this.staticText = "Note the type and amount of mana spent to pay this activation cost"; + this.staticText = "and note the type and amount of mana spent to pay this activation cost"; } private IceCauldronNoteManaEffect(final IceCauldronNoteManaEffect effect) { diff --git a/Mage.Sets/src/mage/cards/i/IceFloe.java b/Mage.Sets/src/mage/cards/i/IceFloe.java index 2f3a53dcf35..3e3d91fff18 100644 --- a/Mage.Sets/src/mage/cards/i/IceFloe.java +++ b/Mage.Sets/src/mage/cards/i/IceFloe.java @@ -16,6 +16,7 @@ import mage.constants.Zone; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.filter.common.FilterCreatureAttackingYou; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class IceFloe extends CardImpl { // {T}: Tap target creature without flying that's attacking you. It doesn't untap during its controller's untap step for as long as Ice Floe remains tapped. Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); ability.addEffect(new DontUntapAsLongAsSourceTappedEffect()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/IcefallRegent.java b/Mage.Sets/src/mage/cards/i/IcefallRegent.java index 4454729a6f6..dfe304b20f0 100644 --- a/Mage.Sets/src/mage/cards/i/IcefallRegent.java +++ b/Mage.Sets/src/mage/cards/i/IcefallRegent.java @@ -16,10 +16,13 @@ import mage.constants.SubType; import mage.constants.TargetController; import mage.filter.FilterCard; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * @author fireshoes */ @@ -38,7 +41,7 @@ public final class IcefallRegent extends CardImpl { // That creature doesn't untap during its controller's untap step for as long as you control Icefall Regent. Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect(), false); ability.addEffect(new DontUntapInControllersUntapStepTargetEffect(Duration.WhileControlled)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); // Spells your opponents cast that target Icefall Regent cost {2} more to cast. diff --git a/Mage.Sets/src/mage/cards/i/IcefeatherAven.java b/Mage.Sets/src/mage/cards/i/IcefeatherAven.java index 17026022fb1..9f8eced1780 100644 --- a/Mage.Sets/src/mage/cards/i/IcefeatherAven.java +++ b/Mage.Sets/src/mage/cards/i/IcefeatherAven.java @@ -14,8 +14,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * * @author LevelX2 @@ -36,7 +39,7 @@ public final class IcefeatherAven extends CardImpl { this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{1}{G}{U}"))); // When Icefeather Aven is turned face up, you may return another target creature to its owner's hand. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new ReturnToHandTargetEffect(), false, true); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/IdentityThief.java b/Mage.Sets/src/mage/cards/i/IdentityThief.java index 1a9ecce99c8..437f949029b 100644 --- a/Mage.Sets/src/mage/cards/i/IdentityThief.java +++ b/Mage.Sets/src/mage/cards/i/IdentityThief.java @@ -3,26 +3,26 @@ package mage.cards.i; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CopyEffect; import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; import java.util.UUID; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.common.CopyEffect; -import mage.util.CardUtil; /** * @author spjspj @@ -32,6 +32,7 @@ public final class IdentityThief extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("target nontoken creature"); static { + filter.add(AnotherPredicate.instance); filter.add(TokenPredicate.FALSE); } @@ -44,8 +45,8 @@ public final class IdentityThief extends CardImpl { // Whenever Identity Thief attacks, you may exile another target nontoken creature. // If you do, Identity Thief becomes a copy of that creature until end of turn. // Return the exiled card to the battlefield under its owner's control at the beginning of the next end step. - Ability ability = new IdentityThiefAbility(); - ability.addTarget(new TargetCreaturePermanent(0, 1, filter, false)); + Ability ability = new AttacksTriggeredAbility(new IdentityThiefEffect(), true); + ability.addTarget(new TargetPermanent(0, 1, filter)); this.addAbility(ability); } @@ -101,26 +102,28 @@ class IdentityThiefEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent targetPermanent = getTargetPointer().getFirstTargetPermanentOrLKI(game, source); Player controller = game.getPlayer(source.getControllerId()); - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (controller != null - && targetPermanent != null - && sourcePermanent != null) { - ContinuousEffect copyEffect = new CopyEffect(Duration.EndOfTurn, targetPermanent, source.getSourceId()); - copyEffect.setTargetPointer(new FixedTarget(sourcePermanent.getId(), game)); - game.addEffect(copyEffect, source); - - UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); - if (controller.moveCardsToExile(targetPermanent, source, game, true, exileZoneId, sourcePermanent.getName())) { - Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, true); - effect.setText("Return the exiled card to the battlefield under its owner's control at the beginning of the next end step"); - effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game)); - game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source); - } - return true; + Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (controller == null || targetPermanent == null) { + return false; } - return false; + controller.moveCardsToExile( + targetPermanent, source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, true) + .setText("Return the exiled card to the battlefield under its owner's control at the beginning of the next end step") + .setTargetPointer(new FixedTarget(source.getFirstTarget(), game)) + ), source); + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); + if (sourcePermanent != null) { + game.addEffect(new CopyEffect( + Duration.EndOfTurn, targetPermanent, source.getSourceId() + ).setTargetPointer(new FixedTarget(sourcePermanent.getId(), game)), source); + } + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/i/IdolOfOblivion.java b/Mage.Sets/src/mage/cards/i/IdolOfOblivion.java index 2dba9b17035..377142c4535 100644 --- a/Mage.Sets/src/mage/cards/i/IdolOfOblivion.java +++ b/Mage.Sets/src/mage/cards/i/IdolOfOblivion.java @@ -12,7 +12,6 @@ import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.game.permanent.token.EldraziToken; import mage.watchers.common.CreatedTokenWatcher; @@ -28,7 +27,7 @@ public final class IdolOfOblivion extends CardImpl { // {T}: Draw a card. Activate this ability only if you created a token this turn. this.addAbility(new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), + new DrawCardSourceControllerEffect(1), new TapSourceCost(), CreatedTokenThisTurnCondition.instance ).addHint(CreatedTokenThisTurnCondition.getHint()), new CreatedTokenWatcher()); diff --git a/Mage.Sets/src/mage/cards/i/IllithidHarvester.java b/Mage.Sets/src/mage/cards/i/IllithidHarvester.java index 3819725e282..06027dad520 100644 --- a/Mage.Sets/src/mage/cards/i/IllithidHarvester.java +++ b/Mage.Sets/src/mage/cards/i/IllithidHarvester.java @@ -14,6 +14,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicates; @@ -23,6 +24,7 @@ import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.XTargetsCountAdjuster; @@ -34,7 +36,7 @@ import java.util.UUID; */ public final class IllithidHarvester extends AdventureCard { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped nontoken creatures"); + private static final FilterPermanent filter = new FilterCreaturePermanent("tapped nontoken creatures"); static { filter.add(TappedPredicate.TAPPED); @@ -50,7 +52,7 @@ public final class IllithidHarvester extends AdventureCard { // Ceremorphosis — When Illithid Harvester enters the battlefield, turn any number // of target tapped nontoken creatures face down. They're 2/2 Horror creatures. Ability ability = new EntersBattlefieldTriggeredAbility(new IllithidHarvesterEffect()); - ability.addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, false)); + ability.addTarget(new TargetPermanent(0, Integer.MAX_VALUE, filter)); this.addAbility(ability.withFlavorWord("Ceremorphosis")); // Plant Tadpoles diff --git a/Mage.Sets/src/mage/cards/i/IllusionaryInformant.java b/Mage.Sets/src/mage/cards/i/IllusionaryInformant.java index 2a386666fcc..9be533acf14 100644 --- a/Mage.Sets/src/mage/cards/i/IllusionaryInformant.java +++ b/Mage.Sets/src/mage/cards/i/IllusionaryInformant.java @@ -1,14 +1,14 @@ package mage.cards.i; import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.InfoEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.InfoEffect; import java.util.UUID; @@ -28,10 +28,10 @@ public final class IllusionaryInformant extends CardImpl { // TODO: Draft specific abilities not implemented // Draft Illusionary Informant face up. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft Illusionary Informant face up - not implemented."))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft {this} face up - not implemented."))); // During the draft, you may turn Illusionary Informant face down. If you do, look at the next card drafted by a player of your choice. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("During the draft, you may turn Illusionary Informant face down. If you do, " + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("During the draft, you may turn {this} face down. If you do, " + "look at the next card drafted by a player of your choice - not implemented."))); // Flying diff --git a/Mage.Sets/src/mage/cards/i/IllusionistsStratagem.java b/Mage.Sets/src/mage/cards/i/IllusionistsStratagem.java index 5c4992102ba..139d721d8c0 100644 --- a/Mage.Sets/src/mage/cards/i/IllusionistsStratagem.java +++ b/Mage.Sets/src/mage/cards/i/IllusionistsStratagem.java @@ -5,7 +5,6 @@ import mage.abilities.effects.common.ExileThenReturnTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.StaticFilters; import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; @@ -20,8 +19,7 @@ public final class IllusionistsStratagem extends CardImpl { // Exile up to two target creatures you control, then return those cards to the battlefield under their owner's control. this.getSpellAbility().addEffect(new ExileThenReturnTargetEffect(false, true)); - this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, 2, - StaticFilters.FILTER_CONTROLLED_CREATURES, false)); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, 2)); // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); diff --git a/Mage.Sets/src/mage/cards/i/ImaginaryPet.java b/Mage.Sets/src/mage/cards/i/ImaginaryPet.java index 3a1ccda78f2..f99f97caef3 100644 --- a/Mage.Sets/src/mage/cards/i/ImaginaryPet.java +++ b/Mage.Sets/src/mage/cards/i/ImaginaryPet.java @@ -1,35 +1,33 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.condition.common.CardsInHandCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.HellbentCondition; import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.ComparisonType; + +import java.util.UUID; /** - * * @author LoneFox */ public final class ImaginaryPet extends CardImpl { + private static final Condition condition = new InvertCondition(HellbentCondition.instance, "you have a card in hand"); + public ImaginaryPet(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.subtype.add(SubType.ILLUSION); this.power = new MageInt(4); this.toughness = new MageInt(4); // At the beginning of your upkeep, if you have a card in hand, return Imaginary Pet to its owner's hand. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new ReturnToHandSourceEffect(true)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new CardsInHandCondition(ComparisonType.MORE_THAN, 0), - "At the beginning of your upkeep, if you have a card in hand, return {this} to its owner's hand.")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new ReturnToHandSourceEffect(true)).withInterveningIf(condition)); } private ImaginaryPet(final ImaginaryPet card) { diff --git a/Mage.Sets/src/mage/cards/i/ImpelledGiant.java b/Mage.Sets/src/mage/cards/i/ImpelledGiant.java index 4b136e16cec..5a32d0d837f 100644 --- a/Mage.Sets/src/mage/cards/i/ImpelledGiant.java +++ b/Mage.Sets/src/mage/cards/i/ImpelledGiant.java @@ -1,6 +1,5 @@ package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -17,23 +16,23 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetControlledPermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class ImpelledGiant extends CardImpl { - static final private FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("an untapped red creature you control other than Impelled Giant"); + static final private FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("an untapped red creature you control other than {this}"); static { filter.add(TappedPredicate.UNTAPPED); @@ -73,7 +72,7 @@ class ImpelledGiantCost extends CostImpl { public ImpelledGiantCost(TargetControlledPermanent target) { this.target = target; - this.text = "Tap an untapped red creature you control other than Impelled Giant"; + this.text = "Tap an untapped red creature you control other than {this}"; } private ImpelledGiantCost(final ImpelledGiantCost cost) { diff --git a/Mage.Sets/src/mage/cards/i/ImpendingDisaster.java b/Mage.Sets/src/mage/cards/i/ImpendingDisaster.java index a584f8cedcf..f11fc9d4897 100644 --- a/Mage.Sets/src/mage/cards/i/ImpendingDisaster.java +++ b/Mage.Sets/src/mage/cards/i/ImpendingDisaster.java @@ -1,36 +1,37 @@ package mage.cards.i; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.StaticFilters; +import mage.filter.common.FilterLandPermanent; import java.util.UUID; /** - * * @author Plopman */ public final class ImpendingDisaster extends CardImpl { - private static final Condition condition = new PermanentsOnTheBattlefieldCondition(StaticFilters.FILTER_LAND, ComparisonType.OR_GREATER, 7, false); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterLandPermanent("there are seven or more lands on the battlefield"), + ComparisonType.OR_GREATER, 7, false + ); public ImpendingDisaster(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); // At the beginning of your upkeep, if there are seven or more lands on the battlefield, sacrifice Impending Disaster and destroy all lands. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceEffect()); - ability.addEffect(new DestroyAllEffect(StaticFilters.FILTER_LANDS)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, condition, - "At the beginning of your upkeep, if there are seven or more lands on the battlefield, sacrifice {this} and destroy all lands")); + Ability ability = new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceEffect()).withInterveningIf(condition); + ability.addEffect(new DestroyAllEffect(StaticFilters.FILTER_LANDS).concatBy("and")); + this.addAbility(ability); } private ImpendingDisaster(final ImpendingDisaster card) { diff --git a/Mage.Sets/src/mage/cards/i/ImperialAerosaur.java b/Mage.Sets/src/mage/cards/i/ImperialAerosaur.java index 0a974072b93..f77cc637d2d 100644 --- a/Mage.Sets/src/mage/cards/i/ImperialAerosaur.java +++ b/Mage.Sets/src/mage/cards/i/ImperialAerosaur.java @@ -1,9 +1,7 @@ package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.FlyingAbility; @@ -13,10 +11,11 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class ImperialAerosaur extends CardImpl { @@ -32,13 +31,13 @@ public final class ImperialAerosaur extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Imperial Aerosaur enters the battlefield, another target creature you control gets +1/+1 and gains flying until end of turn. - Effect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn); - effect.setText("another target creature you control gets +1/+1"); - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(effect); - effect = new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn); - effect.setText("and gains flying until end of turn"); - ability.addEffect(effect); - ability.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL)); + EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility( + new BoostTargetEffect(1, 1).setText("another target creature you control gets +1/+1") + ); + ability.addEffect(new GainAbilityTargetEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains flying until end of turn")); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/ImperialMask.java b/Mage.Sets/src/mage/cards/i/ImperialMask.java index fca7bfa7cce..3142da97e8c 100644 --- a/Mage.Sets/src/mage/cards/i/ImperialMask.java +++ b/Mage.Sets/src/mage/cards/i/ImperialMask.java @@ -2,15 +2,14 @@ package mage.cards.i; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.continuous.GainAbilityControllerEffect; import mage.abilities.keyword.HexproofAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.predicate.permanent.TokenPredicate; @@ -21,23 +20,22 @@ import java.util.UUID; */ public final class ImperialMask extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent(); + private static final FilterPermanent filter = new FilterPermanent("it's not a token"); static { filter.add(TokenPredicate.FALSE); } + private static final Condition condition = new SourceMatchesFilterCondition(filter); + public ImperialMask(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{W}"); // When Imperial Mask enters the battlefield, if it's not a token, each of your teammates puts a token that's a copy of Imperial Mask onto the battlefield. // No implementation of teammates currently, so no effect needed - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new InfoEffect(""), false), - new SourceMatchesFilterCondition(filter), - "When {this} enters, if it's not a token, " - + "each of your teammates creates a token that's a copy of {this}" - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new InfoEffect( + "each of your teammates creates a token that's a copy of {this}" + ), false).withInterveningIf(condition)); // You have hexproof. this.addAbility(new SimpleStaticAbility(new GainAbilityControllerEffect(HexproofAbility.getInstance()))); diff --git a/Mage.Sets/src/mage/cards/i/ImpetuousDevils.java b/Mage.Sets/src/mage/cards/i/ImpetuousDevils.java index 0d98b477525..c25814320f6 100644 --- a/Mage.Sets/src/mage/cards/i/ImpetuousDevils.java +++ b/Mage.Sets/src/mage/cards/i/ImpetuousDevils.java @@ -1,26 +1,21 @@ package mage.cards.i; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.combat.MustBeBlockedByTargetSourceEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.TargetController; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; -import mage.game.events.GameEvent; +import mage.constants.*; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; + +import java.util.UUID; /** * @@ -39,7 +34,12 @@ public final class ImpetuousDevils extends CardImpl { // Haste this.addAbility(HasteAbility.getInstance()); // When Impetuous Devils attacks, up to one target creature defending player controls blocks it this combat if able. - this.addAbility(new ImpetuousDevilsAbility()); + TriggeredAbility ability = new AttacksTriggeredAbility(new MustBeBlockedByTargetSourceEffect(Duration.EndOfCombat) + .setText("up to one target creature defending player controls blocks it this combat if able"), false, null, SetTargetPointer.PLAYER); + ability.setTriggerPhrase("When {this} attacks, "); + ability.addTarget(new TargetCreaturePermanent(0, 1)); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); + this.addAbility(ability); // At the beginning of the end step, sacrifice Impetuous Devils. this.addAbility(new BeginningOfEndStepTriggeredAbility(TargetController.NEXT, new SacrificeSourceEffect(), false)); @@ -54,44 +54,3 @@ public final class ImpetuousDevils extends CardImpl { return new ImpetuousDevils(this); } } - -class ImpetuousDevilsAbility extends TriggeredAbilityImpl { - - public ImpetuousDevilsAbility() { - super(Zone.BATTLEFIELD, new MustBeBlockedByTargetSourceEffect(Duration.EndOfCombat), false); - } - - private ImpetuousDevilsAbility(final ImpetuousDevilsAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ATTACKER_DECLARED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getSourceId().equals(this.getSourceId())) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); - UUID defenderId = game.getCombat().getDefendingPlayerId(sourceId, game); - filter.add(new ControllerIdPredicate(defenderId)); - - this.getTargets().clear(); - TargetCreaturePermanent target = new TargetCreaturePermanent(0, 1, filter, false); - this.addTarget(target); - return true; - } - return false; - } - - @Override - public String getRule() { - return "When {this} attacks, up to one target creature defending player controls blocks it this combat if able."; - } - - @Override - public ImpetuousDevilsAbility copy() { - return new ImpetuousDevilsAbility(this); - } -} diff --git a/Mage.Sets/src/mage/cards/i/ImposingSovereign.java b/Mage.Sets/src/mage/cards/i/ImposingSovereign.java index 34ca08ba114..07c91d643ae 100644 --- a/Mage.Sets/src/mage/cards/i/ImposingSovereign.java +++ b/Mage.Sets/src/mage/cards/i/ImposingSovereign.java @@ -26,7 +26,7 @@ public final class ImposingSovereign extends CardImpl { // Creatures your opponents control enter the battlefield tapped. this.addAbility(new SimpleStaticAbility(new PermanentsEnterBattlefieldTappedEffect( StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE - ).setText("creatures your opponents control enter the battlefield tapped"))); + ).setText("creatures your opponents control enter tapped"))); } private ImposingSovereign(final ImposingSovereign card) { diff --git a/Mage.Sets/src/mage/cards/i/ImposterMech.java b/Mage.Sets/src/mage/cards/i/ImposterMech.java index 032a5d3ae73..4061536b07d 100644 --- a/Mage.Sets/src/mage/cards/i/ImposterMech.java +++ b/Mage.Sets/src/mage/cards/i/ImposterMech.java @@ -42,7 +42,7 @@ public final class ImposterMech extends CardImpl { // You may have Imposter Mech enter the battlefield as a copy of a creature an opponent controls, except its a Vehicle artifact with crew 3 and it loses all other card types. this.addAbility(new EntersBattlefieldAbility( new CopyPermanentEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_A_CREATURE, applier), true, - null, "You may have {this} enter the battlefield as a copy of a creature " + + null, "You may have {this} enter as a copy of a creature " + "an opponent controls, except it's a Vehicle artifact with crew 3 and it loses all other card types.", null )); diff --git a/Mage.Sets/src/mage/cards/i/InactionInjunction.java b/Mage.Sets/src/mage/cards/i/InactionInjunction.java index 11703b984be..cf98a54f3b7 100644 --- a/Mage.Sets/src/mage/cards/i/InactionInjunction.java +++ b/Mage.Sets/src/mage/cards/i/InactionInjunction.java @@ -1,40 +1,37 @@ - package mage.cards.i; - -import java.util.UUID; + import mage.abilities.effects.common.DetainTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.StaticFilters; -import mage.target.common.TargetCreaturePermanent; - +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + /** - * * @author LevelX2 */ public final class InactionInjunction extends CardImpl { - + public InactionInjunction(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}"); + // Detain target creature an opponent controls. // (Until your next turn, that creature can't attack or block and its activated abilities can't be activated.) this.getSpellAbility().addEffect(new DetainTargetEffect()); - TargetCreaturePermanent target = new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE); - this.getSpellAbility().addTarget(target); - + this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent()); + // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } - + private InactionInjunction(final InactionInjunction card) { super(card); } - + @Override public InactionInjunction copy() { return new InactionInjunction(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/i/InallaArchmageRitualist.java b/Mage.Sets/src/mage/cards/i/InallaArchmageRitualist.java index 28fe07109de..c57570a5c7a 100644 --- a/Mage.Sets/src/mage/cards/i/InallaArchmageRitualist.java +++ b/Mage.Sets/src/mage/cards/i/InallaArchmageRitualist.java @@ -1,31 +1,20 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.condition.common.SourceOnBattlefieldOrCommandZoneCondition; import mage.abilities.costs.common.TapTargetCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.effects.common.ExileTargetEffect; -import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AbilityWord; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SetTargetPointer; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.permanent.TappedPredicate; @@ -34,22 +23,20 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPlayer; import mage.target.common.TargetControlledPermanent; -import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class InallaArchmageRitualist extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("another nontoken Wizard"); - private static final FilterControlledPermanent filter2 = new FilterControlledPermanent("untapped Wizards you control"); + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.WIZARD, "another nontoken Wizard you control"); + private static final FilterControlledPermanent filter2 = new FilterControlledPermanent(SubType.WIZARD, "untapped Wizards you control"); static { - filter.add(SubType.WIZARD.getPredicate()); filter.add(TokenPredicate.FALSE); filter.add(AnotherPredicate.instance); - filter2.add(SubType.WIZARD.getPredicate()); filter2.add(TappedPredicate.UNTAPPED); } @@ -63,20 +50,19 @@ public final class InallaArchmageRitualist extends CardImpl { this.toughness = new MageInt(5); // Eminence - Whenever another nontoken Wizard you control enters, if Inalla, Archmage Ritualist is in the command zone or on the battlefield, you may pay {1}. If you do, create a token that's a copy of that Wizard. The token gains haste. Exile it at the beginning of the next end step. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldControlledTriggeredAbility(Zone.ALL, new DoIfCostPaid( - new InallaArchmageRitualistEffect(), new ManaCostsImpl<>("{1}"), "Pay {1} to create a token copy?"), - filter, false, SetTargetPointer.PERMANENT), - SourceOnBattlefieldOrCommandZoneCondition.instance, - "Whenever another nontoken Wizard you control enters, " - + "if {this} is in the command zone or on the battlefield, " - + "you may pay {1}. If you do, create a token that's a copy of that Wizard. " - + "The token gains haste. Exile it at the beginning of the next end step"); - ability.setAbilityWord(AbilityWord.EMINENCE); - this.addAbility(ability); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + Zone.ALL, + new DoIfCostPaid( + new InallaArchmageRitualistEffect(), new GenericManaCost(1), + "Pay {1} to create a token copy?" + ), filter, false, SetTargetPointer.PERMANENT + ).withInterveningIf(SourceOnBattlefieldOrCommandZoneCondition.instance).setAbilityWord(AbilityWord.EMINENCE)); // Tap five untapped Wizards you control: Target player loses 7 life. - ability = new SimpleActivatedAbility(new LoseLifeTargetEffect(7), new TapTargetCost(new TargetControlledPermanent(5, 5, filter2, true))); + Ability ability = new SimpleActivatedAbility( + new LoseLifeTargetEffect(7), + new TapTargetCost(new TargetControlledPermanent(5, filter2)) + ); ability.addTarget(new TargetPlayer()); this.addAbility(ability); } @@ -95,7 +81,7 @@ class InallaArchmageRitualistEffect extends OneShotEffect { InallaArchmageRitualistEffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "create a token that's a copy of that Wizard. That token gains haste. Exile it at the beginning of the next end step"; + this.staticText = "create a token that's a copy of that Wizard. The token gains haste. Exile it at the beginning of the next end step"; } private InallaArchmageRitualistEffect(final InallaArchmageRitualistEffect effect) { @@ -109,21 +95,14 @@ class InallaArchmageRitualistEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = getTargetPointer().getFirstTargetPermanentOrLKI(game, source); - if (permanent != null) { - CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(null, null, true); - effect.setTargetPointer(this.getTargetPointer().copy()); - if (effect.apply(game, source)) { - for (Permanent tokenPermanent : effect.getAddedPermanents()) { - ExileTargetEffect exileEffect = new ExileTargetEffect(); - exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - game.addDelayedTriggeredAbility(delayedAbility, source); - } - return true; - } + Permanent permanent = (Permanent) getValue("permanentEnteringBattlefield"); + if (permanent == null) { + return false; } - - return false; + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(null, null, true); + effect.setSavedPermanent(permanent); + effect.apply(game, source); + effect.exileTokensCreatedAtNextEndStep(game, source); + return true; } } diff --git a/Mage.Sets/src/mage/cards/i/InameAsOne.java b/Mage.Sets/src/mage/cards/i/InameAsOne.java index 6bbdde2369c..cc98884af02 100644 --- a/Mage.Sets/src/mage/cards/i/InameAsOne.java +++ b/Mage.Sets/src/mage/cards/i/InameAsOne.java @@ -1,14 +1,11 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromHandSourcePermanentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileSourceEffect; @@ -29,8 +26,9 @@ import mage.target.common.TargetCardInYourGraveyard; import mage.target.targetpointer.FixedTarget; import mage.watchers.common.CastFromHandWatcher; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class InameAsOne extends CardImpl { @@ -42,18 +40,16 @@ public final class InameAsOne extends CardImpl { } public InameAsOne(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{8}{B}{B}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{8}{B}{B}{G}{G}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.SPIRIT); this.power = new MageInt(8); this.toughness = new MageInt(8); // When Iname as One enters the battlefield, if you cast it from your hand, you may search your library for a Spirit permanent card, put it onto the battlefield, then shuffle your library. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(0, 1, filter)), true), - CastFromHandSourcePermanentCondition.instance, - "When {this} enters, if you cast it from your hand, you may search your library for a Spirit permanent card, put it onto the battlefield, then shuffle."), - new CastFromHandWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter)), true + ).withInterveningIf(CastFromHandSourcePermanentCondition.instance), new CastFromHandWatcher()); // When Iname as One dies, you may exile it. If you do, return target Spirit permanent card from your graveyard to the battlefield. Ability ability = new DiesSourceTriggeredAbility(new InameAsOneEffect(), false); diff --git a/Mage.Sets/src/mage/cards/i/Incendiary.java b/Mage.Sets/src/mage/cards/i/Incendiary.java index b349674d1a1..1da5f208c95 100644 --- a/Mage.Sets/src/mage/cards/i/Incendiary.java +++ b/Mage.Sets/src/mage/cards/i/Incendiary.java @@ -1,24 +1,25 @@ package mage.cards.i; -import java.util.UUID; -import mage.constants.SubType; -import mage.target.common.TargetCreaturePermanent; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.DiesAttachedTriggeredAbility; import mage.abilities.dynamicvalue.common.CountersSourceCount; import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.constants.Outcome; -import mage.target.TargetPermanent; import mage.abilities.keyword.EnchantAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; +import mage.target.TargetPermanent; import mage.target.common.TargetCreatureOrPlayer; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; /** * @@ -47,7 +48,7 @@ public final class Incendiary extends CardImpl { // When enchanted creature dies, Incendiary deals X damage to any target, where X is the number of fuse counters on Incendiary. Effect effect = new DamageTargetEffect(new CountersSourceCount(CounterType.FUSE)).setText(rule); Ability ability2 = new DiesAttachedTriggeredAbility(effect, "enchanted creature"); - ability.addTarget(new TargetCreatureOrPlayer()); + ability2.addTarget(new TargetCreatureOrPlayer()); this.addAbility(ability2); } diff --git a/Mage.Sets/src/mage/cards/i/IncisorGlider.java b/Mage.Sets/src/mage/cards/i/IncisorGlider.java index 20c35591e40..afbc4d58ec5 100644 --- a/Mage.Sets/src/mage/cards/i/IncisorGlider.java +++ b/Mage.Sets/src/mage/cards/i/IncisorGlider.java @@ -1,19 +1,18 @@ package mage.cards.i; -import java.util.UUID; - import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.CorruptedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.constants.AbilityWord; -import mage.constants.Duration; -import mage.constants.SubType; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; /** * @author TheElk801 @@ -32,11 +31,9 @@ public final class IncisorGlider extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Corrupted -- Whenever Incisor Glider attacks, if an opponent has three or more poison counters, creatures you control get +1/+1 until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new BoostControlledEffect(1, 1, Duration.EndOfTurn)), - CorruptedCondition.instance, "Whenever {this} attacks, if an opponent has three or " + - "more poison counters, creatures you control get +1/+1 until end of turn." - ).setAbilityWord(AbilityWord.CORRUPTED).addHint(CorruptedCondition.getHint())); + this.addAbility(new AttacksTriggeredAbility( + new BoostControlledEffect(1, 1, Duration.EndOfTurn) + ).withInterveningIf(CorruptedCondition.instance).setAbilityWord(AbilityWord.CORRUPTED).addHint(CorruptedCondition.getHint())); } private IncisorGlider(final IncisorGlider card) { diff --git a/Mage.Sets/src/mage/cards/i/IncrementalBlight.java b/Mage.Sets/src/mage/cards/i/IncrementalBlight.java index b6559225a3f..343a3e7f036 100644 --- a/Mage.Sets/src/mage/cards/i/IncrementalBlight.java +++ b/Mage.Sets/src/mage/cards/i/IncrementalBlight.java @@ -1,49 +1,44 @@ package mage.cards.i; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.other.AnotherTargetPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; +import mage.target.targetpointer.ThirdTargetPointer; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class IncrementalBlight extends CardImpl { - public IncrementalBlight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}{B}"); + private static final FilterPermanent filter = new FilterCreaturePermanent("another creature"); + static { + filter.add(new AnotherTargetPredicate(3)); + } + + public IncrementalBlight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}{B}"); // Put a -1/-1 counter on target creature, two -1/-1 counters on another target creature, and three -1/-1 counters on a third target creature. - this.getSpellAbility().addEffect(new IncrementalBlightEffect()); - - FilterCreaturePermanent filter1 = new FilterCreaturePermanent("creature (gets a -1/-1 counter)"); - TargetCreaturePermanent target1 = new TargetCreaturePermanent(filter1); - target1.setTargetTag(1); - this.getSpellAbility().addTarget(target1); - - FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another creature (gets two -1/-1 counters)"); - filter2.add(new AnotherTargetPredicate(2)); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter2); - target2.setTargetTag(2); - this.getSpellAbility().addTarget(target2); - - FilterCreaturePermanent filter3 = new FilterCreaturePermanent("another creature (gets three -1/-1 counters)"); - filter3.add(new AnotherTargetPredicate(3)); - TargetCreaturePermanent target3 = new TargetCreaturePermanent(filter3); - target3.setTargetTag(3); - this.getSpellAbility().addTarget(target3); + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.M1M1.createInstance())); + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.M1M1.createInstance(2)) + .setTargetPointer(new SecondTargetPointer()).setText(", two -1/-1 counters on another target creature")); + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.M1M1.createInstance(3)) + .setTargetPointer(new ThirdTargetPointer()).setText(", and three -1/-1 counters on a third target creature")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("gets a -1/-1 counter").setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2).withChooseHint("gets two -1/-1 counters").setTargetTag(2)); + this.getSpellAbility().addTarget(new TargetPermanent(filter).withChooseHint("gets three -1/-1 counters").setTargetTag(3)); } private IncrementalBlight(final IncrementalBlight card) { @@ -55,32 +50,3 @@ public final class IncrementalBlight extends CardImpl { return new IncrementalBlight(this); } } -class IncrementalBlightEffect extends OneShotEffect { - - public IncrementalBlightEffect() { - super(Outcome.UnboostCreature); - this.staticText = "Put a -1/-1 counter on target creature, two -1/-1 counters on another target creature, and three -1/-1 counters on a third target creature"; - } - - private IncrementalBlightEffect(final IncrementalBlightEffect effect) { - super(effect); - } - - @Override - public IncrementalBlightEffect copy() { - return new IncrementalBlightEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - int i = 0; - for (Target target : source.getTargets()) { - i++; - Permanent creature = game.getPermanent(target.getFirstTarget()); - if (creature != null) { - creature.addCounters(CounterType.M1M1.createInstance(i), source.getControllerId(), source, game); - } - } - return false; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/i/IncrementalGrowth.java b/Mage.Sets/src/mage/cards/i/IncrementalGrowth.java index 96ca91cb9d1..b36efc9a4f6 100644 --- a/Mage.Sets/src/mage/cards/i/IncrementalGrowth.java +++ b/Mage.Sets/src/mage/cards/i/IncrementalGrowth.java @@ -1,49 +1,45 @@ package mage.cards.i; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.other.AnotherTargetPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; +import mage.target.targetpointer.ThirdTargetPointer; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class IncrementalGrowth extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("another creature"); + + static { + filter.add(new AnotherTargetPredicate(3)); + } + public IncrementalGrowth(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}{G}"); // Put a +1/+1 counter on target creature, two +1/+1 counters on another target // creature, and three +1/+1 counters on a third target creature. - this.getSpellAbility().addEffect(new IncrementalGrowthEffect()); - - FilterCreaturePermanent filter1 = new FilterCreaturePermanent("creature (gets a +1/+1 counter)"); - TargetCreaturePermanent target1 = new TargetCreaturePermanent(filter1); - target1.setTargetTag(1); - this.getSpellAbility().addTarget(target1); - - FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another creature (gets two +1/+1 counters)"); - filter2.add(new AnotherTargetPredicate(2)); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter2); - target2.setTargetTag(2); - this.getSpellAbility().addTarget(target2); - - FilterCreaturePermanent filter3 = new FilterCreaturePermanent("another creature (gets three +1/+1 counters)"); - filter3.add(new AnotherTargetPredicate(3)); - TargetCreaturePermanent target3 = new TargetCreaturePermanent(filter3); - target3.setTargetTag(3); - this.getSpellAbility().addTarget(target3); + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)) + .setTargetPointer(new SecondTargetPointer()).setText(", two +1/+1 counters on another target creature")); + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(3)) + .setTargetPointer(new ThirdTargetPointer()).setText(", and three +1/+1 counters on a third target creature")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("gets a +1/+1 counter").setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2).withChooseHint("gets two +1/+1 counters").setTargetTag(2)); + this.getSpellAbility().addTarget(new TargetPermanent(filter).withChooseHint("gets three +1/+1 counters").setTargetTag(3)); } private IncrementalGrowth(final IncrementalGrowth card) { @@ -55,35 +51,3 @@ public final class IncrementalGrowth extends CardImpl { return new IncrementalGrowth(this); } } - -class IncrementalGrowthEffect extends OneShotEffect { - - IncrementalGrowthEffect() { - super(Outcome.Benefit); - this.staticText = "Put a +1/+1 counter on target creature, " - + "two +1/+1 counters on another target creature, " - + "and three +1/+1 counters on a third target creature"; - } - - private IncrementalGrowthEffect(final IncrementalGrowthEffect effect) { - super(effect); - } - - @Override - public IncrementalGrowthEffect copy() { - return new IncrementalGrowthEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - int i = 0; - for (Target target : source.getTargets()) { - i++; - Permanent creature = game.getPermanent(target.getFirstTarget()); - if (creature != null) { - creature.addCounters(CounterType.P1P1.createInstance(i), source.getControllerId(), source, game); - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/i/IndulgingPatrician.java b/Mage.Sets/src/mage/cards/i/IndulgingPatrician.java index 5c6e1417d83..0334027bf0b 100644 --- a/Mage.Sets/src/mage/cards/i/IndulgingPatrician.java +++ b/Mage.Sets/src/mage/cards/i/IndulgingPatrician.java @@ -1,15 +1,14 @@ package mage.cards.i; import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.YouGainedLifeCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -25,7 +24,7 @@ import java.util.UUID; public final class IndulgingPatrician extends CardImpl { private static final Condition condition = new YouGainedLifeCondition(ComparisonType.MORE_THAN, 2); - private static final Hint hint = new ConditionHint(condition, "You gained 3 or more life this turn"); + private static final Hint hint = new ConditionHint(condition); public IndulgingPatrician(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{B}"); @@ -42,12 +41,8 @@ public final class IndulgingPatrician extends CardImpl { this.addAbility(LifelinkAbility.getInstance()); // At the beginning of your end step, if you gained 3 or more life this turn, each opponent loses 3 life. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - new LoseLifeOpponentsEffect(3) - ), condition, "At the beginning of your end step, " + - "if you gained 3 or more life this turn, each opponent loses 3 life." - ).addHint(hint), new PlayerGainedLifeWatcher()); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new LoseLifeOpponentsEffect(3)) + .withInterveningIf(condition).addHint(hint), new PlayerGainedLifeWatcher()); } private IndulgingPatrician(final IndulgingPatrician card) { diff --git a/Mage.Sets/src/mage/cards/i/InexorableBlob.java b/Mage.Sets/src/mage/cards/i/InexorableBlob.java index 10feef7ff39..977258dfe90 100644 --- a/Mage.Sets/src/mage/cards/i/InexorableBlob.java +++ b/Mage.Sets/src/mage/cards/i/InexorableBlob.java @@ -1,19 +1,19 @@ package mage.cards.i; -import java.util.UUID; - import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; import mage.game.permanent.token.InexorableBlobOozeToken; +import java.util.UUID; + /** * @author fireshoes */ @@ -27,11 +27,9 @@ public final class InexorableBlob extends CardImpl { // Delirium — Whenever Inexorable Blob attacks, if there are four or more card types among cards // in your graveyard, create a 3/3 green Ooze creature token that’s tapped and attacking. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new AttacksTriggeredAbility(new CreateTokenEffect(new InexorableBlobOozeToken(), 1, true, true), false), - DeliriumCondition.instance, - "Delirium — Whenever {this} attacks, if there are four or more card types among cards in your graveyard, " + - "create a 3/3 green Ooze creature token that's tapped and attacking.") - .addHint(CardTypesInGraveyardCount.YOU.getHint())); + this.addAbility(new AttacksTriggeredAbility(new CreateTokenEffect( + new InexorableBlobOozeToken(), 1, true, true + )).withInterveningIf(DeliriumCondition.instance).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); } private InexorableBlob(final InexorableBlob card) { diff --git a/Mage.Sets/src/mage/cards/i/InfectedVermin.java b/Mage.Sets/src/mage/cards/i/InfectedVermin.java index 78c9ce5884f..61c6499c2cc 100644 --- a/Mage.Sets/src/mage/cards/i/InfectedVermin.java +++ b/Mage.Sets/src/mage/cards/i/InfectedVermin.java @@ -4,7 +4,7 @@ import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.ThresholdCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamageEverythingEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -30,7 +30,7 @@ public final class InfectedVermin extends CardImpl { this.addAbility(new SimpleActivatedAbility(new DamageEverythingEffect(1), new ManaCostsImpl<>("{2}{B}"))); // Threshold - {3}{B}: Infected Vermin deals 3 damage to each creature and each player. Activate this ability only if seven or more cards are in your graveyard. - this.addAbility(new ConditionalActivatedAbility( + this.addAbility(new ActivateIfConditionActivatedAbility( new DamageEverythingEffect(3), new ManaCostsImpl<>("{3}{B}"), ThresholdCondition.instance ).setAbilityWord(AbilityWord.THRESHOLD)); } diff --git a/Mage.Sets/src/mage/cards/i/InfectiousBite.java b/Mage.Sets/src/mage/cards/i/InfectiousBite.java index 3d77ad7eab2..b163633f2d3 100644 --- a/Mage.Sets/src/mage/cards/i/InfectiousBite.java +++ b/Mage.Sets/src/mage/cards/i/InfectiousBite.java @@ -8,11 +8,14 @@ import mage.constants.CardType; import mage.constants.TargetController; import mage.counters.CounterType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author TheElk801 */ @@ -24,7 +27,7 @@ public final class InfectiousBite extends CardImpl { // Target creature you control deals damage equal to its power to target creature you don't control. Each opponent gets a poison counter. this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.getSpellAbility().addEffect(new AddCountersPlayersEffect( CounterType.POISON.createInstance(), TargetController.OPPONENT )); diff --git a/Mage.Sets/src/mage/cards/i/InfernalDenizen.java b/Mage.Sets/src/mage/cards/i/InfernalDenizen.java index 1f2ce602ea9..8b9b07987c2 100644 --- a/Mage.Sets/src/mage/cards/i/InfernalDenizen.java +++ b/Mage.Sets/src/mage/cards/i/InfernalDenizen.java @@ -1,40 +1,36 @@ package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.condition.common.SourceOnBattlefieldCondition; -import mage.abilities.condition.common.SourceRemainsInZoneCondition; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.SacrificeControllerEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.TargetController; -import mage.constants.Zone; import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class InfernalDenizen extends CardImpl { @@ -50,11 +46,11 @@ public final class InfernalDenizen extends CardImpl { this.addAbility(new BeginningOfUpkeepTriggeredAbility(new InfernalDenizenEffect())); // {tap}: Gain control of target creature for as long as Infernal Denizen remains on the battlefield. - ConditionalContinuousEffect effect = new ConditionalContinuousEffect( - new GainControlTargetEffect(Duration.Custom, true), - new SourceRemainsInZoneCondition(Zone.BATTLEFIELD), - "gain control of target creature for as long as {this} remains on the battlefield"); - Ability ability = new SimpleActivatedAbility(effect, new TapSourceCost()); + Ability ability = new SimpleActivatedAbility( + new GainControlTargetEffect(Duration.UntilSourceLeavesBattlefield, true) + .setText("gain control of target creature for as long as {this} remains on the battlefield"), + new TapSourceCost() + ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } @@ -71,12 +67,7 @@ public final class InfernalDenizen extends CardImpl { class InfernalDenizenEffect extends OneShotEffect { - private static final FilterPermanent filter = new FilterPermanent(); - - static { - filter.add(SubType.SWAMP.getPredicate()); - filter.add(TargetController.YOU.getControllerPredicate()); - } + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.SWAMP); InfernalDenizenEffect() { super(Outcome.Benefit); @@ -96,41 +87,36 @@ class InfernalDenizenEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent creature = game.getPermanent(source.getSourceId()); - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - DynamicValue swamps = new PermanentsOnBattlefieldCount(filter); - boolean canSac = swamps.calculate(game, source, this) > 1; - Effect effect = new SacrificeControllerEffect(filter, 2, "Sacrifice two Swamps"); - effect.apply(game, source); - if (!canSac) { - if (creature != null) { - creature.tap(source, game); - } - TargetOpponent targetOpp = new TargetOpponent(true); - if (targetOpp.canChoose(player.getId(), source, game) - && targetOpp.choose(Outcome.Detriment, player.getId(), source.getSourceId(), source, game)) { - Player opponent = game.getPlayer(targetOpp.getFirstTarget()); - if (opponent != null) { - FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creature controlled by " + player.getLogName()); - filter2.add(new ControllerIdPredicate(player.getId())); - TargetCreaturePermanent targetCreature = new TargetCreaturePermanent(1, 1, filter2, true); - targetCreature.setTargetController(opponent.getId()); - if (targetCreature.canChoose(source.getControllerId(), source, game) - && opponent.chooseUse(Outcome.GainControl, "Gain control of a creature?", source, game) - && opponent.chooseTarget(Outcome.GainControl, targetCreature, source, game)) { - ConditionalContinuousEffect giveEffect = new ConditionalContinuousEffect( - new GainControlTargetEffect(Duration.Custom, true, opponent.getId()), - SourceOnBattlefieldCondition.instance, - ""); - giveEffect.setTargetPointer(new FixedTarget(targetCreature.getFirstTarget(), game)); - game.addEffect(giveEffect, source); - return true; - } - } - } - } + Cost cost = new SacrificeTargetCost(filter); + if (cost.canPay(source, source, source.getControllerId(), game) + && cost.pay(source, game, source, source.getControllerId(), true)) { + return true; } - return false; + Permanent creature = source.getSourcePermanentIfItStillExists(game); + if (creature == null) { + return false; + } + creature.tap(source, game); + TargetPlayer targetPlayer = new TargetOpponent(true); + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return true; + } + player.choose(outcome, targetPlayer, source, game); + Player opponent = game.getPlayer(targetPlayer.getFirstTarget()); + if (opponent == null) { + return true; + } + FilterPermanent filterPermanent = new FilterCreaturePermanent("creature controlled by " + player.getName()); + filterPermanent.add(new ControllerIdPredicate(player.getId())); + TargetPermanent target = new TargetPermanent(0, 1, filterPermanent, true); + opponent.choose(outcome, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + game.addEffect(new GainControlTargetEffect( + Duration.UntilSourceLeavesBattlefield, true, opponent.getId() + ).setTargetPointer(new FixedTarget(permanent, game)), source); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/i/InfernalSpawnOfEvil.java b/Mage.Sets/src/mage/cards/i/InfernalSpawnOfEvil.java index fed4b3f46ec..d4f5c352f5f 100644 --- a/Mage.Sets/src/mage/cards/i/InfernalSpawnOfEvil.java +++ b/Mage.Sets/src/mage/cards/i/InfernalSpawnOfEvil.java @@ -1,6 +1,5 @@ package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; @@ -16,21 +15,21 @@ import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.PhaseStep; import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetOpponentOrPlaneswalker; +import java.util.UUID; + /** - * * @author Ketsuban */ public final class InfernalSpawnOfEvil extends CardImpl { public InfernalSpawnOfEvil(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[] { CardType.CREATURE }, "{6}{B}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{B}{B}{B}"); this.subtype.add(SubType.BEAST); this.power = new MageInt(7); @@ -47,13 +46,13 @@ public final class InfernalSpawnOfEvil extends CardImpl { // Activate this ability only during your upkeep and only once each turn. Ability ability = new LimitedTimesPerTurnActivatedAbility(Zone.HAND, new DamageTargetEffect(1), new CompositeCost( - new ManaCostsImpl<>("{1}{B}"), - new CompositeCost( - new RevealSourceFromYourHandCost(), - new SayCost("It's coming!"), - "Reveal {this} from your hand, Say \"It's coming!\""), - "{1}{B}, Reveal {this} from your hand, Say \"It's coming!\""), - 1, new IsStepCondition(PhaseStep.UPKEEP, true)); + new ManaCostsImpl<>("{1}{B}"), + new CompositeCost( + new RevealSourceFromYourHandCost(), + new SayCost("It's coming!"), + "Reveal {this} from your hand, Say \"It's coming!\""), + "{1}{B}, Reveal {this} from your hand, Say \"It's coming!\""), + 1, IsStepCondition.getMyUpkeep()); ability.addTarget(new TargetOpponentOrPlaneswalker()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/InfernalVessel.java b/Mage.Sets/src/mage/cards/i/InfernalVessel.java index 5050807b7ba..1517b016807 100644 --- a/Mage.Sets/src/mage/cards/i/InfernalVessel.java +++ b/Mage.Sets/src/mage/cards/i/InfernalVessel.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldWithCounterTargetEffect; import mage.abilities.effects.common.continuous.AddCardSubTypeTargetEffect; @@ -22,26 +21,21 @@ import mage.util.CardUtil; import java.util.UUID; /** - * * @author ciaccona007 */ public final class InfernalVessel extends CardImpl { public InfernalVessel(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); - + this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); this.power = new MageInt(2); this.toughness = new MageInt(1); // When this creature dies, if it wasn't a Demon, return it to the battlefield under its owner's control with two +1/+1 counters on it. It's a Demon in addition to its other types. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new DiesSourceTriggeredAbility(new InfernalVesselReturnEffect()), - InfernalVesselCondition.instance, - "When this creature dies, if it wasn't a Demon, return it to the battlefield under its owner's control " - + "with two +1/+1 counters on it. It's a Demon in addition to its other types" - )); + this.addAbility(new DiesSourceTriggeredAbility(new InfernalVesselReturnEffect()) + .withInterveningIf(InfernalVesselCondition.instance)); } private InfernalVessel(final InfernalVessel card) { @@ -59,8 +53,15 @@ enum InfernalVesselCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) source.getEffects().get(0).getValue("permanentLeftBattlefield"); - return permanent != null && !permanent.hasSubtype(SubType.DEMON, game); + return CardUtil + .getEffectValueFromAbility(source, "permanentLeftBattlefield", Permanent.class) + .filter(permanent -> !permanent.hasSubtype(SubType.DEMON, game)) + .isPresent(); + } + + @Override + public String toString() { + return "it wasn't a Demon"; } } @@ -68,6 +69,7 @@ class InfernalVesselReturnEffect extends OneShotEffect { InfernalVesselReturnEffect() { super(Outcome.PutCreatureInPlay); + staticText = "return it to the battlefield under its owner's control with two +1/+1 counters on it. It's a Demon in addition to its other types"; } private InfernalVesselReturnEffect(final InfernalVesselReturnEffect effect) { diff --git a/Mage.Sets/src/mage/cards/i/InfernoHellion.java b/Mage.Sets/src/mage/cards/i/InfernoHellion.java index 8546f4673cb..b660716c70f 100644 --- a/Mage.Sets/src/mage/cards/i/InfernoHellion.java +++ b/Mage.Sets/src/mage/cards/i/InfernoHellion.java @@ -1,25 +1,24 @@ package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ShuffleIntoLibrarySourceEffect; -import mage.constants.SubType; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.constants.TargetController; import mage.game.Game; import mage.watchers.common.AttackedThisTurnWatcher; import mage.watchers.common.BlockedThisTurnWatcher; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class InfernoHellion extends CardImpl { @@ -35,18 +34,10 @@ public final class InfernoHellion extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // At the beginning of each end step, if Inferno Hellion attacked or blocked this turn, its owner shuffles it into their library. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - TargetController.ANY, new ShuffleIntoLibrarySourceEffect(), - false - ), - InfernoHellionCondition.instance, - "At the beginning of each end step, " - + "if {this} attacked or blocked this turn, " - + "its owner shuffles it into their library." - ); - ability.addWatcher(new BlockedThisTurnWatcher()); - this.addAbility(ability); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.ANY, new ShuffleIntoLibrarySourceEffect(), + false, InfernoHellionCondition.instance + ), new BlockedThisTurnWatcher()); } private InfernoHellion(final InfernoHellion card) { @@ -60,7 +51,6 @@ public final class InfernoHellion extends CardImpl { } enum InfernoHellionCondition implements Condition { - instance; @Override @@ -74,4 +64,9 @@ enum InfernoHellionCondition implements Condition { return watcherAttacked.getAttackedThisTurnCreatures().contains(mor) || watcherBlocked.getBlockedThisTurnCreatures().contains(mor); } + + @Override + public String toString() { + return "{this} attacked or blocked this turn"; + } } diff --git a/Mage.Sets/src/mage/cards/i/InfiniteHourglass.java b/Mage.Sets/src/mage/cards/i/InfiniteHourglass.java index b7219ba551a..794d4a13062 100644 --- a/Mage.Sets/src/mage/cards/i/InfiniteHourglass.java +++ b/Mage.Sets/src/mage/cards/i/InfiniteHourglass.java @@ -1,33 +1,35 @@ - package mage.cards.i; -import java.util.UUID; -import mage.abilities.ActivatedAbility; import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CountersSourceCount; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.PhaseStep; import mage.constants.TargetController; -import mage.constants.Zone; import mage.counters.CounterType; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class InfiniteHourglass extends CardImpl { + private static final DynamicValue xValue = new CountersSourceCount(CounterType.TIME); + private static final Condition condition = new IsStepCondition(PhaseStep.UPKEEP, false); + public InfiniteHourglass(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); @@ -35,23 +37,14 @@ public final class InfiniteHourglass extends CardImpl { this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.TIME.createInstance()))); // All creatures get +1/+0 for each time counter on Infinite Hourglass. - this.addAbility(new SimpleStaticAbility( - new BoostAllEffect( - new CountersSourceCount(CounterType.TIME), - StaticValue.get(0), - Duration.WhileOnBattlefield - ) - )); + this.addAbility(new SimpleStaticAbility(new BoostAllEffect( + xValue, StaticValue.get(0), Duration.WhileOnBattlefield + ))); // {3}: Remove a time counter from Infinite Hourglass. Any player may activate this ability but only during any upkeep step. - ActivatedAbility ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new RemoveCounterSourceEffect(CounterType.TIME.createInstance()), - new GenericManaCost(3), - new IsStepCondition(PhaseStep.UPKEEP, false) - ); - ability.setMayActivate(TargetController.ANY); - this.addAbility(ability); + this.addAbility(new ActivateIfConditionActivatedAbility( + new RemoveCounterSourceEffect(CounterType.TIME.createInstance()), new GenericManaCost(3), condition + ).withConditionText("any player may activate this ability but only during any upkeep step").setMayActivate(TargetController.ANY)); } private InfiniteHourglass(final InfiniteHourglass card) { diff --git a/Mage.Sets/src/mage/cards/i/IngeniousProdigy.java b/Mage.Sets/src/mage/cards/i/IngeniousProdigy.java index 2fb2158a51c..a03f3440b5d 100644 --- a/Mage.Sets/src/mage/cards/i/IngeniousProdigy.java +++ b/Mage.Sets/src/mage/cards/i/IngeniousProdigy.java @@ -1,16 +1,15 @@ package mage.cards.i; import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.costs.common.RemoveCountersSourceCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.EntersBattlefieldWithXCountersEffect; import mage.abilities.keyword.SkulkAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -41,15 +40,10 @@ public final class IngeniousProdigy extends CardImpl { this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.P1P1.createInstance()))); // At the beginning of your upkeep, if Ingenious Prodigy has one or more +1/+1 counters on it, you may remove a +1/+1 counter from it. If you do, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - new DoIfCostPaid( - new DrawCardSourceControllerEffect(1), - new RemoveCountersSourceCost(CounterType.P1P1.createInstance()) - ), false - ), condition, "At the beginning of your upkeep, if {this} has one or more " + - "+1/+1 counters on it, you may remove a +1/+1 counter from it. If you do, draw a card." - )); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DoIfCostPaid( + new DrawCardSourceControllerEffect(1), + new RemoveCountersSourceCost(CounterType.P1P1.createInstance()).setText("remove a +1/+1 counter from it") + )).withInterveningIf(condition)); } private IngeniousProdigy(final IngeniousProdigy card) { diff --git a/Mage.Sets/src/mage/cards/i/IngeniousSmith.java b/Mage.Sets/src/mage/cards/i/IngeniousSmith.java index 109dbd3b1ee..2e1f731c96d 100644 --- a/Mage.Sets/src/mage/cards/i/IngeniousSmith.java +++ b/Mage.Sets/src/mage/cards/i/IngeniousSmith.java @@ -1,8 +1,7 @@ package mage.cards.i; -import java.util.UUID; import mage.MageInt; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; @@ -12,16 +11,18 @@ import mage.constants.CardType; import mage.constants.PutCards; import mage.constants.SubType; import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; -import mage.filter.common.FilterArtifactPermanent; +import mage.filter.common.FilterControlledArtifactPermanent; + +import java.util.UUID; /** - * * @author weirddan455 */ public final class IngeniousSmith extends CardImpl { - private static final FilterArtifactPermanent filter = new FilterArtifactPermanent("one or more artifacts"); + private static final FilterPermanent filter = new FilterControlledArtifactPermanent("one or more artifacts you control"); public IngeniousSmith(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); @@ -34,12 +35,16 @@ public final class IngeniousSmith extends CardImpl { // When Ingenious Smith enters the battlefield, look at the top four cards of your library. // You may reveal an artifact card from among them and put it into your hand. // Put the rest on the bottom of your library in a random order. - this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( - 4, 1, StaticFilters.FILTER_CARD_ARTIFACT_AN, PutCards.HAND, PutCards.BOTTOM_RANDOM))); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new LookLibraryAndPickControllerEffect( + 4, 1, StaticFilters.FILTER_CARD_ARTIFACT_AN, + PutCards.HAND, PutCards.BOTTOM_RANDOM + ) + )); // Whenever one or more artifacts enter the battlefield under your control, put a +1/+1 counter on Ingenious Smith. // This ability triggers only once each turn. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + this.addAbility(new EntersBattlefieldAllTriggeredAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter ).setTriggersLimitEachTurn(1)); } diff --git a/Mage.Sets/src/mage/cards/i/InnerFire.java b/Mage.Sets/src/mage/cards/i/InnerFire.java index 1e286f7e104..dcaabe61dd1 100644 --- a/Mage.Sets/src/mage/cards/i/InnerFire.java +++ b/Mage.Sets/src/mage/cards/i/InnerFire.java @@ -20,7 +20,7 @@ public final class InnerFire extends CardImpl { // Add {R} for each card in your hand. - this.getSpellAbility().addEffect(new DynamicManaEffect(Mana.RedMana(1), CardsInControllerHandCount.ANY)); + this.getSpellAbility().addEffect(new DynamicManaEffect(Mana.RedMana(1), CardsInControllerHandCount.ANY_SINGULAR)); } private InnerFire(final InnerFire card) { diff --git a/Mage.Sets/src/mage/cards/i/Inquisition.java b/Mage.Sets/src/mage/cards/i/Inquisition.java index 5d9e9427d9a..d538d10bb0f 100644 --- a/Mage.Sets/src/mage/cards/i/Inquisition.java +++ b/Mage.Sets/src/mage/cards/i/Inquisition.java @@ -50,7 +50,7 @@ class InquisitionEffect extends OneShotEffect { public InquisitionEffect() { super(Outcome.Exile); - staticText = "Target player reveals their hand. Inquisition deals damage to that player equal to the number of white cards in their hand"; + staticText = "Target player reveals their hand. {this} deals damage to that player equal to the number of white cards in their hand"; } private InquisitionEffect(final InquisitionEffect effect) { diff --git a/Mage.Sets/src/mage/cards/i/InquisitorsFlail.java b/Mage.Sets/src/mage/cards/i/InquisitorsFlail.java index 03205bc4cf1..e52c817ec8f 100644 --- a/Mage.Sets/src/mage/cards/i/InquisitorsFlail.java +++ b/Mage.Sets/src/mage/cards/i/InquisitorsFlail.java @@ -3,12 +3,14 @@ package mage.cards.i; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.keyword.EquipAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.game.Game; import mage.game.events.DamageEvent; import mage.game.events.GameEvent; @@ -16,7 +18,6 @@ import mage.game.permanent.Permanent; import mage.util.CardUtil; import java.util.UUID; -import mage.target.common.TargetControlledCreaturePermanent; /** * @author nantuko @@ -32,7 +33,7 @@ public final class InquisitorsFlail extends CardImpl { this.addAbility(new SimpleStaticAbility(new InquisitorsFlailEffect())); // Equip {2} - this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(2), new TargetControlledCreaturePermanent(), false)); + this.addAbility(new EquipAbility(2, false)); } private InquisitorsFlail(final InquisitorsFlail card) { @@ -49,7 +50,7 @@ class InquisitorsFlailEffect extends ReplacementEffectImpl { InquisitorsFlailEffect() { super(Duration.WhileOnBattlefield, Outcome.Damage); - staticText = "If equipped creature would deal combat damage, it deals double that damage instead. \n" + staticText = "If equipped creature would deal combat damage, it deals double that damage instead.
" + "If another creature would deal combat damage to equipped creature, it deals double that damage to equipped creature instead"; } diff --git a/Mage.Sets/src/mage/cards/i/InsatiableSkittermaw.java b/Mage.Sets/src/mage/cards/i/InsatiableSkittermaw.java new file mode 100644 index 00000000000..4a1c3855eca --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InsatiableSkittermaw.java @@ -0,0 +1,48 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.condition.common.VoidCondition; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.watchers.common.VoidWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InsatiableSkittermaw extends CardImpl { + + public InsatiableSkittermaw(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.INSECT); + this.subtype.add(SubType.HORROR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Menace + this.addAbility(new MenaceAbility()); + + // Void -- At the beginning of your end step, if a nonland permanent left the battlefield this turn or a spell was warped this turn, put a +1/+1 counter on this creature. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()) + ).withInterveningIf(VoidCondition.instance).setAbilityWord(AbilityWord.VOID).addHint(VoidCondition.getHint()), new VoidWatcher()); + } + + private InsatiableSkittermaw(final InsatiableSkittermaw card) { + super(card); + } + + @Override + public InsatiableSkittermaw copy() { + return new InsatiableSkittermaw(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InscriptionOfAbundance.java b/Mage.Sets/src/mage/cards/i/InscriptionOfAbundance.java index 0e0c67f2563..5568a081e94 100644 --- a/Mage.Sets/src/mage/cards/i/InscriptionOfAbundance.java +++ b/Mage.Sets/src/mage/cards/i/InscriptionOfAbundance.java @@ -16,6 +16,7 @@ import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.TargetPlayer; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; @@ -23,6 +24,8 @@ import mage.target.common.TargetCreaturePermanent; import java.util.Objects; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author TheElk801 */ @@ -49,7 +52,7 @@ public final class InscriptionOfAbundance extends CardImpl { // • Target creature you control fights target creature you don't control. mode = new Mode(new FightTargetsEffect(false)); mode.addTarget(new TargetControlledCreaturePermanent().withChooseHint("fights")); - mode.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL).withChooseHint("fights")); + mode.addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL).withChooseHint("fights")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/i/IntegrityIntervention.java b/Mage.Sets/src/mage/cards/i/IntegrityIntervention.java index 3c51fb1f7fc..08bce3880fa 100644 --- a/Mage.Sets/src/mage/cards/i/IntegrityIntervention.java +++ b/Mage.Sets/src/mage/cards/i/IntegrityIntervention.java @@ -1,6 +1,5 @@ package mage.cards.i; -import java.util.UUID; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; @@ -12,8 +11,9 @@ import mage.constants.SpellAbilityType; import mage.target.common.TargetAnyTarget; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class IntegrityIntervention extends SplitCard { @@ -33,7 +33,7 @@ public final class IntegrityIntervention extends SplitCard { // Intervention // Intervention deals 3 damage to any target and you gain 3 life. this.getRightHalfCard().getSpellAbility().addEffect( - new DamageTargetEffect(3).setText("Intervention deals 3 damage to any target") + new DamageTargetEffect(3).setText("{this} deals 3 damage to any target") ); this.getRightHalfCard().getSpellAbility().addEffect( new GainLifeEffect(3).setText("and you gain 3 life") diff --git a/Mage.Sets/src/mage/cards/i/IntimidationTactics.java b/Mage.Sets/src/mage/cards/i/IntimidationTactics.java index 29f8234c272..79b2c04a6d7 100644 --- a/Mage.Sets/src/mage/cards/i/IntimidationTactics.java +++ b/Mage.Sets/src/mage/cards/i/IntimidationTactics.java @@ -7,6 +7,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.common.TargetOpponent; import java.util.UUID; @@ -20,6 +21,7 @@ public final class IntimidationTactics extends CardImpl { // Target opponent reveals their hand. You choose an artifact or creature card from it. Exile that card. this.getSpellAbility().addEffect(new ExileCardYouChooseTargetOpponentEffect(StaticFilters.FILTER_CARD_ARTIFACT_OR_CREATURE)); + this.getSpellAbility().addTarget(new TargetOpponent()); // Cycling {3} this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{3}"))); diff --git a/Mage.Sets/src/mage/cards/i/IntrepidHero.java b/Mage.Sets/src/mage/cards/i/IntrepidHero.java index a22cf92ce3d..eea2276794b 100644 --- a/Mage.Sets/src/mage/cards/i/IntrepidHero.java +++ b/Mage.Sets/src/mage/cards/i/IntrepidHero.java @@ -15,6 +15,7 @@ import mage.constants.ComparisonType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class IntrepidHero extends CardImpl { // {tap}: Destroy target creature with power 4 or greater. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/InventorsFair.java b/Mage.Sets/src/mage/cards/i/InventorsFair.java index be5427e89b1..38dda972622 100644 --- a/Mage.Sets/src/mage/cards/i/InventorsFair.java +++ b/Mage.Sets/src/mage/cards/i/InventorsFair.java @@ -1,7 +1,6 @@ package mage.cards.i; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.MetalcraftCondition; import mage.abilities.costs.common.SacrificeSourceCost; @@ -11,15 +10,12 @@ import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.hint.common.MetalcraftHint; import mage.abilities.mana.ColorlessManaAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.filter.common.FilterArtifactPermanent; -import mage.game.Game; -import mage.game.events.GameEvent; import mage.target.common.TargetCardInLibrary; import java.util.UUID; @@ -34,19 +30,20 @@ public final class InventorsFair extends CardImpl { this.supertype.add(SuperType.LEGENDARY); // At the beginning of your upkeep, if you control three or more artifacts, you gain 1 life. - this.addAbility(new InventorsFairAbility()); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new GainLifeEffect(1)) + .withInterveningIf(MetalcraftCondition.instance)); // {t}: Add {C}. this.addAbility(new ColorlessManaAbility()); // {4}, {T}, Sacrifice Inventors' Fair: Search your library for an artifact card, reveal it, put it into your hand, then shuffle your library. // Activate this ability only if you control threeor more artifacts. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_ARTIFACT), true), - new GenericManaCost(4), MetalcraftCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility(new SearchLibraryPutInHandEffect( + new TargetCardInLibrary(StaticFilters.FILTER_CARD_ARTIFACT), true + ), new GenericManaCost(4), MetalcraftCondition.instance); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); - ability.addHint(MetalcraftHint.instance); - this.addAbility(ability); + this.addAbility(ability.addHint(MetalcraftHint.instance)); } private InventorsFair(final InventorsFair card) { @@ -58,41 +55,3 @@ public final class InventorsFair extends CardImpl { return new InventorsFair(this); } } - -class InventorsFairAbility extends TriggeredAbilityImpl { - - private FilterArtifactPermanent filter = new FilterArtifactPermanent(); - - public InventorsFairAbility() { - super(Zone.BATTLEFIELD, new GainLifeEffect(1)); - } - - private InventorsFairAbility(final InventorsFairAbility ability) { - super(ability); - } - - @Override - public InventorsFairAbility copy() { - return new InventorsFairAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - return event.getPlayerId().equals(this.controllerId); - } - - @Override - public boolean checkInterveningIfClause(Game game) { - return game.getBattlefield().countAll(filter, this.controllerId, game) >= 3; - } - - @Override - public String getRule() { - return "At the beginning of your upkeep, if you control three or more artifacts, you gain 1 life."; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/i/InventoryManagement.java b/Mage.Sets/src/mage/cards/i/InventoryManagement.java new file mode 100644 index 00000000000..ecaf2f9f119 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InventoryManagement.java @@ -0,0 +1,109 @@ +package mage.cards.i; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.SplitSecondAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetImpl; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class InventoryManagement extends CardImpl { + + public InventoryManagement(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}{W}"); + + // Split second + this.addAbility(new SplitSecondAbility()); + + // For each Aura and Equipment you control, you may attach it to a creature you control. + this.getSpellAbility().addEffect(new InventoryManagementEffect()); + } + + private InventoryManagement(final InventoryManagement card) { + super(card); + } + + @Override + public InventoryManagement copy() { + return new InventoryManagement(this); + } +} + +class InventoryManagementEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterControlledPermanent("Aura or Equipment you control"); + + static { + filter.add(Predicates.or( + SubType.AURA.getPredicate(), + SubType.EQUIPMENT.getPredicate() + )); + } + + InventoryManagementEffect() { + super(Outcome.Benefit); + staticText = "for each Aura and Equipment you control, you may attach it to a creature you control"; + } + + private InventoryManagementEffect(final InventoryManagementEffect effect) { + super(effect); + } + + @Override + public InventoryManagementEffect copy() { + return new InventoryManagementEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null + || !game.getBattlefield().contains(filter, source, game, 1) + || !game.getBattlefield().contains(StaticFilters.FILTER_CONTROLLED_CREATURE, source, game, 1)) { + return false; + } + TargetPermanent target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); + target.withChooseHint("to attach to a creature you control"); + player.choose(outcome, target, source, game); + List permanents = target + .getTargets() + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + if (permanents.isEmpty()) { + return false; + } + for (Permanent permanent : permanents) { + TargetPermanent targetCreature = new TargetControlledCreaturePermanent(0, 1); + targetCreature.withNotTarget(true); + targetCreature.withChooseHint("to attach " + permanent.getLogName() + " to"); + Optional.ofNullable(targetCreature) + .map(TargetImpl::getFirstTarget) + .map(game::getPermanent) + .ifPresent(p -> p.addAttachment(permanent.getId(), source, game)); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvigoratedRampage.java b/Mage.Sets/src/mage/cards/i/InvigoratedRampage.java index 303332f0ace..3e6e9091032 100644 --- a/Mage.Sets/src/mage/cards/i/InvigoratedRampage.java +++ b/Mage.Sets/src/mage/cards/i/InvigoratedRampage.java @@ -1,9 +1,6 @@ - package mage.cards.i; -import java.util.UUID; import mage.abilities.Mode; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.TrampleAbility; @@ -13,8 +10,9 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Styxo */ public final class InvigoratedRampage extends CardImpl { @@ -24,21 +22,15 @@ public final class InvigoratedRampage extends CardImpl { // Choose one // Target creature gets +4/+0 and gains trample until end of turn. - Effect effect = new BoostTargetEffect(4, 0, Duration.EndOfTurn); - effect.setText("Target creature gets +4/+0"); - this.getSpellAbility().addEffect(effect); - effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); - effect.setText("and gains trample until end of turn"); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(new BoostTargetEffect(4, 0).setText("target creature gets +4/+0")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains trample until end of turn")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Two target creatures each get +2/+0 and gain trample until end of turn. - effect = new BoostTargetEffect(2, 0, Duration.EndOfTurn); - effect.setText("Two target creatures each get +2/+0"); - Mode mode = new Mode(effect); - effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); - effect.setText("and gain trample until end of turn"); - mode.addEffect(effect); + Mode mode = new Mode(new BoostTargetEffect(2, 0).setText("two target creatures each get +2/+0")); + mode.addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance()).setText("and gain trample until end of turn")); mode.addTarget(new TargetCreaturePermanent(2)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/i/IronApprentice.java b/Mage.Sets/src/mage/cards/i/IronApprentice.java index 0671b3432d1..3fc9dd21fc1 100644 --- a/Mage.Sets/src/mage/cards/i/IronApprentice.java +++ b/Mage.Sets/src/mage/cards/i/IronApprentice.java @@ -58,6 +58,7 @@ class IronApprenticeEffect extends OneShotEffect { IronApprenticeEffect() { super(Outcome.Benefit); + staticText = "put those counters on target creature you control"; } private IronApprenticeEffect(final IronApprenticeEffect effect) { diff --git a/Mage.Sets/src/mage/cards/i/IronFistOfTheEmpire.java b/Mage.Sets/src/mage/cards/i/IronFistOfTheEmpire.java index 80c03b2baec..2c4151e5365 100644 --- a/Mage.Sets/src/mage/cards/i/IronFistOfTheEmpire.java +++ b/Mage.Sets/src/mage/cards/i/IronFistOfTheEmpire.java @@ -1,23 +1,21 @@ - package mage.cards.i; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.common.HateCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.TargetController; import mage.game.permanent.token.RoyalGuardToken; import mage.watchers.common.LifeLossOtherFromCombatWatcher; +import java.util.UUID; + /** - * * @author Styxo */ public final class IronFistOfTheEmpire extends CardImpl { @@ -26,13 +24,11 @@ public final class IronFistOfTheEmpire extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}{B}{R}"); // Hate — At the beggining of each end step, if opponent lost life from a source other than combat damage this turn, you gain 2 life and create a 2/2 red Soldier creature token with first strike name Royal Guard. - TriggeredAbility triggeredAbility = new BeginningOfEndStepTriggeredAbility(TargetController.ANY, new GainLifeEffect(2), false); - triggeredAbility.addEffect(new CreateTokenEffect(new RoyalGuardToken())); - Ability ability = new ConditionalInterveningIfTriggeredAbility( - triggeredAbility, - HateCondition.instance, - "Hate — At the beggining of each end step, if opponent lost life from a source other than combat damage this turn, you gain 1 life and create a 2/2 red Soldier creature token with first strike named Royal Guard."); - this.addAbility(ability, new LifeLossOtherFromCombatWatcher()); + Ability ability = new BeginningOfEndStepTriggeredAbility( + TargetController.ANY, new GainLifeEffect(2), false + ).withInterveningIf(HateCondition.instance); + ability.addEffect(new CreateTokenEffect(new RoyalGuardToken()).concatBy("and")); + this.addAbility(ability.setAbilityWord(AbilityWord.HATE), new LifeLossOtherFromCombatWatcher()); } private IronFistOfTheEmpire(final IronFistOfTheEmpire card) { diff --git a/Mage.Sets/src/mage/cards/i/IronHeartChimera.java b/Mage.Sets/src/mage/cards/i/IronHeartChimera.java index 799f7165b19..8ebc556645b 100644 --- a/Mage.Sets/src/mage/cards/i/IronHeartChimera.java +++ b/Mage.Sets/src/mage/cards/i/IronHeartChimera.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -45,7 +46,7 @@ public final class IronHeartChimera extends CardImpl { Ability ability = new SimpleActivatedAbility(new AddCountersTargetEffect(CounterType.P2P2.createInstance()), new SacrificeSourceCost()); ability.addEffect(new GainAbilityTargetEffect(VigilanceAbility.getInstance(), Duration.WhileOnBattlefield) .setText("It gains vigilance. (This effect lasts indefinitely.)")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/IshkanahGrafwidow.java b/Mage.Sets/src/mage/cards/i/IshkanahGrafwidow.java index cea21a63a50..eace7802f5b 100644 --- a/Mage.Sets/src/mage/cards/i/IshkanahGrafwidow.java +++ b/Mage.Sets/src/mage/cards/i/IshkanahGrafwidow.java @@ -6,15 +6,17 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; import mage.abilities.keyword.ReachAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; @@ -29,7 +31,10 @@ import java.util.UUID; */ public final class IshkanahGrafwidow extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.SPIDER, "Spider you control"); + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount( + new FilterControlledPermanent(SubType.SPIDER, "Spider you control") + ); + private static final Hint hint = new ValueHint("Spiders you control", xValue); public IshkanahGrafwidow(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); @@ -43,20 +48,16 @@ public final class IshkanahGrafwidow extends CardImpl { // Delirium &mdash When Ishkanah, Grafwidow enters the battlefield, if there are four or more card types among cards in your graveyard, // create three 1/2 green Spider creature tokens with reach. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new SpiderToken(), 3), false), - DeliriumCondition.instance, - "Delirium — When {this} enters, if there are four or more card types among cards in your graveyard, " - + "create three 1/2 green Spider creature tokens with reach."); - ability.addHint(CardTypesInGraveyardCount.YOU.getHint()); - this.addAbility(ability); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new CreateTokenEffect(new SpiderToken(), 3), false + ).withInterveningIf(DeliriumCondition.instance) + .setAbilityWord(AbilityWord.DELIRIUM) + .addHint(CardTypesInGraveyardCount.YOU.getHint())); // {5}{B}: Target opponent loses 1 life for each Spider you control. - PermanentsOnBattlefieldCount count = new PermanentsOnBattlefieldCount(filter); - ability = new SimpleActivatedAbility(new LoseLifeTargetEffect(count), new ManaCostsImpl<>("{6}{B}")); + Ability ability = new SimpleActivatedAbility(new LoseLifeTargetEffect(xValue), new ManaCostsImpl<>("{6}{B}")); ability.addTarget(new TargetOpponent()); - ability.addHint(new ValueHint("Spiders you control", count)); - this.addAbility(ability); + this.addAbility(ability.addHint(hint)); } private IshkanahGrafwidow(final IshkanahGrafwidow card) { diff --git a/Mage.Sets/src/mage/cards/i/IslandOfWakWak.java b/Mage.Sets/src/mage/cards/i/IslandOfWakWak.java index 0b75eb02e36..fd027139515 100644 --- a/Mage.Sets/src/mage/cards/i/IslandOfWakWak.java +++ b/Mage.Sets/src/mage/cards/i/IslandOfWakWak.java @@ -18,6 +18,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class IslandOfWakWak extends CardImpl { // {tap}: Target creature with flying has base power 0 until end of turn. Ability ability = new SimpleActivatedAbility(new IslandOfWakWakEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filterWithFlying)); + ability.addTarget(new TargetPermanent(filterWithFlying)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/IsolatedWatchtower.java b/Mage.Sets/src/mage/cards/i/IsolatedWatchtower.java index 7d0d9c4489e..c3119d300b2 100644 --- a/Mage.Sets/src/mage/cards/i/IsolatedWatchtower.java +++ b/Mage.Sets/src/mage/cards/i/IsolatedWatchtower.java @@ -1,11 +1,10 @@ package mage.cards.i; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.Card; @@ -19,8 +18,9 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class IsolatedWatchtower extends CardImpl { @@ -32,11 +32,8 @@ public final class IsolatedWatchtower extends CardImpl { this.addAbility(new ColorlessManaAbility()); // {2}, {T}: Scry 1, then you may reveal the top card of your library. If a basic land card is revealed this way, put it onto the battlefield tapped. Activate this ability only if an opponent controls at least two more lands than you. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, - new IsolatedWatchtowerEffect(), - new GenericManaCost(2), - new IsolatedWatchtowerCondition() + Ability ability = new ActivateIfConditionActivatedAbility( + new IsolatedWatchtowerEffect(), new GenericManaCost(2), IsolatedWatchtowerCondition.instance ); ability.addCost(new TapSourceCost()); this.addAbility(ability); @@ -94,7 +91,8 @@ class IsolatedWatchtowerEffect extends OneShotEffect { } } -class IsolatedWatchtowerCondition implements Condition { +enum IsolatedWatchtowerCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { diff --git a/Mage.Sets/src/mage/cards/i/IsperiasSkywatch.java b/Mage.Sets/src/mage/cards/i/IsperiasSkywatch.java index 186570dd784..4ad79be3a97 100644 --- a/Mage.Sets/src/mage/cards/i/IsperiasSkywatch.java +++ b/Mage.Sets/src/mage/cards/i/IsperiasSkywatch.java @@ -1,7 +1,5 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -11,17 +9,17 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.StaticFilters; -import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class IsperiasSkywatch extends CardImpl { - + public IsperiasSkywatch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}"); this.subtype.add(SubType.VEDALKEN); this.subtype.add(SubType.KNIGHT); @@ -30,12 +28,11 @@ public final class IsperiasSkywatch extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // When Isperia's Skywatch enters the battlefield, detain target creature an opponent controls. // (Until your next turn, that creature can't attack or block and its activated abilities can't be activated.) Ability ability = new EntersBattlefieldTriggeredAbility(new DetainTargetEffect()); - TargetCreaturePermanent target = new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE); - ability.addTarget(target); + ability.addTarget(new TargetOpponentsCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/ItlimocCradleOfTheSun.java b/Mage.Sets/src/mage/cards/i/ItlimocCradleOfTheSun.java index a1140a281d8..a9f5a6dffcc 100644 --- a/Mage.Sets/src/mage/cards/i/ItlimocCradleOfTheSun.java +++ b/Mage.Sets/src/mage/cards/i/ItlimocCradleOfTheSun.java @@ -1,11 +1,8 @@ package mage.cards.i; -import java.util.UUID; - import mage.Mana; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; -import mage.abilities.hint.Hint; -import mage.abilities.hint.ValueHint; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.abilities.mana.DynamicManaAbility; import mage.abilities.mana.GreenManaAbility; import mage.cards.CardImpl; @@ -14,19 +11,16 @@ import mage.constants.CardType; import mage.constants.SuperType; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author JRHerlehy */ public final class ItlimocCradleOfTheSun extends CardImpl { - private static final Hint hint = new ValueHint( - "Number of creatures you control", new PermanentsOnBattlefieldCount(StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED) - ); - public ItlimocCradleOfTheSun(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - + this.supertype.add(SuperType.LEGENDARY); // (Transforms from Growing Rites of Itlimoc.)/ @@ -36,7 +30,7 @@ public final class ItlimocCradleOfTheSun extends CardImpl { this.addAbility(new GreenManaAbility()); // {T}: Add {G} for each creature you control. - this.addAbility(new DynamicManaAbility(Mana.GreenMana(1), new PermanentsOnBattlefieldCount(StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED)).addHint(hint)); + this.addAbility(new DynamicManaAbility(Mana.GreenMana(1), new PermanentsOnBattlefieldCount(StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED)).addHint(CreaturesYouControlHint.instance)); } private ItlimocCradleOfTheSun(final ItlimocCradleOfTheSun card) { diff --git a/Mage.Sets/src/mage/cards/i/ItzquinthFirstbornOfGishath.java b/Mage.Sets/src/mage/cards/i/ItzquinthFirstbornOfGishath.java index 3f0183fb6f5..07410694410 100644 --- a/Mage.Sets/src/mage/cards/i/ItzquinthFirstbornOfGishath.java +++ b/Mage.Sets/src/mage/cards/i/ItzquinthFirstbornOfGishath.java @@ -16,6 +16,7 @@ import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.other.AnotherTargetPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; @@ -47,7 +48,7 @@ public final class ItzquinthFirstbornOfGishath extends CardImpl { // When Itzquinth enters the battlefield, you may pay {2}. When you do, target Dinosaur you control deals damage equal to its power to another target creature. ReflexiveTriggeredAbility reflexive = new ReflexiveTriggeredAbility(new DamageWithPowerFromOneToAnotherTargetEffect(), false); reflexive.addTarget(new TargetControlledPermanent(filter1).setTargetTag(1)); // may not be a creature. Don't ask me why. - reflexive.addTarget(new TargetCreaturePermanent(filter2).setTargetTag(2)); + reflexive.addTarget(new TargetPermanent(filter2).setTargetTag(2)); this.addAbility(new EntersBattlefieldTriggeredAbility( new DoWhenCostPaid(reflexive, new GenericManaCost(2), "Pay {2}?") )); diff --git a/Mage.Sets/src/mage/cards/i/IvoryCraneNetsuke.java b/Mage.Sets/src/mage/cards/i/IvoryCraneNetsuke.java index 18a83c4c14a..3b08be2f2af 100644 --- a/Mage.Sets/src/mage/cards/i/IvoryCraneNetsuke.java +++ b/Mage.Sets/src/mage/cards/i/IvoryCraneNetsuke.java @@ -1,31 +1,28 @@ - package mage.cards.i; -import java.util.UUID; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInHandCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class IvoryCraneNetsuke extends CardImpl { + private static final Condition condition = new CardsInHandCondition(ComparisonType.MORE_THAN, 6); + public IvoryCraneNetsuke(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // At the beginning of your upkeep, if you have seven or more cards in hand, you gain 4 life. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new GainLifeEffect(4)); - CardsInHandCondition condition = new CardsInHandCondition(ComparisonType.MORE_THAN, 6); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, condition, "At the beginning of your upkeep, if you have seven or more cards in hand, you gain 4 life.")); - + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new GainLifeEffect(4)).withInterveningIf(condition)); } private IvoryCraneNetsuke(final IvoryCraneNetsuke card) { diff --git a/Mage.Sets/src/mage/cards/i/IvoryMask.java b/Mage.Sets/src/mage/cards/i/IvoryMask.java index 1d8d3eb5d0c..c178f6ad089 100644 --- a/Mage.Sets/src/mage/cards/i/IvoryMask.java +++ b/Mage.Sets/src/mage/cards/i/IvoryMask.java @@ -1,4 +1,3 @@ - package mage.cards.i; import java.util.UUID; @@ -19,7 +18,6 @@ public final class IvoryMask extends CardImpl { public IvoryMask(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}{W}"); - // You have shroud. this.addAbility(new SimpleStaticAbility(new GainAbilityControllerEffect(ShroudAbility.getInstance()))); } diff --git a/Mage.Sets/src/mage/cards/i/IxidorRealitySculptor.java b/Mage.Sets/src/mage/cards/i/IxidorRealitySculptor.java index 97c3b1ccba2..3fa598cc4f3 100644 --- a/Mage.Sets/src/mage/cards/i/IxidorRealitySculptor.java +++ b/Mage.Sets/src/mage/cards/i/IxidorRealitySculptor.java @@ -14,6 +14,7 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.card.FaceDownPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -44,7 +45,7 @@ public final class IxidorRealitySculptor extends CardImpl { // {2}{U}: Turn target face-down creature face up. Ability ability = new SimpleActivatedAbility(new TurnFaceUpTargetEffect(), new ManaCostsImpl<>("{2}{U}")); - ability.addTarget(new TargetCreaturePermanent(filterTarget)); + ability.addTarget(new TargetPermanent(filterTarget)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/j/JabarisInfluence.java b/Mage.Sets/src/mage/cards/j/JabarisInfluence.java index e93b88a110c..c8d546de0e8 100644 --- a/Mage.Sets/src/mage/cards/j/JabarisInfluence.java +++ b/Mage.Sets/src/mage/cards/j/JabarisInfluence.java @@ -20,6 +20,7 @@ import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.watchers.Watcher; @@ -48,7 +49,7 @@ public final class JabarisInfluence extends CardImpl { // Gain control of target nonartifact, nonblack creature that attacked you this turn and put a -1/-0 counter on it. this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.Custom)); this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.M1M0.createInstance()).setText("and put a -1/-0 counter on it")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addWatcher(new JabarisInfluenceWatcher()); } diff --git a/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java b/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java index ad4ef1f1cff..22499a1b5fc 100644 --- a/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java +++ b/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java @@ -108,6 +108,7 @@ class JaceArchitectOfThoughtEffect3 extends OneShotEffect { controller.moveCards(card, Zone.EXILED, source, game); player.shuffleLibrary(source, game); } + game.processAction(); cards.retainZone(Zone.EXILED, game); CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, StaticFilters.FILTER_CARD); return true; diff --git a/Mage.Sets/src/mage/cards/j/JaceIngeniousMindMage.java b/Mage.Sets/src/mage/cards/j/JaceIngeniousMindMage.java index 65ac048d787..d3181fdce1c 100644 --- a/Mage.Sets/src/mage/cards/j/JaceIngeniousMindMage.java +++ b/Mage.Sets/src/mage/cards/j/JaceIngeniousMindMage.java @@ -1,7 +1,5 @@ - package mage.cards.j; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -10,14 +8,15 @@ import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.SuperType; import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class JaceIngeniousMindMage extends CardImpl { @@ -38,7 +37,7 @@ public final class JaceIngeniousMindMage extends CardImpl { // -9: Gain control of up to three target creatures. Ability ability = new LoyaltyAbility(new GainControlTargetEffect(Duration.Custom), -9); - ability.addTarget(new TargetCreaturePermanent(0, 3, StaticFilters.FILTER_PERMANENT_CREATURES, false)); + ability.addTarget(new TargetCreaturePermanent(0, 3)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/j/JaceMirrorMage.java b/Mage.Sets/src/mage/cards/j/JaceMirrorMage.java index cfb398ddb63..f221f75e324 100644 --- a/Mage.Sets/src/mage/cards/j/JaceMirrorMage.java +++ b/Mage.Sets/src/mage/cards/j/JaceMirrorMage.java @@ -4,7 +4,6 @@ import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.abilities.effects.keyword.ScryEffect; @@ -41,11 +40,7 @@ public final class JaceMirrorMage extends CardImpl { this.addAbility(new KickerAbility("{2}")); // When Jace, Mirror Mage enters the battlefield, if Jace was kicked, create a token that's a copy of Jace, Mirror Mage except it's not legendary and its starting loyalty is 1. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new JaceMirrorMageCopyEffect()), - KickedCondition.ONCE, "When {this} enters, if {this} was kicked, " + - "create a token that's a copy of {this}, except it's not legendary and its starting loyalty is 1." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new JaceMirrorMageCopyEffect()).withInterveningIf(KickedCondition.ONCE)); // +1: Scry 2. this.addAbility(new LoyaltyAbility(new ScryEffect(2), 1)); @@ -68,6 +63,7 @@ class JaceMirrorMageCopyEffect extends OneShotEffect { JaceMirrorMageCopyEffect() { super(Outcome.Benefit); + staticText = "create a token that's a copy of {this}, except it's not legendary and its starting loyalty is 1."; } private JaceMirrorMageCopyEffect(final JaceMirrorMageCopyEffect effect) { diff --git a/Mage.Sets/src/mage/cards/j/JackdawSavior.java b/Mage.Sets/src/mage/cards/j/JackdawSavior.java index f5db76b14ee..dfddc7a096e 100644 --- a/Mage.Sets/src/mage/cards/j/JackdawSavior.java +++ b/Mage.Sets/src/mage/cards/j/JackdawSavior.java @@ -1,25 +1,25 @@ package mage.cards.j; import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; import mage.abilities.common.DiesThisOrAnotherTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ComparisonType; import mage.constants.SubType; import mage.filter.FilterCard; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.Predicates; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.filter.predicate.mageobject.MageObjectReferencePredicate; -import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; import java.util.UUID; @@ -27,6 +27,14 @@ import java.util.UUID; * @author notgreat */ public final class JackdawSavior extends CardImpl { + private static final FilterControlledCreaturePermanent flyingFilter = new FilterControlledCreaturePermanent("creature you control with flying"); + private static final FilterCard filterCard = new FilterCreatureCard("another target creature card with lesser mana value from your graveyard"); + + static { + flyingFilter.add(new AbilityPredicate(FlyingAbility.class)); + filterCard.add(JackdawSaviorPredicate.instance); + } + public JackdawSavior(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); @@ -39,7 +47,9 @@ public final class JackdawSavior extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever Jackdaw Savior or another creature you control with flying dies, return another target creature card with lesser mana value from your graveyard to the battlefield. - this.addAbility(new JackdawSaviorDiesThisOrAnotherTriggeredAbility()); + Ability ability = new DiesThisOrAnotherTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), false, flyingFilter); + ability.addTarget(new TargetCardInYourGraveyard(filterCard)); + this.addAbility(ability); } private JackdawSavior(final JackdawSavior card) { @@ -52,40 +62,14 @@ public final class JackdawSavior extends CardImpl { } } -class JackdawSaviorDiesThisOrAnotherTriggeredAbility extends DiesThisOrAnotherTriggeredAbility { - private static final FilterControlledCreaturePermanent flyingFilter = new FilterControlledCreaturePermanent("creature you control with flying"); - - static { - flyingFilter.add(new AbilityPredicate(FlyingAbility.class)); - } - - public JackdawSaviorDiesThisOrAnotherTriggeredAbility() { - super(new ReturnFromGraveyardToBattlefieldTargetEffect().setText( - "return another target creature card with lesser mana value from your graveyard to the battlefield"), - false, flyingFilter); - } - - protected JackdawSaviorDiesThisOrAnotherTriggeredAbility(final JackdawSaviorDiesThisOrAnotherTriggeredAbility ability) { - super(ability); - } +enum JackdawSaviorPredicate implements ObjectSourcePlayerPredicate { + instance; @Override - public JackdawSaviorDiesThisOrAnotherTriggeredAbility copy() { - return new JackdawSaviorDiesThisOrAnotherTriggeredAbility(this); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (super.checkTrigger(event, game)) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - FilterCard filter = new FilterCreatureCard(); - filter.add(Predicates.not(new MageObjectReferencePredicate(zEvent.getTargetId(), game))); - filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, zEvent.getTarget().getManaValue())); - filter.setMessage("target creature card other than "+zEvent.getTarget().getLogName()+" with mana value less than "+zEvent.getTarget().getManaValue()); - this.getTargets().clear(); - this.addTarget(new TargetCardInYourGraveyard(filter)); - return true; - } - return false; + public boolean apply(ObjectSourcePlayer input, Game game) { + Permanent diedCreature = CardUtil.getEffectValueFromAbility(input.getSource(), "creatureDied", Permanent.class).orElse(null); + return diedCreature != null + && !input.getObject().getId().equals(diedCreature.getId()) + && input.getObject().getManaValue() < diedCreature.getManaValue(); } } diff --git a/Mage.Sets/src/mage/cards/j/JaddiLifestrider.java b/Mage.Sets/src/mage/cards/j/JaddiLifestrider.java index 128d48d778b..7d95d82d972 100644 --- a/Mage.Sets/src/mage/cards/j/JaddiLifestrider.java +++ b/Mage.Sets/src/mage/cards/j/JaddiLifestrider.java @@ -15,7 +15,7 @@ import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -67,7 +67,7 @@ class JaddiLifestriderEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { int tappedAmount = 0; Player you = game.getPlayer(source.getControllerId()); - TargetCreaturePermanent target = new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, true); + TargetPermanent target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); if (target.canChoose(source.getControllerId(), source, game) && target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), source, game)) { for (UUID creatureId : target.getTargets()) { Permanent creature = game.getPermanent(creatureId); diff --git a/Mage.Sets/src/mage/cards/j/JadeStatue.java b/Mage.Sets/src/mage/cards/j/JadeStatue.java index e46a4729cc0..d735909a470 100644 --- a/Mage.Sets/src/mage/cards/j/JadeStatue.java +++ b/Mage.Sets/src/mage/cards/j/JadeStatue.java @@ -1,33 +1,35 @@ - package mage.cards.j; -import java.util.UUID; -import mage.MageInt; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.IsPhaseCondition; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.TurnPhase; -import mage.constants.Zone; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; + +import java.util.UUID; /** - * * @author anonymous */ public final class JadeStatue extends CardImpl { + private static final Condition condition = new IsPhaseCondition(TurnPhase.COMBAT); + public JadeStatue(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); - // {2}: Jade Statue becomes a 3/6 Golem artifact creature until end of combat. Activate this ability only during combat. - this.addAbility(new ConditionalActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect (new JadeStatueToken(), CardType.ARTIFACT, Duration.EndOfCombat), new ManaCostsImpl<>("{2}"), new IsPhaseCondition(TurnPhase.COMBAT), "{2}: {this} becomes a 3/6 Golem artifact creature until end of combat. Activate only during combat.")); + this.addAbility(new ActivateIfConditionActivatedAbility(new BecomesCreatureSourceEffect( + new CreatureToken(3, 6, "3/6 Golem artifact creature", SubType.GOLEM) + .withType(CardType.ARTIFACT), CardType.ARTIFACT, Duration.EndOfCombat + ), new GenericManaCost(2), condition)); } private JadeStatue(final JadeStatue card) { @@ -38,22 +40,4 @@ public final class JadeStatue extends CardImpl { public JadeStatue copy() { return new JadeStatue(this); } - - private static class JadeStatueToken extends TokenImpl { - JadeStatueToken() { - super("", "3/6 Golem artifact creature"); - cardType.add(CardType.ARTIFACT); - cardType.add(CardType.CREATURE); - this.subtype.add(SubType.GOLEM); - power = new MageInt(3); - toughness = new MageInt(6); - } - private JadeStatueToken(final JadeStatueToken token) { - super(token); - } - - public JadeStatueToken copy() { - return new JadeStatueToken(this); - } - } } diff --git a/Mage.Sets/src/mage/cards/j/JadedSellSword.java b/Mage.Sets/src/mage/cards/j/JadedSellSword.java index 1baeb5240f7..29cf15c604d 100644 --- a/Mage.Sets/src/mage/cards/j/JadedSellSword.java +++ b/Mage.Sets/src/mage/cards/j/JadedSellSword.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.TreasureSpentToCastCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.HasteAbility; @@ -13,7 +12,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.watchers.common.ManaPaidSourceWatcher; import java.util.UUID; @@ -31,15 +29,12 @@ public final class JadedSellSword extends CardImpl { this.toughness = new MageInt(3); // When Jaded Sell-Sword enters the battlefield, if mana from a Treasure was spent to cast it, it gains first strike and haste until end of turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new GainAbilitySourceEffect( - FirstStrikeAbility.getInstance(), Duration.EndOfTurn - )), TreasureSpentToCastCondition.instance, "When {this} enters, " + - "if mana from a Treasure was spent to cast it, it gains first strike and haste until end of turn." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new GainAbilitySourceEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn + ).setText("it gains first strike")).withInterveningIf(TreasureSpentToCastCondition.instance); ability.addEffect(new GainAbilitySourceEffect( HasteAbility.getInstance(), Duration.EndOfTurn - )); + ).setText("and haste until end of turn")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/j/JaggedLightning.java b/Mage.Sets/src/mage/cards/j/JaggedLightning.java index 490a278ec21..0da793f9011 100644 --- a/Mage.Sets/src/mage/cards/j/JaggedLightning.java +++ b/Mage.Sets/src/mage/cards/j/JaggedLightning.java @@ -1,16 +1,14 @@ - package mage.cards.j; -import java.util.UUID; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LoneFox */ public final class JaggedLightning extends CardImpl { @@ -20,7 +18,7 @@ public final class JaggedLightning extends CardImpl { // Jagged Lightning deals 3 damage to each of two target creatures. this.getSpellAbility().addEffect(new DamageTargetEffect(3, true, "each of two target creatures")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(2, 2, StaticFilters.FILTER_PERMANENT_CREATURE, false)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(2)); } private JaggedLightning(final JaggedLightning card) { diff --git a/Mage.Sets/src/mage/cards/j/JaggedPoppet.java b/Mage.Sets/src/mage/cards/j/JaggedPoppet.java index ce1ca657e24..e01eeb0da47 100644 --- a/Mage.Sets/src/mage/cards/j/JaggedPoppet.java +++ b/Mage.Sets/src/mage/cards/j/JaggedPoppet.java @@ -1,12 +1,9 @@ package mage.cards.j; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.DealtDamageToSourceTriggeredAbility; import mage.abilities.condition.common.HellbentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.discard.DiscardControllerEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; @@ -16,8 +13,9 @@ import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** - * * @author jerekwilson */ public final class JaggedPoppet extends CardImpl { @@ -31,15 +29,16 @@ public final class JaggedPoppet extends CardImpl { this.toughness = new MageInt(4); // Whenever Jagged Poppet is dealt damage, discard that many cards. - this.addAbility(new DealtDamageToSourceTriggeredAbility(new DiscardControllerEffect(SavedDamageValue.MANY), false)); + this.addAbility(new DealtDamageToSourceTriggeredAbility( + new DiscardControllerEffect(SavedDamageValue.MANY), false + )); // Hellbent - Whenever Jagged Poppet deals combat damage to a player, if you have no cards in hand, that player discards cards equal to the damage. - Ability hellbentAbility = new ConditionalInterveningIfTriggeredAbility( - new DealsCombatDamageToAPlayerTriggeredAbility(new DiscardTargetEffect(SavedDamageValue.MANY), false, true), - HellbentCondition.instance, - "Whenever {this} deals combat damage to a player, if you have no cards in hand, that player discards cards equal to the damage."); - hellbentAbility.setAbilityWord(AbilityWord.HELLBENT); - this.addAbility(hellbentAbility); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new DiscardTargetEffect(SavedDamageValue.MANY) + .setText("that player discards cards equal to the damage"), + false, true + ).withInterveningIf(HellbentCondition.instance).setAbilityWord(AbilityWord.HELLBENT)); } private JaggedPoppet(final JaggedPoppet card) { diff --git a/Mage.Sets/src/mage/cards/j/JaggedScarArchers.java b/Mage.Sets/src/mage/cards/j/JaggedScarArchers.java index f7f1b8944a1..28d11bf11bf 100644 --- a/Mage.Sets/src/mage/cards/j/JaggedScarArchers.java +++ b/Mage.Sets/src/mage/cards/j/JaggedScarArchers.java @@ -18,6 +18,7 @@ import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -47,7 +48,7 @@ public final class JaggedScarArchers extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(new PermanentsOnBattlefieldCount(controlledElvesFilter)))); // {tap}: Jagged-Scar Archers deals damage equal to its power to target creature with flying. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(SourcePermanentPowerValue.NOT_NEGATIVE).setText("{this} deals damage equal to its power to target creature with flying"), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(flyingCreatureFilter)); + ability.addTarget(new TargetPermanent(flyingCreatureFilter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/j/JandorsRing.java b/Mage.Sets/src/mage/cards/j/JandorsRing.java index de04870fd54..a14b0737ec6 100644 --- a/Mage.Sets/src/mage/cards/j/JandorsRing.java +++ b/Mage.Sets/src/mage/cards/j/JandorsRing.java @@ -1,44 +1,46 @@ - package mage.cards.j; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.condition.Condition; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardTargetCost; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.discard.DiscardCardYouChooseTargetEffect; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.WatcherScope; -import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.CardIdPredicate; +import mage.filter.predicate.Predicate; import mage.game.Game; import mage.game.events.GameEvent; -import mage.players.Player; +import mage.target.common.TargetCardInHand; import mage.watchers.Watcher; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** * @author MarcoMarin */ public final class JandorsRing extends CardImpl { + private static final FilterCard filter = new FilterCard("the last card you drew this turn"); + + static { + filter.add(JandorsRingPredicate.instance); + } + public JandorsRing(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}"); - Watcher watcher = new JandorsRingWatcher(); // {2}, {tap}, Discard the last card you drew this turn: Draw a card. - // TODO: discard has to be a cost not a payment during resolution - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new JandorsRingEffect(), new ManaCostsImpl<>("{2}"), WatchedCardInHandCondition.instance, "{2}, {T}, Discard the last card you drew this turn: Draw a card."); + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(2)); ability.addCost(new TapSourceCost()); - this.addAbility(ability, watcher); + ability.addCost(new DiscardTargetCost(new TargetCardInHand(filter)).setText("discard the last card you drew this turn")); + this.addAbility(ability, new JandorsRingWatcher()); } private JandorsRing(final JandorsRing card) { @@ -51,86 +53,42 @@ public final class JandorsRing extends CardImpl { } } -class JandorsRingEffect extends OneShotEffect { - - JandorsRingEffect() { - super(Outcome.Discard); - staticText = "Draw a card"; - } - - private JandorsRingEffect(final JandorsRingEffect effect) { - super(effect); - } +enum JandorsRingPredicate implements Predicate { + instance; @Override - public JandorsRingEffect copy() { - return new JandorsRingEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - JandorsRingWatcher watcher = game.getState().getWatcher(JandorsRingWatcher.class); - if (watcher != null) { - UUID cardId = watcher.getLastDrewCard(source.getControllerId()); - Card card = game.getCard(cardId); - if (card != null) { - FilterCard filter = new FilterCard(card.getName()); - filter.add(new CardIdPredicate(card.getId())); - DiscardCardYouChooseTargetEffect effect = new DiscardCardYouChooseTargetEffect(filter); - if (effect.apply(game, source)) {//Conditional was already checked, card should be in hand, but if for some weird reason it fails, the card won't be drawn, although the cost will already be paid - Player controller = game.getPlayer(source.getControllerId()); - if(controller != null) { - controller.drawCards(1, source, game); - } - } - } - return true; - } - return false; + public boolean apply(Card input, Game game) { + return JandorsRingWatcher.checkCard(input, game); } } class JandorsRingWatcher extends Watcher { - private Map lastDrawnCards = new HashMap<>(); + private final Set set = new HashSet<>(); - public JandorsRingWatcher() { + JandorsRingWatcher() { super(WatcherScope.GAME); } @Override public void watch(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.DREW_CARD) { - lastDrawnCards.putIfAbsent(event.getPlayerId(), event.getTargetId()); + set.add(event.getTargetId()); } } @Override public void reset() { super.reset(); - lastDrawnCards.clear(); + set.clear(); } - public UUID getLastDrewCard(UUID playerId) { - return lastDrawnCards.get(playerId); + static boolean checkCard(Card card, Game game) { + return card != null + && game + .getState() + .getWatcher(JandorsRingWatcher.class) + .set + .contains(card.getId()); } } - -enum WatchedCardInHandCondition implements Condition { - - instance; - - @Override - public boolean apply(Game game, Ability source) { - JandorsRingWatcher watcher = game.getState().getWatcher(JandorsRingWatcher.class); - - return watcher != null - && game.getPlayer(source.getControllerId()).getHand().contains(watcher.getLastDrewCard(source.getControllerId())); - } - - @Override - public String toString() { - return "if last drawn card is still in hand"; - } - -} diff --git a/Mage.Sets/src/mage/cards/j/JasperaSentinel.java b/Mage.Sets/src/mage/cards/j/JasperaSentinel.java index 3e6f97cf6e3..4c206e94aef 100644 --- a/Mage.Sets/src/mage/cards/j/JasperaSentinel.java +++ b/Mage.Sets/src/mage/cards/j/JasperaSentinel.java @@ -1,32 +1,23 @@ package mage.cards.j; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.costs.common.TapTargetCost; -import mage.abilities.mana.AnyColorManaAbility; -import mage.constants.SubType; import mage.abilities.keyword.ReachAbility; +import mage.abilities.mana.AnyColorManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author weirddan455 */ public final class JasperaSentinel extends CardImpl { - private static final FilterControlledCreaturePermanent filter - = new FilterControlledCreaturePermanent("an untapped creature you control"); - - static { - filter.add(TappedPredicate.UNTAPPED); - } - public JasperaSentinel(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); @@ -40,7 +31,7 @@ public final class JasperaSentinel extends CardImpl { // {T}, Tap an untapped creature you control: Add one mana of any color. Ability ability = new AnyColorManaAbility(); - ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(filter))); + ability.addCost(new TapTargetCost(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/j/JawboneSkulkin.java b/Mage.Sets/src/mage/cards/j/JawboneSkulkin.java index ae1c7205381..395983aea33 100644 --- a/Mage.Sets/src/mage/cards/j/JawboneSkulkin.java +++ b/Mage.Sets/src/mage/cards/j/JawboneSkulkin.java @@ -17,6 +17,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -36,7 +37,7 @@ public final class JawboneSkulkin extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn), new GenericManaCost(2)); - ability.addTarget(new TargetCreaturePermanent(filterRedCreature)); + ability.addTarget(new TargetPermanent(filterRedCreature)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/j/JediInstructor.java b/Mage.Sets/src/mage/cards/j/JediInstructor.java index 6b14794a12f..f5da94d0668 100644 --- a/Mage.Sets/src/mage/cards/j/JediInstructor.java +++ b/Mage.Sets/src/mage/cards/j/JediInstructor.java @@ -13,8 +13,11 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * * @author Styxo @@ -30,7 +33,7 @@ public final class JediInstructor extends CardImpl { // When Jedi Instructor enters the battlefield, you may put a +1/+1 counter on another target creature. EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), true); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); // Meditate {1}{W} diff --git a/Mage.Sets/src/mage/cards/j/JediSentinel.java b/Mage.Sets/src/mage/cards/j/JediSentinel.java index fdf53233d97..7b824dd5e5f 100644 --- a/Mage.Sets/src/mage/cards/j/JediSentinel.java +++ b/Mage.Sets/src/mage/cards/j/JediSentinel.java @@ -11,12 +11,14 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.EachTargetPointer; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author Styxo */ @@ -35,8 +37,8 @@ public final class JediSentinel extends CardImpl { // When Jedi Sentinel enters the battlefield, return another target creature you control and target creature you don't control to their owners' hands. Effect effect = new ReturnToHandTargetEffect().setTargetPointer(new EachTargetPointer()); Ability ability = new EntersBattlefieldTriggeredAbility(effect); - ability.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/j/JediStarfighter.java b/Mage.Sets/src/mage/cards/j/JediStarfighter.java index 4d2935cbafb..906fb5824ef 100644 --- a/Mage.Sets/src/mage/cards/j/JediStarfighter.java +++ b/Mage.Sets/src/mage/cards/j/JediStarfighter.java @@ -1,7 +1,6 @@ package mage.cards.j; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -15,10 +14,11 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author Styxo */ public final class JediStarfighter extends CardImpl { @@ -27,11 +27,11 @@ public final class JediStarfighter extends CardImpl { static { filter.add(SubType.JEDI.getPredicate()); - filter.add(TargetController.YOU.getControllerPredicate()); + filter.add(TargetController.YOU.getControllerPredicate()); } public JediStarfighter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{2}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{W}{W}"); this.subtype.add(SubType.JEDI); this.subtype.add(SubType.STARSHIP); this.power = new MageInt(2); @@ -42,7 +42,7 @@ public final class JediStarfighter extends CardImpl { // When Jedi Starfighter enters the battlefield, up to two Jedi creatures you control gain spaceflight until end of turn. EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new GainAbilityTargetEffect(SpaceflightAbility.getInstance(), Duration.EndOfTurn)); - ability.addTarget(new TargetCreaturePermanent(0, 2, filter, true)); + ability.addTarget(new TargetPermanent(0, 2, filter, true)); this.addAbility(ability); // Meditate {1}{W} diff --git a/Mage.Sets/src/mage/cards/j/JeeringInstigator.java b/Mage.Sets/src/mage/cards/j/JeeringInstigator.java index 61beb4fa0ec..08b77a67d25 100644 --- a/Mage.Sets/src/mage/cards/j/JeeringInstigator.java +++ b/Mage.Sets/src/mage/cards/j/JeeringInstigator.java @@ -3,10 +3,10 @@ package mage.cards.j; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.TurnedFaceUpSourceTriggeredAbility; -import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.condition.Condition; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.NotMyTurnCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; @@ -18,9 +18,8 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import java.util.UUID; @@ -29,11 +28,7 @@ import java.util.UUID; */ public final class JeeringInstigator extends CardImpl { - static final private FilterCreaturePermanent filter = new FilterCreaturePermanent(); - - static { - filter.add(AnotherPredicate.instance); - } + private static final Condition condition = new InvertCondition(NotMyTurnCondition.instance, "it's your turn"); public JeeringInstigator(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); @@ -47,20 +42,16 @@ public final class JeeringInstigator extends CardImpl { this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{2}{R}"))); // When Jeering Instigator is turned face up, if it's your turn, gain control of another target creature until end of turn. Untap it. That creature gains haste until end of turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new TurnedFaceUpSourceTriggeredAbility(new GainControlTargetEffect(Duration.EndOfTurn), false, false), - MyTurnCondition.instance, - "When {this} is turned face up, if it's your turn, gain control of another target creature until end of turn. Untap that creature. It gains haste until end of turn."); + Ability ability = new TurnedFaceUpSourceTriggeredAbility( + new GainControlTargetEffect(Duration.EndOfTurn), false, false + ).withInterveningIf(condition); + ability.addEffect(new UntapTargetEffect().setText("Untap that creature")); + ability.addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("It gains haste until end of turn")); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); ability.setWorksFaceDown(true); - Effect effect = new UntapTargetEffect(); - effect.setText("Untap that creature"); - ability.addEffect(effect); - effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); - effect.setText("It gains haste until end of turn"); - ability.addEffect(effect); - ability.addTarget(new TargetCreaturePermanent(filter)); - ability.addHint(MyTurnHint.instance); - this.addAbility(ability); + this.addAbility(ability.addHint(MyTurnHint.instance)); } private JeeringInstigator(final JeeringInstigator card) { diff --git a/Mage.Sets/src/mage/cards/j/JennyFlint.java b/Mage.Sets/src/mage/cards/j/JennyFlint.java index 5a026b5706f..ded14374a75 100644 --- a/Mage.Sets/src/mage/cards/j/JennyFlint.java +++ b/Mage.Sets/src/mage/cards/j/JennyFlint.java @@ -1,7 +1,7 @@ package mage.cards.j; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.SacrificePermanentTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.FirstStrikeAbility; @@ -16,7 +16,7 @@ import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.predicate.Predicates; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -53,12 +53,11 @@ public final class JennyFlint extends CardImpl { this.addAbility(new TrainingAbility()); // Whenever you sacrifice a Clue or Food, put a +1/+1 counter on another target creature you control. - TriggeredAbility trigger = new SacrificePermanentTriggeredAbility( - new AddCountersTargetEffect(CounterType.P1P1.createInstance()), - filter + Ability ability = new SacrificePermanentTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), filter ); - trigger.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); - this.addAbility(trigger); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + this.addAbility(ability); } private JennyFlint(final JennyFlint card) { diff --git a/Mage.Sets/src/mage/cards/j/JeskaiBarricade.java b/Mage.Sets/src/mage/cards/j/JeskaiBarricade.java index 4df70be8bff..7987818b455 100644 --- a/Mage.Sets/src/mage/cards/j/JeskaiBarricade.java +++ b/Mage.Sets/src/mage/cards/j/JeskaiBarricade.java @@ -1,4 +1,3 @@ - package mage.cards.j; import mage.MageInt; @@ -12,31 +11,30 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; /** - * * @author fireshoes */ public final class JeskaiBarricade extends CardImpl { public JeskaiBarricade(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.subtype.add(SubType.WALL); this.power = new MageInt(0); this.toughness = new MageInt(4); // Flash this.addAbility(FlashAbility.getInstance()); + // Defender this.addAbility(DefenderAbility.getInstance()); + // When Jeskai Barricade enters the battlefield, you may return another target creature you control to its owner's hand. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); - Target target = new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL); - ability.addTarget(target); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/j/JeweledAmulet.java b/Mage.Sets/src/mage/cards/j/JeweledAmulet.java index 995ff03bb1a..aa31f2d3f18 100644 --- a/Mage.Sets/src/mage/cards/j/JeweledAmulet.java +++ b/Mage.Sets/src/mage/cards/j/JeweledAmulet.java @@ -2,12 +2,12 @@ package mage.cards.j; import mage.Mana; import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.costs.common.RemoveCountersSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.mana.ManaEffect; @@ -37,7 +37,7 @@ public final class JeweledAmulet extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{0}"); // {1}, {tap}: Put a charge counter on Jeweled Amulet. Note the type of mana spent to pay this activation cost. Activate this ability only if there are no charge counters on Jeweled Amulet. - ConditionalActivatedAbility ability = new ConditionalActivatedAbility( + Ability ability = new ActivateIfConditionActivatedAbility( new AddCountersSourceEffect(CounterType.CHARGE.createInstance(), true), new GenericManaCost(1), condition ); ability.addEffect(new JeweledAmuletAddCounterEffect()); diff --git a/Mage.Sets/src/mage/cards/j/JhoirasToolbox.java b/Mage.Sets/src/mage/cards/j/JhoirasToolbox.java index e1609e6f9c9..d089bd97b86 100644 --- a/Mage.Sets/src/mage/cards/j/JhoirasToolbox.java +++ b/Mage.Sets/src/mage/cards/j/JhoirasToolbox.java @@ -13,6 +13,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -36,7 +37,7 @@ public final class JhoirasToolbox extends CardImpl { // {2}: Regenerate target artifact creature. Ability ability = new SimpleActivatedAbility(new RegenerateTargetEffect(), new ManaCostsImpl<>("{2}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/j/Jilt.java b/Mage.Sets/src/mage/cards/j/Jilt.java index 9051022f8ec..588eb9c2133 100644 --- a/Mage.Sets/src/mage/cards/j/Jilt.java +++ b/Mage.Sets/src/mage/cards/j/Jilt.java @@ -10,6 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.other.AnotherTargetPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.ConditionalTargetAdjuster; import mage.target.targetpointer.SecondTargetPointer; @@ -41,7 +42,7 @@ public final class Jilt extends CardImpl { .setTargetPointer(new SecondTargetPointer())); this.getSpellAbility().addTarget(new TargetCreaturePermanent().setTargetTag(1).withChooseHint("to return to hand")); this.getSpellAbility().setTargetAdjuster(new ConditionalTargetAdjuster(KickedCondition.ONCE, true, - new TargetCreaturePermanent(filter).setTargetTag(2).withChooseHint("to deal 2 damage"))); + new TargetPermanent(filter).setTargetTag(2).withChooseHint("to deal 2 damage"))); } private Jilt(final Jilt card) { diff --git a/Mage.Sets/src/mage/cards/j/JinGitaxias.java b/Mage.Sets/src/mage/cards/j/JinGitaxias.java index 4faee7085dc..6fd9909cef0 100644 --- a/Mage.Sets/src/mage/cards/j/JinGitaxias.java +++ b/Mage.Sets/src/mage/cards/j/JinGitaxias.java @@ -4,7 +4,7 @@ import mage.MageInt; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.common.CardsInHandCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; import mage.abilities.keyword.TransformAbility; @@ -48,7 +48,7 @@ public class JinGitaxias extends CardImpl { //{3}{U}: Exile Jin-Gitaxias, then return it to the battlefield transformed under its owner’s control. Activate //only as a sorcery and only if you have seven or more cards in hand. this.addAbility(new TransformAbility()); - this.addAbility(new ConditionalActivatedAbility( + this.addAbility(new ActivateIfConditionActivatedAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED), new ManaCostsImpl<>("{3}{U}"), new CardsInHandCondition(ComparisonType.MORE_THAN, 6) diff --git a/Mage.Sets/src/mage/cards/j/JiwariTheEarthAflame.java b/Mage.Sets/src/mage/cards/j/JiwariTheEarthAflame.java index 40e1d750240..3bf6a41ed56 100644 --- a/Mage.Sets/src/mage/cards/j/JiwariTheEarthAflame.java +++ b/Mage.Sets/src/mage/cards/j/JiwariTheEarthAflame.java @@ -21,6 +21,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -46,7 +47,7 @@ public final class JiwariTheEarthAflame extends CardImpl { // {X}{R}, {tap}: Jiwari, the Earth Aflame deals X damage to target creature without flying. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(GetXValue.instance), new ManaCostsImpl<>("{X}{R}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Channel - {X}{R}{R}{R}, Discard Jiwari: Jiwari deals X damage to each creature without flying. diff --git a/Mage.Sets/src/mage/cards/j/JoragaAuxiliary.java b/Mage.Sets/src/mage/cards/j/JoragaAuxiliary.java index e207271ca52..c2d5bbbce5b 100644 --- a/Mage.Sets/src/mage/cards/j/JoragaAuxiliary.java +++ b/Mage.Sets/src/mage/cards/j/JoragaAuxiliary.java @@ -1,7 +1,5 @@ - package mage.cards.j; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -11,13 +9,13 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author fireshoes */ public final class JoragaAuxiliary extends CardImpl { @@ -29,7 +27,7 @@ public final class JoragaAuxiliary extends CardImpl { } public JoragaAuxiliary(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{W}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.SOLDIER); this.subtype.add(SubType.ALLY); @@ -38,7 +36,7 @@ public final class JoragaAuxiliary extends CardImpl { // {4}{G}{W}: Support 2. (Put a +1/+1 counter on each of up to two other target creatures.) Ability ability = new SimpleActivatedAbility(new SupportEffect(this, 2, true), new ManaCostsImpl<>("{4}{G}{W}")); - ability.addTarget(new TargetCreaturePermanent(0, 2, filter, false)); + ability.addTarget(new TargetPermanent(0, 2, filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/j/JoragaWarcaller.java b/Mage.Sets/src/mage/cards/j/JoragaWarcaller.java index e7bc1f28bd7..d8460c3e19e 100644 --- a/Mage.Sets/src/mage/cards/j/JoragaWarcaller.java +++ b/Mage.Sets/src/mage/cards/j/JoragaWarcaller.java @@ -1,7 +1,6 @@ package mage.cards.j; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; @@ -12,21 +11,25 @@ import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.MultikickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.TargetController; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class JoragaWarcaller extends CardImpl { - - private static final String rule = "Other Elf creatures you control get +1/+1 for each +1/+1 counter on Joraga Warcaller"; - + + private static final String rule = "Other Elf creatures you control get +1/+1 for each +1/+1 counter on {this}"; + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("elf creatures you control"); - + static { filter.add(TargetController.YOU.getControllerPredicate()); filter.add(SubType.ELF.getPredicate()); diff --git a/Mage.Sets/src/mage/cards/j/JosuVessLichKnight.java b/Mage.Sets/src/mage/cards/j/JosuVessLichKnight.java index c5397acc96a..016e8be553d 100644 --- a/Mage.Sets/src/mage/cards/j/JosuVessLichKnight.java +++ b/Mage.Sets/src/mage/cards/j/JosuVessLichKnight.java @@ -3,7 +3,6 @@ package mage.cards.j; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.KickerAbility; import mage.abilities.keyword.MenaceAbility; @@ -18,7 +17,7 @@ import java.util.UUID; public final class JosuVessLichKnight extends CardImpl { - public JosuVessLichKnight(UUID ownerID, CardSetInfo cardSetInfo){ + public JosuVessLichKnight(UUID ownerID, CardSetInfo cardSetInfo) { super(ownerID, cardSetInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.ZOMBIE, SubType.KNIGHT); @@ -32,12 +31,12 @@ public final class JosuVessLichKnight extends CardImpl { this.addAbility(new MenaceAbility(false)); //When Josu Vess, Lich Knight enters the battlefield, if it was kicked, create eight 2/2 black Zombie Knight creature tokens with menace. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ZombieKnightToken(), 8)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.ONCE, - "When {this} enters, if it was kicked, create eight 2/2 black Zombie Knight creature tokens with menace.")); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new CreateTokenEffect(new ZombieKnightToken(), 8) + ).withInterveningIf(KickedCondition.ONCE)); } - private JosuVessLichKnight(final JosuVessLichKnight card){ + private JosuVessLichKnight(final JosuVessLichKnight card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/j/JubilantMascot.java b/Mage.Sets/src/mage/cards/j/JubilantMascot.java index cceafa71a50..12dd6115469 100644 --- a/Mage.Sets/src/mage/cards/j/JubilantMascot.java +++ b/Mage.Sets/src/mage/cards/j/JubilantMascot.java @@ -1,24 +1,23 @@ package mage.cards.j; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.constants.SubType; +import mage.abilities.effects.keyword.SupportEffect; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.counters.CounterType; +import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class JubilantMascot extends CardImpl { @@ -39,11 +38,10 @@ public final class JubilantMascot extends CardImpl { // At the beginning of combat on your turn, you may pay {3}{W}. If you do, support 2. (Put a +1/+1 counter on each of up to two other target creatures.) Ability ability = new BeginningOfCombatTriggeredAbility( new DoIfCostPaid( - new AddCountersTargetEffect(CounterType.P1P1.createInstance()) - .setText("support 2"), + new SupportEffect(this, 2, true), new ManaCostsImpl<>("{3}{W}") )); - ability.addTarget(new TargetCreaturePermanent(0, 2, filter, false)); + ability.addTarget(new TargetPermanent(0, 2, filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/j/JuniperOrderRootweaver.java b/Mage.Sets/src/mage/cards/j/JuniperOrderRootweaver.java index 0e22e065f99..3c3beccdc97 100644 --- a/Mage.Sets/src/mage/cards/j/JuniperOrderRootweaver.java +++ b/Mage.Sets/src/mage/cards/j/JuniperOrderRootweaver.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; @@ -33,11 +32,9 @@ public final class JuniperOrderRootweaver extends CardImpl { this.addAbility(new KickerAbility("{G}")); // When Juniper Order Rootweaver enters the battlefield, if it was kicked, put a +1/+1 counter on target creature you control. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility( - new AddCountersTargetEffect(CounterType.P1P1.createInstance()) - ), KickedCondition.ONCE, "When {this} enters, " + - "if it was kicked, put a +1/+1 counter on target creature you control."); + Ability ability = new EntersBattlefieldTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()) + ).withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KalamaxTheStormsire.java b/Mage.Sets/src/mage/cards/k/KalamaxTheStormsire.java index 6cffb041ca4..e64a01d24f1 100644 --- a/Mage.Sets/src/mage/cards/k/KalamaxTheStormsire.java +++ b/Mage.Sets/src/mage/cards/k/KalamaxTheStormsire.java @@ -103,7 +103,7 @@ class KalamaxTheStormsireSpellCastAbility extends SpellCastControllerTriggeredAb @Override public String getRule() { return "Whenever you cast your first instant spell each turn, " + - "if Kalamax, the Stormsire is tapped, " + + "if {this} is tapped, " + "copy that spell. You may choose new targets for the copy."; } } diff --git a/Mage.Sets/src/mage/cards/k/KamiOfCelebration.java b/Mage.Sets/src/mage/cards/k/KamiOfCelebration.java index 3ae960bcfd2..5c36864c75d 100644 --- a/Mage.Sets/src/mage/cards/k/KamiOfCelebration.java +++ b/Mage.Sets/src/mage/cards/k/KamiOfCelebration.java @@ -1,21 +1,17 @@ package mage.cards.k; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.AttacksCreatureYouControlTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.*; import mage.counters.CounterType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.ModifiedPredicate; -import mage.game.Game; -import mage.game.events.GameEvent; import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; @@ -45,7 +41,12 @@ public final class KamiOfCelebration extends CardImpl { )); // Whenever you cast a spell from exile, put a +1/+1 counter on target creature you control. - this.addAbility(new KamiOfCelebrationAbility()); + Ability ability = new SpellCastControllerTriggeredAbility( + Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), null, + false, SetTargetPointer.NONE, Zone.EXILED + ); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); } private KamiOfCelebration(final KamiOfCelebration card) { @@ -57,30 +58,3 @@ public final class KamiOfCelebration extends CardImpl { return new KamiOfCelebration(this); } } - -class KamiOfCelebrationAbility extends SpellCastControllerTriggeredAbility { - - KamiOfCelebrationAbility() { - super(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false); - this.addTarget(new TargetControlledCreaturePermanent()); - } - - private KamiOfCelebrationAbility(final KamiOfCelebrationAbility ability) { - super(ability); - } - - @Override - public KamiOfCelebrationAbility copy() { - return new KamiOfCelebrationAbility(this); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - return event.getZone() == Zone.EXILED && super.checkTrigger(event, game); - } - - @Override - public String getRule() { - return "Whenever you cast a spell from exile, put a +1/+1 counter on target creature you control."; - } -} diff --git a/Mage.Sets/src/mage/cards/k/KangeeAerieKeeper.java b/Mage.Sets/src/mage/cards/k/KangeeAerieKeeper.java index f33970abf0a..2fe9d2e2682 100644 --- a/Mage.Sets/src/mage/cards/k/KangeeAerieKeeper.java +++ b/Mage.Sets/src/mage/cards/k/KangeeAerieKeeper.java @@ -1,11 +1,10 @@ package mage.cards.k; import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CountersSourceCount; import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.effects.common.continuous.BoostAllEffect; @@ -14,7 +13,10 @@ import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; @@ -33,6 +35,8 @@ public final class KangeeAerieKeeper extends CardImpl { filter.add(AnotherPredicate.instance); } + private static final DynamicValue xValue = new CountersSourceCount(CounterType.FEATHER); + public KangeeAerieKeeper(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{U}"); this.supertype.add(SuperType.LEGENDARY); @@ -49,11 +53,15 @@ public final class KangeeAerieKeeper extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Kangee, Aerie Keeper enters the battlefield, if it was kicked, put X feather counters on it. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.FEATHER.createInstance(), GetXValue.instance, true)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.ONCE, "When {this} enters, if it was kicked, put X feather counters on it.")); + this.addAbility(new EntersBattlefieldTriggeredAbility(new AddCountersSourceEffect( + CounterType.FEATHER.createInstance(), GetXValue.instance, true + )).withInterveningIf(KickedCondition.ONCE).withRuleTextReplacement(true)); // Other Bird creatures get +1/+1 for each feather counter on Kangee, Aerie Keeper. - this.addAbility(new SimpleStaticAbility(new BoostAllEffect(new CountersSourceCount(CounterType.FEATHER), new CountersSourceCount(CounterType.FEATHER), Duration.WhileOnBattlefield, filter, true, "Other Bird creatures get +1/+1 for each feather counter on {this}."))); + this.addAbility(new SimpleStaticAbility(new BoostAllEffect( + xValue, xValue, Duration.WhileOnBattlefield, filter, true, + "Other Bird creatures get +1/+1 for each feather counter on {this}." + ))); } private KangeeAerieKeeper(final KangeeAerieKeeper card) { diff --git a/Mage.Sets/src/mage/cards/k/Karakas.java b/Mage.Sets/src/mage/cards/k/Karakas.java index de9281807f1..c122c59fded 100644 --- a/Mage.Sets/src/mage/cards/k/Karakas.java +++ b/Mage.Sets/src/mage/cards/k/Karakas.java @@ -13,6 +13,7 @@ import mage.constants.CardType; import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -34,7 +35,7 @@ public final class Karakas extends CardImpl { this.addAbility(new WhiteManaAbility()); // {T}: Return target legendary creature to its owner's hand. Ability ability = new SimpleActivatedAbility(new ReturnToHandTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KarazikarTheEyeTyrant.java b/Mage.Sets/src/mage/cards/k/KarazikarTheEyeTyrant.java index 368a9b6c0df..87999eba723 100644 --- a/Mage.Sets/src/mage/cards/k/KarazikarTheEyeTyrant.java +++ b/Mage.Sets/src/mage/cards/k/KarazikarTheEyeTyrant.java @@ -1,22 +1,20 @@ package mage.cards.k; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.AttacksPlayerWithCreaturesTriggeredAbility; import mage.abilities.effects.common.*; import mage.abilities.effects.common.combat.GoadTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.events.GameEvent; -import mage.players.Player; import mage.target.TargetPermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; import mage.target.targetpointer.FixedTarget; import java.util.Set; @@ -26,6 +24,7 @@ import java.util.UUID; * @author TheElk801 */ public final class KarazikarTheEyeTyrant extends CardImpl { + FilterPermanent filter = new FilterCreaturePermanent("creature that player controls"); public KarazikarTheEyeTyrant(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{R}"); @@ -36,7 +35,11 @@ public final class KarazikarTheEyeTyrant extends CardImpl { this.toughness = new MageInt(5); // Whenever you attack a player, tap target creature that player controls and goad it. - this.addAbility(new KarazikarTheEyeTyrantFirstTriggeredAbility()); + Ability ability = new AttacksPlayerWithCreaturesTriggeredAbility(new TapTargetEffect(), SetTargetPointer.PLAYER); + ability.addEffect(new GoadTargetEffect().setText("goad it. " + GoadTargetEffect.goadReminderText).concatBy("and")); + ability.addTarget(new TargetPermanent(filter)); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); + this.addAbility(ability); // Whenever an opponent attacks another one of your opponents, you and the attacking player each draw a card and lose 1 life. this.addAbility(new KarazikarTheEyeTyrantSecondTriggeredAbility()); @@ -52,49 +55,6 @@ public final class KarazikarTheEyeTyrant extends CardImpl { } } -class KarazikarTheEyeTyrantFirstTriggeredAbility extends TriggeredAbilityImpl { - - KarazikarTheEyeTyrantFirstTriggeredAbility() { - super(Zone.BATTLEFIELD, new TapTargetEffect(), false); - this.addEffect(new GoadTargetEffect()); - } - - private KarazikarTheEyeTyrantFirstTriggeredAbility(final KarazikarTheEyeTyrantFirstTriggeredAbility ability) { - super(ability); - } - - @Override - public KarazikarTheEyeTyrantFirstTriggeredAbility copy() { - return new KarazikarTheEyeTyrantFirstTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DEFENDER_ATTACKED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (!isControlledBy(event.getPlayerId())) { - return false; - } - Player player = game.getPlayer(event.getTargetId()); - if (player == null) { - return false; - } - FilterPermanent filter = new FilterCreaturePermanent("creature controlled by " + player.getName()); - filter.add(new ControllerIdPredicate(player.getId())); - this.getTargets().clear(); - this.addTarget(new TargetPermanent(filter)); - return true; - } - - @Override - public String getRule() { - return "Whenever you attack a player, tap target creature that player controls and goad it."; - } -} - class KarazikarTheEyeTyrantSecondTriggeredAbility extends TriggeredAbilityImpl { KarazikarTheEyeTyrantSecondTriggeredAbility() { diff --git a/Mage.Sets/src/mage/cards/k/KarlachFuryOfAvernus.java b/Mage.Sets/src/mage/cards/k/KarlachFuryOfAvernus.java index a606bfc31e4..0effa284293 100644 --- a/Mage.Sets/src/mage/cards/k/KarlachFuryOfAvernus.java +++ b/Mage.Sets/src/mage/cards/k/KarlachFuryOfAvernus.java @@ -5,16 +5,17 @@ import mage.abilities.Ability; import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; import mage.abilities.common.ChooseABackgroundAbility; import mage.abilities.condition.common.FirstCombatPhaseCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.AdditionalCombatPhaseEffect; import mage.abilities.effects.common.UntapAllEffect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.StaticFilters; -import mage.game.Game; import java.util.UUID; @@ -33,17 +34,13 @@ public final class KarlachFuryOfAvernus extends CardImpl { this.toughness = new MageInt(4); // Whenever you attack, if it's the first combat phase of the turn, untap all attacking creatures. They gain first strike until end of turn. After this phase, there is an additional combat phase. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksWithCreaturesTriggeredAbility( - new UntapAllEffect(StaticFilters.FILTER_ATTACKING_CREATURES), 1 - ), FirstCombatPhaseCondition.instance, "Whenever you attack, if it's the first " + - "combat phase of the turn, untap all attacking creatures. They gain first strike " + - "until end of turn. After this phase, there is an additional combat phase." - ); + Ability ability = new AttacksWithCreaturesTriggeredAbility( + new UntapAllEffect(StaticFilters.FILTER_ATTACKING_CREATURES), 1 + ).withInterveningIf(FirstCombatPhaseCondition.instance); ability.addEffect(new GainAbilityAllEffect( FirstStrikeAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_ATTACKING_CREATURES - )); + ).setText("They gain first strike until end of turn")); ability.addEffect(new AdditionalCombatPhaseEffect()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/k/KarmicJustice.java b/Mage.Sets/src/mage/cards/k/KarmicJustice.java index 68bb6406d27..ef9e7be0aa1 100644 --- a/Mage.Sets/src/mage/cards/k/KarmicJustice.java +++ b/Mage.Sets/src/mage/cards/k/KarmicJustice.java @@ -1,7 +1,6 @@ package mage.cards.k; -import java.util.UUID; import mage.MageObject; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.common.DestroyTargetEffect; @@ -15,6 +14,9 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.target.Target; import mage.target.TargetPermanent; +import mage.target.targetadjustment.DefineByTriggerTargetAdjuster; + +import java.util.UUID; /** * @@ -25,7 +27,6 @@ public final class KarmicJustice extends CardImpl { public KarmicJustice(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}"); - // Whenever a spell or ability an opponent controls destroys a noncreature permanent you control, you may destroy target permanent that opponent controls. this.addAbility(new KarmicJusticeTriggeredAbility()); } @@ -45,8 +46,9 @@ class KarmicJusticeTriggeredAbility extends TriggeredAbilityImpl { KarmicJusticeTriggeredAbility() { super(Zone.BATTLEFIELD, new DestroyTargetEffect(), true); this.setLeavesTheBattlefieldTrigger(true); + this.setTargetAdjuster(DefineByTriggerTargetAdjuster.instance); } - + private KarmicJusticeTriggeredAbility(final KarmicJusticeTriggeredAbility ability) { super(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KarplusanHound.java b/Mage.Sets/src/mage/cards/k/KarplusanHound.java index cfd0c78ea9d..39ef5994d2c 100644 --- a/Mage.Sets/src/mage/cards/k/KarplusanHound.java +++ b/Mage.Sets/src/mage/cards/k/KarplusanHound.java @@ -1,11 +1,10 @@ package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -14,27 +13,26 @@ import mage.constants.SubType; import mage.filter.common.FilterPlaneswalkerPermanent; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class KarplusanHound extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterPlaneswalkerPermanent(SubType.CHANDRA, "you control a Chandra planeswalker") + ); + public KarplusanHound(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.subtype.add(SubType.DOG); this.power = new MageInt(3); this.toughness = new MageInt(3); - FilterPlaneswalkerPermanent filter = new FilterPlaneswalkerPermanent("a Chandra planeswalker"); - filter.add(SubType.CHANDRA.getPredicate()); + // Whenever Karplusan Hound attacks, if you control a Chandra planeswalker, this creature deals 2 damage to any target. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new DamageTargetEffect(2), false), - new PermanentsOnTheBattlefieldCondition(filter), - "Whenever {this} attacks, if you control a Chandra planeswalker, " - + "this creature deals 2 damage to any target" - ); + Ability ability = new AttacksTriggeredAbility(new DamageTargetEffect(2)).withInterveningIf(condition); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KavuPrimarch.java b/Mage.Sets/src/mage/cards/k/KavuPrimarch.java index 30bc8420716..e0b89e5bd08 100644 --- a/Mage.Sets/src/mage/cards/k/KavuPrimarch.java +++ b/Mage.Sets/src/mage/cards/k/KavuPrimarch.java @@ -1,7 +1,6 @@ package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.common.KickedCondition; @@ -14,6 +13,8 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; +import java.util.UUID; + /** * * @author LevelX2 @@ -36,7 +37,7 @@ public final class KavuPrimarch extends CardImpl { // If Kavu Primarch was kicked, it enters with four +1/+1 counters on it. this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(4)),KickedCondition.ONCE, - "If Kavu Primarch was kicked, it enters with four +1/+1 counters on it.", "")); + "If {this} was kicked, it enters with four +1/+1 counters on it.", "")); } private KavuPrimarch(final KavuPrimarch card) { diff --git a/Mage.Sets/src/mage/cards/k/KavuTitan.java b/Mage.Sets/src/mage/cards/k/KavuTitan.java index a60db4425a1..5e2a273fb83 100644 --- a/Mage.Sets/src/mage/cards/k/KavuTitan.java +++ b/Mage.Sets/src/mage/cards/k/KavuTitan.java @@ -1,7 +1,5 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; @@ -13,18 +11,19 @@ import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.counters.CounterType; +import java.util.UUID; + /** - * * @author Backfir3 */ public final class KavuTitan extends CardImpl { public KavuTitan(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.KAVU); this.power = new MageInt(2); @@ -32,10 +31,12 @@ public final class KavuTitan extends CardImpl { // Kicker {2}{G} this.addAbility(new KickerAbility("{2}{G}")); + // If Kavu Titan was kicked, it enters with three +1/+1 counters on it and with trample. - Ability ability = new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(3)), - KickedCondition.ONCE, - "If Kavu Titan was kicked, it enters with three +1/+1 counters on it and with trample.", ""); + Ability ability = new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(3)), KickedCondition.ONCE, + "If {this} was kicked, it enters with three +1/+1 counters on it and with trample.", "" + ); ability.addEffect(new GainAbilitySourceEffect(TrampleAbility.getInstance(), Duration.WhileOnBattlefield)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KayaGhostAssassin.java b/Mage.Sets/src/mage/cards/k/KayaGhostAssassin.java index c091b26812c..a3a1d8be781 100644 --- a/Mage.Sets/src/mage/cards/k/KayaGhostAssassin.java +++ b/Mage.Sets/src/mage/cards/k/KayaGhostAssassin.java @@ -13,7 +13,6 @@ import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -27,8 +26,6 @@ import java.util.UUID; */ public final class KayaGhostAssassin extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("target creature to exile. Choose no targets to exile Kaya."); - public KayaGhostAssassin(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{W}{B}"); this.supertype.add(SuperType.LEGENDARY); @@ -39,21 +36,17 @@ public final class KayaGhostAssassin extends CardImpl { // 0: Exile Kaya, Ghost Assassin or up to one target creature. Return that card to the battlefield under its owner's control at the beginning of your next upkeep. // You lose 2 life. Ability ability = new LoyaltyAbility(new KayaGhostAssassinEffect(), 0); - ability.addTarget(new TargetCreaturePermanent(0, 1, filter, false)); + ability.addTarget(new TargetCreaturePermanent(0, 1).withChooseHint("Choose no targets to exile Kaya")); this.addAbility(ability); // -1: Each opponent loses 2 life and you gain 2 life. ability = new LoyaltyAbility(new LoseLifeOpponentsEffect(2), -1); - Effect effect = new GainLifeEffect(2); - effect.setText("and you gain 2 life"); - ability.addEffect(effect); + ability.addEffect(new GainLifeEffect(2).setText("and you gain 2 life")); this.addAbility(ability); // -2: Each opponent discards a card and you draw a card. ability = new LoyaltyAbility(new DiscardEachPlayerEffect(TargetController.OPPONENT), -2); - effect = new DrawCardSourceControllerEffect(1); - effect.setText("and you draw a card"); - ability.addEffect(effect); + ability.addEffect(new DrawCardSourceControllerEffect(1).setText("and you draw a card")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KayaTheInexorable.java b/Mage.Sets/src/mage/cards/k/KayaTheInexorable.java index cc1ab89fcaf..df3d529fd39 100644 --- a/Mage.Sets/src/mage/cards/k/KayaTheInexorable.java +++ b/Mage.Sets/src/mage/cards/k/KayaTheInexorable.java @@ -1,6 +1,5 @@ package mage.cards.k; -import mage.MageObject; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; @@ -22,21 +21,20 @@ import mage.game.Game; import mage.game.command.emblems.KayaTheInexorableEmblem; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; -import mage.game.permanent.Permanent; import mage.game.permanent.token.SpiritWhiteToken; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetNonlandPermanent; import java.util.UUID; /** - * * @author weirddan455 */ public final class KayaTheInexorable extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature"); + static { filter.add(TokenPredicate.FALSE); } @@ -52,7 +50,7 @@ public final class KayaTheInexorable extends CardImpl { LoyaltyAbility ability = new LoyaltyAbility(new AddCountersTargetEffect(CounterType.GHOSTFORM.createInstance()), 1); ability.addEffect(new GainAbilityTargetEffect(new KayaTheInexorableTriggeredAbility(), Duration.WhileOnBattlefield, "It gains \"When this creature dies or is put into exile, return it to its owner's hand and create a 1/1 white Spirit creature token with flying.\"")); - ability.addTarget(new TargetCreaturePermanent(0, 1, filter, false)); + ability.addTarget(new TargetPermanent(0, 1, filter)); this.addAbility(ability); // −3: Exile target nonland permanent. diff --git a/Mage.Sets/src/mage/cards/k/KeeperOfKeys.java b/Mage.Sets/src/mage/cards/k/KeeperOfKeys.java index a35271883d5..86b92e316aa 100644 --- a/Mage.Sets/src/mage/cards/k/KeeperOfKeys.java +++ b/Mage.Sets/src/mage/cards/k/KeeperOfKeys.java @@ -1,24 +1,23 @@ package mage.cards.k; -import java.util.UUID; import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.MonarchIsSourceControllerCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.BecomesMonarchSourceEffect; import mage.abilities.effects.common.combat.CantBeBlockedAllEffect; import mage.abilities.hint.common.MonarchHint; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class KeeperOfKeys extends CardImpl { @@ -36,10 +35,9 @@ public final class KeeperOfKeys extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new BecomesMonarchSourceEffect()).addHint(MonarchHint.instance)); // At the beginning of your upkeep, if you're the monarch, creatures you control can't be blocked this turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new BeginningOfUpkeepTriggeredAbility( - new CantBeBlockedAllEffect(StaticFilters.FILTER_CONTROLLED_CREATURES, Duration.EndOfTurn) - ), MonarchIsSourceControllerCondition.instance, - "At the beginning of your upkeep, if you're the monarch, creatures you control can't be blocked this turn.")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CantBeBlockedAllEffect( + StaticFilters.FILTER_CONTROLLED_CREATURES, Duration.EndOfTurn + )).withInterveningIf(MonarchIsSourceControllerCondition.instance)); } private KeeperOfKeys(final KeeperOfKeys card) { diff --git a/Mage.Sets/src/mage/cards/k/KeeperOfTheAccord.java b/Mage.Sets/src/mage/cards/k/KeeperOfTheAccord.java index 1c90188f3da..6867dc7a039 100644 --- a/Mage.Sets/src/mage/cards/k/KeeperOfTheAccord.java +++ b/Mage.Sets/src/mage/cards/k/KeeperOfTheAccord.java @@ -2,11 +2,10 @@ package mage.cards.k; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -43,22 +42,14 @@ public final class KeeperOfTheAccord extends CardImpl { this.toughness = new MageInt(4); // At the beginning of each opponent's end step, if that player controls more creatures than you, create a 1/1 white Soldier creature token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - TargetController.OPPONENT, new CreateTokenEffect(new SoldierToken()), false - ), KeeperOfTheAccordCondition.CREATURES, "At the beginning of each opponent's end step, " + - "if that player controls more creatures than you, create a 1/1 white Soldier creature token." - )); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.OPPONENT, new CreateTokenEffect(new SoldierToken()), false + ).withInterveningIf(KeeperOfTheAccordCondition.CREATURES)); // At the beginning of each opponent's end step, if that player controls more lands than you, you may search your library for a basic Plains card, put it onto the battlefield tapped, then shuffle your library. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility(TargetController.OPPONENT, new SearchLibraryPutInPlayEffect( - new TargetCardInLibrary(filter), true - ), true), - KeeperOfTheAccordCondition.LANDS, "At the beginning of each opponent's end step, " + - "if that player controls more lands than you, you may search your library for a basic Plains card, " + - "put it onto the battlefield tapped, then shuffle." - )); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.OPPONENT, new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true), true + ).withInterveningIf(KeeperOfTheAccordCondition.LANDS)); } private KeeperOfTheAccord(final KeeperOfTheAccord card) { @@ -73,8 +64,8 @@ public final class KeeperOfTheAccord extends CardImpl { enum KeeperOfTheAccordCondition implements Condition { - CREATURES(StaticFilters.FILTER_PERMANENT_CREATURE), - LANDS(StaticFilters.FILTER_LAND); + CREATURES(StaticFilters.FILTER_PERMANENT_CREATURES), + LANDS(StaticFilters.FILTER_LANDS); private final FilterPermanent filter; @@ -87,4 +78,9 @@ enum KeeperOfTheAccordCondition implements Condition { return game.getBattlefield().countAll(filter, source.getControllerId(), game) < game.getBattlefield().countAll(filter, game.getActivePlayerId(), game); } + + @Override + public String toString() { + return "that player controls more " + filter.getMessage() + " than you"; + } } diff --git a/Mage.Sets/src/mage/cards/k/KeeperOfTheMind.java b/Mage.Sets/src/mage/cards/k/KeeperOfTheMind.java index a2329e6df87..2a412b08e09 100644 --- a/Mage.Sets/src/mage/cards/k/KeeperOfTheMind.java +++ b/Mage.Sets/src/mage/cards/k/KeeperOfTheMind.java @@ -5,14 +5,12 @@ import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; -import mage.abilities.effects.Effect; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterOpponent; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; @@ -38,12 +36,12 @@ public class KeeperOfTheMind extends CardImpl { this.toughness = new MageInt(2); // {U}, {tap}: Choose target opponent who had at least two more cards in hand than you did as you activated this ability. Draw a card. - Effect effect = new DrawCardSourceControllerEffect(1); - effect.setText("Choose target opponent who had at least two more cards in hand than you did as you activated this ability. Draw a card."); - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{U}"), KeeperOfTheMindCondition.instance, - "{U}, {T}: Choose target opponent who had at least two more cards in " - + "hand than you did as you activated this ability. Draw a card."); + Ability ability = new ActivateIfConditionActivatedAbility( + new DrawCardSourceControllerEffect(1) + .setText("choose target opponent who has at least two more cards " + + "in hand than you do as you activate this ability. Draw a card"), + new ManaCostsImpl<>("{U}"), KeeperOfTheMindCondition.instance + ).hideCondition(); ability.addCost(new TapSourceCost()); ability.setTargetAdjuster(KeeperOfTheMindAdjuster.instance); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/k/KeepsakeGorgon.java b/Mage.Sets/src/mage/cards/k/KeepsakeGorgon.java index ada8df11c62..0e1fbe64369 100644 --- a/Mage.Sets/src/mage/cards/k/KeepsakeGorgon.java +++ b/Mage.Sets/src/mage/cards/k/KeepsakeGorgon.java @@ -16,6 +16,7 @@ import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -43,7 +44,7 @@ public final class KeepsakeGorgon extends CardImpl { this.addAbility(new MonstrosityAbility("{5}{B}{B}", 1)); // When Keepsake Gorgon becomes monstrous, destroy target non-Gorgon creature an opponent controls. Ability ability = new BecomesMonstrousSourceTriggeredAbility(new DestroyTargetEffect()); - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); ability.addTarget(target); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KefkaDancingMad.java b/Mage.Sets/src/mage/cards/k/KefkaDancingMad.java index c3ab872f77e..7f7954118a2 100644 --- a/Mage.Sets/src/mage/cards/k/KefkaDancingMad.java +++ b/Mage.Sets/src/mage/cards/k/KefkaDancingMad.java @@ -114,6 +114,7 @@ class KefkaDancingMadEffect extends OneShotEffect { return false; } controller.moveCards(cards, Zone.EXILED, source, game); + game.processAction(); cards.retainZone(Zone.EXILED, game); KefkaDancingMadTracker tracker = new KefkaDancingMadTracker(); CardUtil.castMultipleWithAttributeForFree( diff --git a/Mage.Sets/src/mage/cards/k/KefnetsMonument.java b/Mage.Sets/src/mage/cards/k/KefnetsMonument.java index 87763e026e9..9ce129baa4c 100644 --- a/Mage.Sets/src/mage/cards/k/KefnetsMonument.java +++ b/Mage.Sets/src/mage/cards/k/KefnetsMonument.java @@ -15,10 +15,13 @@ import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * @author fireshoes */ @@ -43,7 +46,7 @@ public final class KefnetsMonument extends CardImpl { new DontUntapInControllersNextUntapStepTargetEffect(), StaticFilters.FILTER_SPELL_A_CREATURE, false ); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KeldonBerserker.java b/Mage.Sets/src/mage/cards/k/KeldonBerserker.java index 59237df12a6..a94521f8c77 100644 --- a/Mage.Sets/src/mage/cards/k/KeldonBerserker.java +++ b/Mage.Sets/src/mage/cards/k/KeldonBerserker.java @@ -1,33 +1,36 @@ package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledLandPermanent; import mage.filter.predicate.permanent.TappedPredicate; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class KeldonBerserker extends CardImpl { - private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent("untapped lands"); + private static final FilterPermanent filter = new FilterControlledLandPermanent("you control no untapped lands"); static { filter.add(TappedPredicate.UNTAPPED); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0); + public KeldonBerserker(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); @@ -38,11 +41,9 @@ public final class KeldonBerserker extends CardImpl { this.toughness = new MageInt(3); // Whenever Keldon Berserker attacks, if you control no untapped lands, it gets +3/+0 until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new BoostSourceEffect(3, 0, Duration.EndOfTurn), false), - new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)), - "Whenever {this} attacks, if you control no untapped lands, it gets +3/+0 until end of turn." - )); + this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect( + 3, 0, Duration.EndOfTurn, "it" + )).withInterveningIf(condition)); } private KeldonBerserker(final KeldonBerserker card) { diff --git a/Mage.Sets/src/mage/cards/k/KeldonMegaliths.java b/Mage.Sets/src/mage/cards/k/KeldonMegaliths.java index 86f0465ada6..1939b88493a 100644 --- a/Mage.Sets/src/mage/cards/k/KeldonMegaliths.java +++ b/Mage.Sets/src/mage/cards/k/KeldonMegaliths.java @@ -5,14 +5,13 @@ import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.condition.common.HellbentCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.mana.RedManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.Zone; import mage.target.common.TargetAnyTarget; import java.util.UUID; @@ -27,12 +26,13 @@ public final class KeldonMegaliths extends CardImpl { // Keldon Megaliths enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); + // {tap}: Add {R}. this.addAbility(new RedManaAbility()); + // Hellbent - {1}{R}, {tap}: Keldon Megaliths deals 1 damage to any target. Activate this ability only if you have no cards in hand. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new DamageTargetEffect(1), - new ManaCostsImpl<>("{1}{R}"), HellbentCondition.instance + Ability ability = new ActivateIfConditionActivatedAbility( + new DamageTargetEffect(1), new ManaCostsImpl<>("{1}{R}"), HellbentCondition.instance ); ability.setAbilityWord(AbilityWord.HELLBENT); ability.addCost(new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/k/KeldonOverseer.java b/Mage.Sets/src/mage/cards/k/KeldonOverseer.java index 7634b4ec17e..17ea8c590b9 100644 --- a/Mage.Sets/src/mage/cards/k/KeldonOverseer.java +++ b/Mage.Sets/src/mage/cards/k/KeldonOverseer.java @@ -1,12 +1,9 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; @@ -19,8 +16,9 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class KeldonOverseer extends CardImpl { @@ -40,12 +38,15 @@ public final class KeldonOverseer extends CardImpl { this.addAbility(HasteAbility.getInstance()); // When Keldon Overseer enters the battlefield, if it was kicked, gain control of target creature until end of turn. Untap that creature. It gains haste until end of turn. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new GainControlTargetEffect(Duration.EndOfTurn, true)); - ability.addEffect(new UntapTargetEffect()); - ability.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn)); + Ability ability = new EntersBattlefieldTriggeredAbility( + new GainControlTargetEffect(Duration.EndOfTurn) + ).withInterveningIf(KickedCondition.ONCE); + ability.addEffect(new UntapTargetEffect("Untap that creature")); + ability.addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("It gains haste until end of turn")); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.ONCE, - "When {this} enters, if it was kicked, gain control of target creature until end of turn. Untap that creature. It gains haste until end of turn.")); + this.addAbility(ability); } private KeldonOverseer(final KeldonOverseer card) { diff --git a/Mage.Sets/src/mage/cards/k/KeldonStrikeTeam.java b/Mage.Sets/src/mage/cards/k/KeldonStrikeTeam.java index d718011d349..2f30c861bb1 100644 --- a/Mage.Sets/src/mage/cards/k/KeldonStrikeTeam.java +++ b/Mage.Sets/src/mage/cards/k/KeldonStrikeTeam.java @@ -6,7 +6,6 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.KickedCondition; import mage.abilities.condition.common.SourceEnteredThisTurnCondition; import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.HasteAbility; @@ -38,11 +37,9 @@ public final class KeldonStrikeTeam extends CardImpl { this.addAbility(new KickerAbility("{1}{W}")); // When Keldon Strike Team enters the battlefield, if it was kicked, create two 1/1 white Soldier creature tokens. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new SoldierToken(), 2)), - KickedCondition.ONCE, "When {this} enters, if it was kicked, " + - "create two 1/1 white Soldier creature tokens." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new CreateTokenEffect(new SoldierToken(), 2) + ).withInterveningIf(KickedCondition.ONCE)); // As long as Keldon Strike Team entered the battlefield this turn, creatures you control have haste. this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( @@ -50,7 +47,7 @@ public final class KeldonStrikeTeam extends CardImpl { HasteAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_CONTROLLED_CREATURE ), SourceEnteredThisTurnCondition.DID, "as long as {this} " + - "entered the battlefield this turn, creatures you control have haste" + "entered this turn, creatures you control have haste" ))); } diff --git a/Mage.Sets/src/mage/cards/k/KelpieGuide.java b/Mage.Sets/src/mage/cards/k/KelpieGuide.java index 8637b8b6589..10d5d81af0e 100644 --- a/Mage.Sets/src/mage/cards/k/KelpieGuide.java +++ b/Mage.Sets/src/mage/cards/k/KelpieGuide.java @@ -15,7 +15,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledLandPermanent; import mage.target.TargetPermanent; @@ -27,9 +26,9 @@ import java.util.UUID; */ public final class KelpieGuide extends CardImpl { - private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent("you control eight or more lands"); - private static final Condition condition - = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 7); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledLandPermanent("you control eight or more lands"), ComparisonType.MORE_THAN, 7 + ); public KelpieGuide(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); @@ -44,9 +43,7 @@ public final class KelpieGuide extends CardImpl { this.addAbility(ability); // {T}: Tap target permanent. Activate only if you control eight or more lands. - ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new TapTargetEffect(), new TapSourceCost(), condition - ); + ability = new ActivateIfConditionActivatedAbility(new TapTargetEffect(), new TapSourceCost(), condition); ability.addTarget(new TargetPermanent()); this.addAbility(ability.addHint(LandsYouControlHint.instance)); } diff --git a/Mage.Sets/src/mage/cards/k/KelsinkoRanger.java b/Mage.Sets/src/mage/cards/k/KelsinkoRanger.java index 618b18f0e61..644cccb0c2c 100644 --- a/Mage.Sets/src/mage/cards/k/KelsinkoRanger.java +++ b/Mage.Sets/src/mage/cards/k/KelsinkoRanger.java @@ -17,6 +17,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -44,7 +45,7 @@ public final class KelsinkoRanger extends CardImpl { new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{1}{W}") ); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/Kezzerdrix.java b/Mage.Sets/src/mage/cards/k/Kezzerdrix.java index 2e4e111d1f2..f4fc06f471d 100644 --- a/Mage.Sets/src/mage/cards/k/Kezzerdrix.java +++ b/Mage.Sets/src/mage/cards/k/Kezzerdrix.java @@ -1,27 +1,31 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.condition.common.CreatureCountCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.constants.TargetController; +import mage.filter.common.FilterOpponentsCreaturePermanent; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class Kezzerdrix extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterOpponentsCreaturePermanent("your opponents control no creatures"), ComparisonType.EQUAL_TO, 0 + ); + public Kezzerdrix(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); this.subtype.add(SubType.RABBIT); this.subtype.add(SubType.BEAST); @@ -32,10 +36,7 @@ public final class Kezzerdrix extends CardImpl { this.addAbility(FirstStrikeAbility.getInstance()); // At the beginning of your upkeep, if your opponents control no creatures, Kezzerdrix deals 4 damage to you. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new DamageControllerEffect(4)), - new CreatureCountCondition(0, TargetController.OPPONENT), - "At the beginning of your upkeep, if your opponents control no creatures, {this} deals 4 damage to you.")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DamageControllerEffect(4)).withInterveningIf(condition)); } private Kezzerdrix(final Kezzerdrix card) { diff --git a/Mage.Sets/src/mage/cards/k/KhalniAmbush.java b/Mage.Sets/src/mage/cards/k/KhalniAmbush.java index 83f23c5fa2b..d4ede15e71e 100644 --- a/Mage.Sets/src/mage/cards/k/KhalniAmbush.java +++ b/Mage.Sets/src/mage/cards/k/KhalniAmbush.java @@ -8,11 +8,14 @@ import mage.cards.ModalDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author JayDi85 */ @@ -31,7 +34,7 @@ public final class KhalniAmbush extends ModalDoubleFacedCard { // Target creature you control fights target creature you don't control. this.getLeftHalfCard().getSpellAbility().addEffect(new FightTargetsEffect()); this.getLeftHalfCard().getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getLeftHalfCard().getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); // 2. // Khalni Territory diff --git a/Mage.Sets/src/mage/cards/k/KikiJikiMirrorBreaker.java b/Mage.Sets/src/mage/cards/k/KikiJikiMirrorBreaker.java index 321feeb05eb..bf78dba3fdd 100644 --- a/Mage.Sets/src/mage/cards/k/KikiJikiMirrorBreaker.java +++ b/Mage.Sets/src/mage/cards/k/KikiJikiMirrorBreaker.java @@ -1,37 +1,34 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; -import mage.abilities.effects.common.SacrificeTargetEffect; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author jonubuu */ public final class KikiJikiMirrorBreaker extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("nonlegendary creature you control"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("nonlegendary creature you control"); static { filter.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); @@ -48,11 +45,11 @@ public final class KikiJikiMirrorBreaker extends CardImpl { // Haste this.addAbility(HasteAbility.getInstance()); + // {T}: Create a token that's a copy of target nonlegendary creature you control, except it has haste. Sacrifice it at the beginning of the next end step. Ability ability = new SimpleActivatedAbility(new KikiJikiMirrorBreakerEffect(), new TapSourceCost()); - ability.addTarget(new TargetControlledCreaturePermanent(1, 1, filter, false)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); - } private KikiJikiMirrorBreaker(final KikiJikiMirrorBreaker card) { diff --git a/Mage.Sets/src/mage/cards/k/KiloApogeeMind.java b/Mage.Sets/src/mage/cards/k/KiloApogeeMind.java new file mode 100644 index 00000000000..3e5003b7852 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KiloApogeeMind.java @@ -0,0 +1,44 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.common.BecomesTappedSourceTriggeredAbility; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KiloApogeeMind extends CardImpl { + + public KiloApogeeMind(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{U}{R}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.ROBOT); + this.subtype.add(SubType.ARTIFICER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Whenever Kilo becomes tapped, proliferate. + this.addAbility(new BecomesTappedSourceTriggeredAbility(new ProliferateEffect())); + } + + private KiloApogeeMind(final KiloApogeeMind card) { + super(card); + } + + @Override + public KiloApogeeMind copy() { + return new KiloApogeeMind(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/Kindle.java b/Mage.Sets/src/mage/cards/k/Kindle.java index 457244f8c50..08ca80c427d 100644 --- a/Mage.Sets/src/mage/cards/k/Kindle.java +++ b/Mage.Sets/src/mage/cards/k/Kindle.java @@ -33,7 +33,7 @@ public final class Kindle extends CardImpl { // Kindle deals X damage to any target, where X is 2 plus the number of cards named Kindle in all graveyards. Effect effect = new DamageTargetEffect(new KindleCardsInAllGraveyardsCount(filter)); - effect.setText("{this} deals X damage to any target, where X is 2 plus the number of cards named {this} in all graveyards"); + effect.setText("{this} deals X damage to any target, where X is 2 plus the number of cards named Kindle in all graveyards"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetAnyTarget()); } diff --git a/Mage.Sets/src/mage/cards/k/KindlyStranger.java b/Mage.Sets/src/mage/cards/k/KindlyStranger.java index d0cb859635d..8a07ada2da8 100644 --- a/Mage.Sets/src/mage/cards/k/KindlyStranger.java +++ b/Mage.Sets/src/mage/cards/k/KindlyStranger.java @@ -3,15 +3,15 @@ package mage.cards.k; import mage.MageInt; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.TransformAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import java.util.UUID; @@ -30,11 +30,9 @@ public final class KindlyStranger extends CardImpl { // Delirium — {2}{B}: Transform Kindly Stranger. Activate this ability only if there are four or more card types among cards in your graveyard. this.addAbility(new TransformAbility()); - this.addAbility(new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new TransformSourceEffect(), new ManaCostsImpl<>("{2}{B}"), - DeliriumCondition.instance, "Delirium — {2}{B}: Transform {this}. " + - "Activate only if there are four or more card types among cards in your graveyard." - ).addHint(CardTypesInGraveyardCount.YOU.getHint())); + this.addAbility(new ActivateIfConditionActivatedAbility( + new TransformSourceEffect(), new ManaCostsImpl<>("{2}{B}"), DeliriumCondition.instance + ).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); } private KindlyStranger(final KindlyStranger card) { diff --git a/Mage.Sets/src/mage/cards/k/KingCrab.java b/Mage.Sets/src/mage/cards/k/KingCrab.java index 31e6bc413ec..4c7eefe63c9 100644 --- a/Mage.Sets/src/mage/cards/k/KingCrab.java +++ b/Mage.Sets/src/mage/cards/k/KingCrab.java @@ -16,6 +16,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class KingCrab extends CardImpl { // {1}{U}, {tap}: Put target green creature on top of its owner's library. Ability ability = new SimpleActivatedAbility(new PutOnLibraryTargetEffect(true), new ManaCostsImpl<>("{1}{U}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KingNarfisBetrayal.java b/Mage.Sets/src/mage/cards/k/KingNarfisBetrayal.java index c6174250f9b..5b618f1ad34 100644 --- a/Mage.Sets/src/mage/cards/k/KingNarfisBetrayal.java +++ b/Mage.Sets/src/mage/cards/k/KingNarfisBetrayal.java @@ -127,7 +127,7 @@ class KingNarfisBetrayalSecondEffect extends OneShotEffect { public KingNarfisBetrayalSecondEffect() { super(Outcome.Benefit); - this.staticText = "Until end of turn, you may cast spells from among cards exiled with King Narfi's Betrayal," + + this.staticText = "Until end of turn, you may cast spells from among cards exiled with {this}," + " and you may spend mana as though it were mana of any color to cast those spells"; } diff --git a/Mage.Sets/src/mage/cards/k/KingsAssassin.java b/Mage.Sets/src/mage/cards/k/KingsAssassin.java index cda86b5d362..bade0ce6034 100644 --- a/Mage.Sets/src/mage/cards/k/KingsAssassin.java +++ b/Mage.Sets/src/mage/cards/k/KingsAssassin.java @@ -1,7 +1,5 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -12,17 +10,17 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author fireshoes */ public final class KingsAssassin extends CardImpl { - + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { @@ -30,16 +28,18 @@ public final class KingsAssassin extends CardImpl { } public KingsAssassin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ASSASSIN); this.power = new MageInt(1); this.toughness = new MageInt(1); // {tap}: Destroy target tapped creature. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new DestroyTargetEffect(), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); - ability.addTarget(new TargetCreaturePermanent(filter)); + Ability ability = new ActivateIfConditionActivatedAbility( + new DestroyTargetEffect(), new TapSourceCost(), + MyTurnBeforeAttackersDeclaredCondition.instance + ); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KioraBehemothBeckoner.java b/Mage.Sets/src/mage/cards/k/KioraBehemothBeckoner.java index 5efdb34cf41..a04671459d6 100644 --- a/Mage.Sets/src/mage/cards/k/KioraBehemothBeckoner.java +++ b/Mage.Sets/src/mage/cards/k/KioraBehemothBeckoner.java @@ -2,14 +2,17 @@ package mage.cards.k; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.UntapTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.target.TargetPermanent; @@ -21,7 +24,7 @@ import java.util.UUID; public final class KioraBehemothBeckoner extends CardImpl { private static final FilterPermanent filter - = new FilterCreaturePermanent("a creature with power 4 or greater"); + = new FilterControlledCreaturePermanent("a creature you control with power 4 or greater"); static { filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); @@ -35,9 +38,7 @@ public final class KioraBehemothBeckoner extends CardImpl { this.setStartingLoyalty(7); // Whenever a creature with power 4 or greater you control enters, draw a card. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility( - Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), filter, false - )); + this.addAbility(new EntersBattlefieldAllTriggeredAbility(new DrawCardSourceControllerEffect(1), filter)); // -1: Untap target permanent. Ability ability = new LoyaltyAbility(new UntapTargetEffect(), -1); diff --git a/Mage.Sets/src/mage/cards/k/KioraTheRisingTide.java b/Mage.Sets/src/mage/cards/k/KioraTheRisingTide.java index 8d47f26d2b2..1c7450de867 100644 --- a/Mage.Sets/src/mage/cards/k/KioraTheRisingTide.java +++ b/Mage.Sets/src/mage/cards/k/KioraTheRisingTide.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.ThresholdCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.cards.CardImpl; @@ -18,14 +17,13 @@ import mage.game.permanent.token.ScionOfTheDeepToken; import java.util.UUID; /** - * * @author ciaccona007 */ public final class KioraTheRisingTide extends CardImpl { public KioraTheRisingTide(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); - + this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.MERFOLK); this.subtype.add(SubType.NOBLE); @@ -38,13 +36,8 @@ public final class KioraTheRisingTide extends CardImpl { )); // Threshold -- Whenever Kiora attacks, if there are seven or more cards in your graveyard, you may create Scion of the Deep, a legendary 8/8 blue Octopus creature token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new CreateTokenEffect(new ScionOfTheDeepToken()), true), - ThresholdCondition.instance, "Whenever {this} attacks, if there are seven " - + "or more cards in your graveyard, you may create " - + "Scion of the Deep, a legendary 8/8 blue Octopus creature token." - ).setAbilityWord(AbilityWord.THRESHOLD)); - + this.addAbility(new AttacksTriggeredAbility(new CreateTokenEffect(new ScionOfTheDeepToken()), true) + .withInterveningIf(ThresholdCondition.instance).setAbilityWord(AbilityWord.THRESHOLD)); } private KioraTheRisingTide(final KioraTheRisingTide card) { diff --git a/Mage.Sets/src/mage/cards/k/KitesailCleric.java b/Mage.Sets/src/mage/cards/k/KitesailCleric.java index 3a98a3682fb..558468dbcd0 100644 --- a/Mage.Sets/src/mage/cards/k/KitesailCleric.java +++ b/Mage.Sets/src/mage/cards/k/KitesailCleric.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.KickerAbility; @@ -36,11 +35,7 @@ public final class KitesailCleric extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Kitesail Cleric enters the battelfield, if it was kicked, tap up to two target creatures. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new TapTargetEffect()), - KickedCondition.ONCE, "When {this} enters, " + - "if it was kicked, tap up to two target creatures." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()).withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetCreaturePermanent(0, 2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KithkinShielddare.java b/Mage.Sets/src/mage/cards/k/KithkinShielddare.java index 2632b782776..fdae7a9efa1 100644 --- a/Mage.Sets/src/mage/cards/k/KithkinShielddare.java +++ b/Mage.Sets/src/mage/cards/k/KithkinShielddare.java @@ -15,6 +15,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterBlockingCreature; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class KithkinShielddare extends CardImpl { new BoostTargetEffect(2, 2, Duration.EndOfTurn), new ManaCostsImpl<>("{W}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KitsuneBonesetter.java b/Mage.Sets/src/mage/cards/k/KitsuneBonesetter.java index dbf33066536..75c7e827a96 100644 --- a/Mage.Sets/src/mage/cards/k/KitsuneBonesetter.java +++ b/Mage.Sets/src/mage/cards/k/KitsuneBonesetter.java @@ -1,40 +1,36 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.common.MoreCardsInHandThanOpponentsCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.PreventDamageToTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class KitsuneBonesetter extends CardImpl { public KitsuneBonesetter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.FOX); this.subtype.add(SubType.CLERIC); this.power = new MageInt(0); this.toughness = new MageInt(1); - + // {tap}: Prevent the next 3 damage that would be dealt to target creature this turn. Activate this ability only if you have more cards in hand than each opponent. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, - new PreventDamageToTargetEffect(Duration.EndOfTurn, 3), - new TapSourceCost(), + Ability ability = new ActivateIfConditionActivatedAbility( + new PreventDamageToTargetEffect(Duration.EndOfTurn, 3), new TapSourceCost(), MoreCardsInHandThanOpponentsCondition.instance ); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/k/KitsuneHealer.java b/Mage.Sets/src/mage/cards/k/KitsuneHealer.java index bcf1ba79a41..e0f9933349d 100644 --- a/Mage.Sets/src/mage/cards/k/KitsuneHealer.java +++ b/Mage.Sets/src/mage/cards/k/KitsuneHealer.java @@ -16,6 +16,7 @@ import mage.constants.Duration; import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetAnyTarget; import mage.target.common.TargetCreaturePermanent; @@ -44,7 +45,7 @@ public final class KitsuneHealer extends CardImpl { this.addAbility(firstAbility); // {T}: Prevent all damage that would be dealt to target legendary creature this turn. Ability secondAbility = new SimpleActivatedAbility(new PreventDamageToTargetEffect(Duration.EndOfTurn, Integer.MAX_VALUE), new TapSourceCost()); - secondAbility.addTarget(new TargetCreaturePermanent(filter)); + secondAbility.addTarget(new TargetPermanent(filter)); this.addAbility(secondAbility); } diff --git a/Mage.Sets/src/mage/cards/k/KitsuneMystic.java b/Mage.Sets/src/mage/cards/k/KitsuneMystic.java index dc71085527f..f84edc36e94 100644 --- a/Mage.Sets/src/mage/cards/k/KitsuneMystic.java +++ b/Mage.Sets/src/mage/cards/k/KitsuneMystic.java @@ -1,36 +1,42 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.EnchantedSourceCondition; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.FlipSourceEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterEnchantmentPermanent; +import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.AttachmentAttachedToCardTypePredicate; +import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.permanent.token.TokenImpl; +import mage.players.Player; +import mage.target.TargetImpl; import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; + +import java.util.Optional; +import java.util.UUID; /** - * * @author LevelX2 */ public final class KitsuneMystic extends CardImpl { + private static final Condition condition = new EnchantedSourceCondition(2); + public KitsuneMystic(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.subtype.add(SubType.FOX); this.subtype.add(SubType.WIZARD); @@ -40,9 +46,9 @@ public final class KitsuneMystic extends CardImpl { this.flipCardName = "Autumn-Tail, Kitsune Sage"; // At the beginning of the end step, if Kitsune Mystic is enchanted by two or more Auras, flip it. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new FlipSourceEffect(new AutumnTailKitsuneSage())), - new EnchantedSourceCondition(2), "At the beginning of the end step, if {this} is enchanted by two or more Auras, flip it.")); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.NEXT, new FlipSourceEffect(new AutumnTailKitsuneSage()).setText("flip it"), false, condition + )); } private KitsuneMystic(final KitsuneMystic card) { @@ -77,9 +83,9 @@ class AutumnTailKitsuneSage extends TokenImpl { // {1}: Attach target Aura attached to a creature to another creature. Ability ability = new SimpleActivatedAbility(new AutumnTailEffect(), new GenericManaCost(1)); ability.addTarget(new TargetPermanent(filter)); - ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } + private AutumnTailKitsuneSage(final AutumnTailKitsuneSage token) { super(token); } @@ -93,7 +99,7 @@ class AutumnTailEffect extends OneShotEffect { AutumnTailEffect() { super(Outcome.BoostCreature); - this.staticText = "Attach target Aura attached to a creature to another creature"; + this.staticText = "attach target Aura attached to a creature to another creature"; } private AutumnTailEffect(final AutumnTailEffect effect) { @@ -107,17 +113,24 @@ class AutumnTailEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent aura = game.getPermanent(source.getFirstTarget()); - Permanent creature = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - if (aura != null && creature != null) { - Permanent oldCreature = game.getPermanent(aura.getAttachedTo()); - if (oldCreature == null || oldCreature.equals(creature)) { - return false; - } - if (oldCreature.removeAttachment(aura.getId(), source, game)) { - return creature.addAttachment(aura.getId(), source, game); - } + Player player = game.getPlayer(source.getControllerId()); + Permanent aura = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (player == null || aura == null) { + return false; } - return false; + FilterPermanent filter = new FilterCreaturePermanent(); + filter.add(Predicates.not(new PermanentIdPredicate(aura.getAttachedTo()))); + if (!game.getBattlefield().contains(filter, source.getControllerId(), source, game, 1)) { + return false; + } + TargetPermanent target = new TargetPermanent(filter); + target.withNotTarget(true); + player.choose(outcome, target, source, game); + return Optional + .ofNullable(target) + .map(TargetImpl::getFirstTarget) + .map(game::getPermanent) + .filter(permanent -> permanent.addAttachment(aura.getId(), source, game)) + .isPresent(); } } diff --git a/Mage.Sets/src/mage/cards/k/KjeldoranEliteGuard.java b/Mage.Sets/src/mage/cards/k/KjeldoranEliteGuard.java index 4480660ced7..393dacb4eda 100644 --- a/Mage.Sets/src/mage/cards/k/KjeldoranEliteGuard.java +++ b/Mage.Sets/src/mage/cards/k/KjeldoranEliteGuard.java @@ -3,9 +3,10 @@ package mage.cards.k; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.IsPhaseCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; @@ -24,6 +25,8 @@ import java.util.UUID; */ public final class KjeldoranEliteGuard extends CardImpl { + private static final Condition condition = new IsPhaseCondition(TurnPhase.COMBAT, false); + public KjeldoranEliteGuard(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.subtype.add(SubType.HUMAN); @@ -34,17 +37,16 @@ public final class KjeldoranEliteGuard extends CardImpl { // Target creature gets +2/+2 until end of turn. // When that creature leaves the battlefield this turn, sacrifice Kjeldoran Elite Guard. // Activate only during combat. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, - new KjeldoranEliteGuardEffect(), - new TapSourceCost(), - new IsPhaseCondition(TurnPhase.COMBAT, false)); + Ability ability = new ActivateIfConditionActivatedAbility( + new KjeldoranEliteGuardEffect(), new TapSourceCost(), condition + ); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability); } - private KjeldoranEliteGuard(final KjeldoranEliteGuard card) { super(card); } + private KjeldoranEliteGuard(final KjeldoranEliteGuard card) { + super(card); + } @Override public KjeldoranEliteGuard copy() { @@ -57,7 +59,7 @@ class KjeldoranEliteGuardEffect extends OneShotEffect { KjeldoranEliteGuardEffect() { super(Outcome.Neutral); staticText = "Target creature gets +2/+2 until end of turn. " - + "When that creature leaves the battlefield this turn, sacrifice Kjeldoran Elite Guard."; + + "When that creature leaves the battlefield this turn, sacrifice {this}."; } @Override @@ -79,10 +81,14 @@ class KjeldoranEliteGuardEffect extends OneShotEffect { return true; } - private KjeldoranEliteGuardEffect(KjeldoranEliteGuardEffect effect) { super(effect); } + private KjeldoranEliteGuardEffect(KjeldoranEliteGuardEffect effect) { + super(effect); + } @Override - public KjeldoranEliteGuardEffect copy() { return new KjeldoranEliteGuardEffect(this); } + public KjeldoranEliteGuardEffect copy() { + return new KjeldoranEliteGuardEffect(this); + } } class KjeldoranEliteGuardDelayedTriggeredAbility extends DelayedTriggeredAbility { @@ -105,7 +111,9 @@ class KjeldoranEliteGuardDelayedTriggeredAbility extends DelayedTriggeredAbility } @Override - public boolean checkTrigger(GameEvent event, Game game) { return event.getTargetId().equals(creatureId); } + public boolean checkTrigger(GameEvent event, Game game) { + return event.getTargetId().equals(creatureId); + } @Override public KjeldoranEliteGuardDelayedTriggeredAbility copy() { @@ -113,5 +121,7 @@ class KjeldoranEliteGuardDelayedTriggeredAbility extends DelayedTriggeredAbility } @Override - public String getRule() { return "that creature left the battlefield this turn"; } + public String getRule() { + return "that creature left the battlefield this turn"; + } } diff --git a/Mage.Sets/src/mage/cards/k/KjeldoranGuard.java b/Mage.Sets/src/mage/cards/k/KjeldoranGuard.java index ece65248115..0818d266dcf 100644 --- a/Mage.Sets/src/mage/cards/k/KjeldoranGuard.java +++ b/Mage.Sets/src/mage/cards/k/KjeldoranGuard.java @@ -5,11 +5,12 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.condition.CompoundCondition; +import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.DefendingPlayerControlsNoSourceCondition; import mage.abilities.condition.common.IsPhaseCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.SacrificeTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; @@ -36,6 +37,12 @@ public final class KjeldoranGuard extends CardImpl { filter.add(SuperType.SNOW.getPredicate()); } + private static final Condition condition = new CompoundCondition( + "during combat and only if defending player controls no snow lands", + new IsPhaseCondition(TurnPhase.COMBAT, false), // Only during combat + new InvertCondition(new DefendingPlayerControlsNoSourceCondition(filter)) // Only if defending player controls no snow land + ); + public KjeldoranGuard(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); @@ -45,19 +52,8 @@ public final class KjeldoranGuard extends CardImpl { this.toughness = new MageInt(1); // {T}: Target creature gets +1/+1 until end of turn. When that creature leaves the battlefield this turn, sacrifice Kjeldoran Guard. Activate only during combat and only if defending player controls no snow lands. - CompoundCondition condition = new CompoundCondition( - new IsPhaseCondition(TurnPhase.COMBAT, false), // Only during combat - new InvertCondition(new DefendingPlayerControlsNoSourceCondition(filter)) // Only if defending player controls no snow land - ); - - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, - new KjeldoranGuardEffect(), - new TapSourceCost(), - condition, - "{T}: Target creature gets +1/+1 until end of turn. " - + "When that creature leaves the battlefield this turn, sacrifice {this}. " - + "Activate only during combat and only if defending player controls no snow lands." + Ability ability = new ActivateIfConditionActivatedAbility( + new KjeldoranGuardEffect(), new TapSourceCost(), condition ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); @@ -77,7 +73,7 @@ class KjeldoranGuardEffect extends OneShotEffect { KjeldoranGuardEffect() { super(Outcome.BoostCreature); - staticText = "Target creature gets +1/+1 until end of turn. " + staticText = "target creature gets +1/+1 until end of turn. " + "When that creature leaves the battlefield this turn, sacrifice {this}."; } @@ -109,7 +105,7 @@ class KjeldoranGuardEffect extends OneShotEffect { // Locking in the Kjeldoran Guard (and its zcc), to be sacrificed later. Permanent guard = source.getSourcePermanentIfItStillExists(game); - if(guard != null) { + if (guard != null) { delayed.getEffects().setTargetPointer(new FixedTarget(guard, game)); } game.addDelayedTriggeredAbility(delayed, source); @@ -152,4 +148,4 @@ class KjeldoranGuardDelayedTriggeredAbility extends DelayedTriggeredAbility { public String getRule() { return "When that creature leaves the battlefield, Sacrifice {this}"; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/k/KjeldoranHomeGuard.java b/Mage.Sets/src/mage/cards/k/KjeldoranHomeGuard.java index 86a203e97b4..94204017100 100644 --- a/Mage.Sets/src/mage/cards/k/KjeldoranHomeGuard.java +++ b/Mage.Sets/src/mage/cards/k/KjeldoranHomeGuard.java @@ -1,24 +1,22 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EndOfCombatTriggeredAbility; import mage.abilities.condition.common.AttackedOrBlockedThisCombatSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.counters.CounterType; import mage.game.permanent.token.DeserterToken; import mage.watchers.common.AttackedOrBlockedThisCombatWatcher; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class KjeldoranHomeGuard extends CardImpl { @@ -32,11 +30,11 @@ public final class KjeldoranHomeGuard extends CardImpl { this.toughness = new MageInt(6); // At end of combat, if Kjeldoran Home Guard attacked or blocked this combat, put a -0/-1 counter on Kjeldoran Home Guard and put a 0/1 white Deserter creature token onto the battlefield. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EndOfCombatTriggeredAbility(new AddCountersSourceEffect(CounterType.M0M1.createInstance()), false), - AttackedOrBlockedThisCombatSourceCondition.instance, - "At end of combat, if {this} attacked or blocked this combat, put a -0/-1 counter on {this} and create a 0/1 white Deserter creature token."); - ability.addEffect(new CreateTokenEffect(new DeserterToken()).setText("and create a 0/1 white Deserter creature token.")); + Ability ability = new EndOfCombatTriggeredAbility( + new AddCountersSourceEffect(CounterType.M0M1.createInstance()), false + ).withInterveningIf(AttackedOrBlockedThisCombatSourceCondition.instance); + ability.addEffect(new CreateTokenEffect(new DeserterToken()) + .setText("and create a 0/1 white Deserter creature token.")); this.addAbility(ability, new AttackedOrBlockedThisCombatWatcher()); } diff --git a/Mage.Sets/src/mage/cards/k/KjeldoranPride.java b/Mage.Sets/src/mage/cards/k/KjeldoranPride.java index e952292516b..6773a890dbb 100644 --- a/Mage.Sets/src/mage/cards/k/KjeldoranPride.java +++ b/Mage.Sets/src/mage/cards/k/KjeldoranPride.java @@ -48,7 +48,7 @@ public final class KjeldoranPride extends CardImpl { // 2U: Attach Kjeldoran Pride to target creature other than enchanted creature. Ability ability = new SimpleActivatedAbility(new AttachEffect(Outcome.Benefit, "attach {this} to target " + filter.getMessage()), new ManaCostsImpl<>("{2}{U}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KjeldoranWarCry.java b/Mage.Sets/src/mage/cards/k/KjeldoranWarCry.java index 3185d1e0355..10711261803 100644 --- a/Mage.Sets/src/mage/cards/k/KjeldoranWarCry.java +++ b/Mage.Sets/src/mage/cards/k/KjeldoranWarCry.java @@ -1,7 +1,6 @@ package mage.cards.k; -import java.util.UUID; import mage.abilities.dynamicvalue.IntPlusDynamicValue; import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount; import mage.abilities.effects.Effect; @@ -14,8 +13,9 @@ import mage.filter.FilterCard; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.NamePredicate; +import java.util.UUID; + /** - * * @author L_J */ public final class KjeldoranWarCry extends CardImpl { @@ -27,12 +27,12 @@ public final class KjeldoranWarCry extends CardImpl { } public KjeldoranWarCry(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); // Creatures you control get +X/+X until end of turn, where X is 1 plus the number of cards named Kjeldoran War Cry in all graveyards. IntPlusDynamicValue value = new IntPlusDynamicValue(1, new CardsInAllGraveyardsCount(filter)); Effect effect = new BoostControlledEffect(value, value, Duration.EndOfTurn, new FilterCreaturePermanent("creatures"), false); - effect.setText("Creatures you control get +X/+X until end of turn, where X is 1 plus the number of cards named {this} in all graveyards"); + effect.setText("Creatures you control get +X/+X until end of turn, where X is 1 plus the number of cards named Kjeldoran War Cry in all graveyards"); this.getSpellAbility().addEffect(effect); } diff --git a/Mage.Sets/src/mage/cards/k/KnightOfTheEbonLegion.java b/Mage.Sets/src/mage/cards/k/KnightOfTheEbonLegion.java index 73aed41bc7c..d21814bed29 100644 --- a/Mage.Sets/src/mage/cards/k/KnightOfTheEbonLegion.java +++ b/Mage.Sets/src/mage/cards/k/KnightOfTheEbonLegion.java @@ -2,16 +2,16 @@ package mage.cards.k; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -46,12 +46,8 @@ public final class KnightOfTheEbonLegion extends CardImpl { this.addAbility(ability); // At the beginning of your end step, if a player lost 4 or more life this turn, put a +1/+1 counter on Knight of the Ebon Legion. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance()) - ), KnightOfTheEbonLegionCondition.instance, "At the beginning of your end step, " + - "if a player lost 4 or more life this turn, put a +1/+1 counter on {this}." - ).addHint(new ConditionHint(KnightOfTheEbonLegionCondition.instance, "A player lost 4 or more life this turn"))); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())) + .withInterveningIf(KnightOfTheEbonLegionCondition.instance).addHint(KnightOfTheEbonLegionCondition.getHint())); } private KnightOfTheEbonLegion(final KnightOfTheEbonLegion card) { @@ -66,6 +62,11 @@ public final class KnightOfTheEbonLegion extends CardImpl { enum KnightOfTheEbonLegionCondition implements Condition { instance; + private static final Hint hint = new ConditionHint(instance); + + public static Hint getHint() { + return hint; + } @Override public boolean apply(Game game, Ability source) { @@ -79,4 +80,9 @@ enum KnightOfTheEbonLegionCondition implements Condition { .stream() .anyMatch(uuid -> watcher.getLifeLost(uuid) > 3); } + + @Override + public String toString() { + return "a player lost 4 or more life this turn"; + } } diff --git a/Mage.Sets/src/mage/cards/k/KnightOfTheWhiteOrchid.java b/Mage.Sets/src/mage/cards/k/KnightOfTheWhiteOrchid.java index 699ae51f03a..aeac56a3b82 100644 --- a/Mage.Sets/src/mage/cards/k/KnightOfTheWhiteOrchid.java +++ b/Mage.Sets/src/mage/cards/k/KnightOfTheWhiteOrchid.java @@ -1,30 +1,32 @@ - - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.OpponentControlsMoreCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.common.FilterBySubtypeCard; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public final class KnightOfTheWhiteOrchid extends CardImpl { + private static final FilterCard filter = new FilterBySubtypeCard(SubType.PLAINS); + private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS); + public KnightOfTheWhiteOrchid(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.KNIGHT); @@ -33,13 +35,11 @@ public final class KnightOfTheWhiteOrchid extends CardImpl { // First strike this.addAbility(FirstStrikeAbility.getInstance()); - + // When Knight of the White Orchid enters the battlefield, if an opponent controls more lands than you, you may search your library for a Plains card, put it onto the battlefield, then shuffle your library. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(0, 1, new FilterBySubtypeCard(SubType.PLAINS)), false), true), - new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS), - "When {this} enters, if an opponent controls more lands than you, you may search your library for a Plains card, put it onto the battlefield, then shuffle.")); - + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter)), true + ).withInterveningIf(condition)); } private KnightOfTheWhiteOrchid(final KnightOfTheWhiteOrchid card) { diff --git a/Mage.Sets/src/mage/cards/k/KnightsOfRen.java b/Mage.Sets/src/mage/cards/k/KnightsOfRen.java index 7a97cc53d6f..302f74fa37b 100644 --- a/Mage.Sets/src/mage/cards/k/KnightsOfRen.java +++ b/Mage.Sets/src/mage/cards/k/KnightsOfRen.java @@ -1,15 +1,13 @@ package mage.cards.k; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; import mage.abilities.condition.common.HateCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.SacrificeAllEffect; import mage.abilities.keyword.MenaceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; @@ -35,18 +33,9 @@ public class KnightsOfRen extends CardImpl { //Hate — Whenever Knights of Ren enters the battlefield or attacks, if an opponent lost life from a source other //than combat damage this turn, you may have each player sacrifice a creature. - Ability abilityEnterBattlefield = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility( - new SacrificeAllEffect(StaticFilters.FILTER_PERMANENT_CREATURE), true), - HateCondition.instance, - "Hate — When {this} enters, if an opponent lost life from a source other than combat damage this turn, you may have each player sacrifice a creature"); - Ability abilityAttacks = new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility( - new SacrificeAllEffect(StaticFilters.FILTER_PERMANENT_CREATURE), true), - HateCondition.instance, - "Hate — When {this} attacks, if an opponent lost life from a source other than combat damage this turn, you may have each player sacrifice a creature"); - this.addAbility(abilityEnterBattlefield, new LifeLossOtherFromCombatWatcher()); - this.addAbility(abilityAttacks, new LifeLossOtherFromCombatWatcher()); + this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility( + new SacrificeAllEffect(StaticFilters.FILTER_PERMANENT_CREATURE).setText("have each player sacrifice a creature") + ).withInterveningIf(HateCondition.instance).setAbilityWord(AbilityWord.HATE), new LifeLossOtherFromCombatWatcher()); } private KnightsOfRen(final KnightsOfRen card) { diff --git a/Mage.Sets/src/mage/cards/k/KnucklesTheEchidna.java b/Mage.Sets/src/mage/cards/k/KnucklesTheEchidna.java new file mode 100644 index 00000000000..47a0d6e6354 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KnucklesTheEchidna.java @@ -0,0 +1,72 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.common.OneOrMoreCombatDamagePlayerTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.WinGameSourceControllerEffect; +import mage.abilities.hint.common.ArtifactYouControlHint; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.game.permanent.token.TreasureToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KnucklesTheEchidna extends CardImpl { + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledArtifactPermanent("you control thirty or more artifacts"), + ComparisonType.MORE_THAN, 29 + ); + + public KnucklesTheEchidna(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.ECHIDNA); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Double strike + this.addAbility(DoubleStrikeAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Whenever one or more creatures you control deal combat damage to a player, create a Treasure token. + this.addAbility(new OneOrMoreCombatDamagePlayerTriggeredAbility( + new CreateTokenEffect(new TreasureToken()), StaticFilters.FILTER_CONTROLLED_CREATURES + )); + + // Treasure Hunter -- At the beginning of your upkeep, if you control thirty or more artifacts, you win the game. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect()) + .withInterveningIf(condition).addHint(ArtifactYouControlHint.instance).withFlavorWord("Treasure Hunter")); + } + + private KnucklesTheEchidna(final KnucklesTheEchidna card) { + super(card); + } + + @Override + public KnucklesTheEchidna copy() { + return new KnucklesTheEchidna(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KodamaOfTheEastTree.java b/Mage.Sets/src/mage/cards/k/KodamaOfTheEastTree.java index a012f1f02d9..36ef81618e5 100644 --- a/Mage.Sets/src/mage/cards/k/KodamaOfTheEastTree.java +++ b/Mage.Sets/src/mage/cards/k/KodamaOfTheEastTree.java @@ -5,7 +5,6 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.PartnerAbility; @@ -18,8 +17,8 @@ import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterPermanentCard; -import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -35,7 +34,7 @@ import java.util.*; */ public final class KodamaOfTheEastTree extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent(); + private static final FilterPermanent filter = new FilterControlledPermanent("another permanent you control"); static { filter.add(AnotherPredicate.instance); @@ -53,12 +52,8 @@ public final class KodamaOfTheEastTree extends CardImpl { this.addAbility(ReachAbility.getInstance()); // Whenever another permanent you control enters, if it wasn't put onto the battlefield with this ability, you may put a permanent card with equal or lesser converted mana cost from your hand onto the battlefield. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldAllTriggeredAbility(new KodamaOfTheEastTreeEffect(), filter), - KodamaOfTheEastTreeCondition.instance, "Whenever another permanent enters the battlefield " + - "under your control, if it wasn't put onto the battlefield with this ability, you may put " + - "a permanent card with equal or lesser mana value from your hand onto the battlefield." - ), new KodamaOfTheEastTreeWatcher()); + this.addAbility(new EntersBattlefieldAllTriggeredAbility(new KodamaOfTheEastTreeEffect(), filter) + .withInterveningIf(KodamaOfTheEastTreeCondition.instance), new KodamaOfTheEastTreeWatcher()); // Partner this.addAbility(PartnerAbility.getInstance()); @@ -90,12 +85,18 @@ enum KodamaOfTheEastTreeCondition implements Condition { KodamaOfTheEastTreeWatcher watcher = game.getState().getWatcher(KodamaOfTheEastTreeWatcher.class); return watcher != null && !watcher.checkPermanent(permanent, source, game); } + + @Override + public String toString() { + return "it wasn't put onto the battlefield with this ability"; + } } class KodamaOfTheEastTreeEffect extends OneShotEffect { KodamaOfTheEastTreeEffect() { super(Outcome.Benefit); + staticText = "you may put a permanent card with equal or lesser mana value from your hand onto the battlefield"; } private KodamaOfTheEastTreeEffect(final KodamaOfTheEastTreeEffect effect) { diff --git a/Mage.Sets/src/mage/cards/k/KondasBanner.java b/Mage.Sets/src/mage/cards/k/KondasBanner.java index 5bd023fa298..ac60cf0bfe3 100644 --- a/Mage.Sets/src/mage/cards/k/KondasBanner.java +++ b/Mage.Sets/src/mage/cards/k/KondasBanner.java @@ -4,29 +4,31 @@ import mage.MageItem; import mage.abilities.Ability; import mage.abilities.common.AttachableToRestrictedAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.keyword.EquipAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Layer; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.List; import java.util.UUID; /** - * * @author LevelX */ public final class KondasBanner extends CardImpl { - private static final FilterControlledCreaturePermanent legendaryFilter = new FilterControlledCreaturePermanent("legendary creature"); + private static final FilterPermanent legendaryFilter = new FilterCreaturePermanent("legendary creature"); static { legendaryFilter.add(SuperType.LEGENDARY.getPredicate()); @@ -37,9 +39,8 @@ public final class KondasBanner extends CardImpl { this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.EQUIPMENT); - Target target = new TargetControlledCreaturePermanent(1, 1, legendaryFilter, false); // Konda's Banner can be attached only to a legendary creature. - this.addAbility(new AttachableToRestrictedAbility(target)); + this.addAbility(new AttachableToRestrictedAbility(new TargetPermanent(legendaryFilter))); // Creatures that share a color with equipped creature get +1/+1. this.addAbility(new SimpleStaticAbility(new KondasBannerColorBoostEffect())); @@ -48,8 +49,7 @@ public final class KondasBanner extends CardImpl { this.addAbility(new SimpleStaticAbility(new KondasBannerTypeBoostEffect())); // Equip {2} - this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2), target, false)); - + this.addAbility(new EquipAbility(2, false)); } private KondasBanner(final KondasBanner card) { diff --git a/Mage.Sets/src/mage/cards/k/KongmingsContraptions.java b/Mage.Sets/src/mage/cards/k/KongmingsContraptions.java index 7ebae6d9a1f..50be5503110 100644 --- a/Mage.Sets/src/mage/cards/k/KongmingsContraptions.java +++ b/Mage.Sets/src/mage/cards/k/KongmingsContraptions.java @@ -1,29 +1,35 @@ package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.CompoundCondition; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.AttackedThisStepCondition; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.PhaseStep; -import mage.constants.Zone; +import mage.constants.SubType; import mage.target.common.TargetAttackingCreature; import mage.watchers.common.PlayerAttackedStepWatcher; +import java.util.UUID; + /** - * * @author L_J */ public final class KongmingsContraptions extends CardImpl { + private static final Condition condition = new CompoundCondition( + "during the declare attackers step and only if you've been attacked this step", + new IsStepCondition(PhaseStep.DECLARE_ATTACKERS, false), + AttackedThisStepCondition.instance + ); + public KongmingsContraptions(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.subtype.add(SubType.HUMAN); @@ -32,10 +38,7 @@ public final class KongmingsContraptions extends CardImpl { this.toughness = new MageInt(4); // {T}: Kongming's Contraptions deals 2 damage to target attacking creature. Activate this ability only during the declare attackers step and only if you've been attacked this step. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new TapSourceCost(), - new CompoundCondition("during the declare attackers step and only if you've been attacked this step", - new IsStepCondition(PhaseStep.DECLARE_ATTACKERS, false), AttackedThisStepCondition.instance) - ); + Ability ability = new ActivateIfConditionActivatedAbility(new DamageTargetEffect(2), new TapSourceCost(), condition); ability.addTarget(new TargetAttackingCreature()); this.addAbility(ability, new PlayerAttackedStepWatcher()); } diff --git a/Mage.Sets/src/mage/cards/k/Kookus.java b/Mage.Sets/src/mage/cards/k/Kookus.java index 58f55d78a1a..ddb80115dea 100644 --- a/Mage.Sets/src/mage/cards/k/Kookus.java +++ b/Mage.Sets/src/mage/cards/k/Kookus.java @@ -1,41 +1,40 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.costs.mana.ColoredManaCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.combat.AttacksIfAbleSourceEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.constants.SubType; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ColoredManaSymbol; +import mage.constants.ComparisonType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.NamePredicate; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class Kookus extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("you don't control a creature named Keeper of Kookus"); static { filter.add(new NamePredicate("Keeper of Kookus")); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0); + public Kookus(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); @@ -47,18 +46,16 @@ public final class Kookus extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // At the beginning of your upkeep, if you don't control a creature named Keeper of Kookus, Kookus deals 3 damage to you and attacks this turn if able. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new DamageControllerEffect(3)); - ability.addEffect(new AttacksIfAbleSourceEffect(Duration.EndOfTurn, false)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - ability, - new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)), - "At the beginning of your upkeep, " - + "if you don't control a creature named Keeper of Kookus, " - + "{this} deals 3 damage to you and attacks this turn if able" - )); + Ability ability = new BeginningOfUpkeepTriggeredAbility(new DamageControllerEffect(3)).withInterveningIf(condition); + ability.addEffect(new AttacksIfAbleSourceEffect( + Duration.EndOfTurn, false + ).setText("and attacks this turn if able")); + this.addAbility(ability); // {R}: Kookus gets +1/+0 until end of turn. - this.addAbility(new SimpleActivatedAbility(new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ColoredManaCost(ColoredManaSymbol.R))); + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl<>("{R}") + )); } private Kookus(final Kookus card) { diff --git a/Mage.Sets/src/mage/cards/k/KorAeronaut.java b/Mage.Sets/src/mage/cards/k/KorAeronaut.java index 2743ee1b975..8f893a15e17 100644 --- a/Mage.Sets/src/mage/cards/k/KorAeronaut.java +++ b/Mage.Sets/src/mage/cards/k/KorAeronaut.java @@ -1,11 +1,9 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.KickerAbility; @@ -13,17 +11,17 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class KorAeronaut extends CardImpl { public KorAeronaut(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}"); this.subtype.add(SubType.KOR); this.subtype.add(SubType.SOLDIER); @@ -37,9 +35,11 @@ public final class KorAeronaut extends CardImpl { this.addAbility(FlyingAbility.getInstance()); //When Kor Aeronaut enters the battlefield, if it was kicked, target creature gains flying until end of turn. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), false); + Ability ability = new EntersBattlefieldTriggeredAbility( + new GainAbilityTargetEffect(FlyingAbility.getInstance()) + ).withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.ONCE, "When {this} enters, if it was kicked, target creature gains flying until end of turn.")); + this.addAbility(ability); } private KorAeronaut(final KorAeronaut card) { diff --git a/Mage.Sets/src/mage/cards/k/KorChant.java b/Mage.Sets/src/mage/cards/k/KorChant.java index d1128957a73..eae15e2e949 100644 --- a/Mage.Sets/src/mage/cards/k/KorChant.java +++ b/Mage.Sets/src/mage/cards/k/KorChant.java @@ -1,7 +1,5 @@ - package mage.cards.k; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.RedirectionEffect; import mage.cards.CardImpl; @@ -9,16 +7,16 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.other.AnotherTargetPredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; +import mage.target.TargetPermanent; import mage.target.TargetSource; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; /** - * * @author emerald000 */ public final class KorChant extends CardImpl { @@ -28,15 +26,8 @@ public final class KorChant extends CardImpl { // All damage that would be dealt this turn to target creature you control by a source of your choice is dealt to another target creature instead. this.getSpellAbility().addEffect(new KorChantEffect()); - TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(); - target.setTargetTag(1); - this.getSpellAbility().addTarget(target); - - FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); - filter.add(new AnotherTargetPredicate(2)); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter); - target2.setTargetTag(2); - this.getSpellAbility().addTarget(target2); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent().setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2).setTargetTag(2)); } private KorChant(final KorChant card) { @@ -55,7 +46,7 @@ class KorChantEffect extends RedirectionEffect { KorChantEffect() { super(Duration.EndOfTurn); - staticText = "All damage that would be dealt this turn to target creature you control by a source of your choice is dealt to another target creature instead"; + staticText = "all damage that would be dealt this turn to target creature you control by a source of your choice is dealt to another target creature instead"; } private KorChantEffect(final KorChantEffect effect) { diff --git a/Mage.Sets/src/mage/cards/k/KorDirge.java b/Mage.Sets/src/mage/cards/k/KorDirge.java index a08131260dc..90a31de93c2 100644 --- a/Mage.Sets/src/mage/cards/k/KorDirge.java +++ b/Mage.Sets/src/mage/cards/k/KorDirge.java @@ -1,7 +1,5 @@ - package mage.cards.k; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.RedirectionEffect; import mage.cards.CardImpl; @@ -9,16 +7,16 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.other.AnotherTargetPredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; +import mage.target.TargetPermanent; import mage.target.TargetSource; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; /** - * * @author emerald000 */ public final class KorDirge extends CardImpl { @@ -28,15 +26,8 @@ public final class KorDirge extends CardImpl { // All damage that would be dealt this turn to target creature you control by a source of your choice is dealt to another target creature instead. this.getSpellAbility().addEffect(new KorDirgeEffect()); - TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(); - target.setTargetTag(1); - this.getSpellAbility().addTarget(target); - - FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); - filter.add(new AnotherTargetPredicate(2)); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter); - target2.setTargetTag(2); - this.getSpellAbility().addTarget(target2); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent().setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2).setTargetTag(2)); } private KorDirge(final KorDirge card) { diff --git a/Mage.Sets/src/mage/cards/k/KorDuelist.java b/Mage.Sets/src/mage/cards/k/KorDuelist.java index f35a918b5a2..c493a238f70 100644 --- a/Mage.Sets/src/mage/cards/k/KorDuelist.java +++ b/Mage.Sets/src/mage/cards/k/KorDuelist.java @@ -1,8 +1,6 @@ package mage.cards.k; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -13,19 +11,21 @@ import mage.abilities.keyword.DoubleStrikeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.List; +import java.util.UUID; + /** * * @author North */ public final class KorDuelist extends CardImpl { - private static final String ruleText = "As long as Kor Duelist is equipped, it has double strike"; + private static final String ruleText = "As long as {this} is equipped, it has double strike"; public KorDuelist(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}"); diff --git a/Mage.Sets/src/mage/cards/k/KorEntanglers.java b/Mage.Sets/src/mage/cards/k/KorEntanglers.java index ad61f183308..0e806142244 100644 --- a/Mage.Sets/src/mage/cards/k/KorEntanglers.java +++ b/Mage.Sets/src/mage/cards/k/KorEntanglers.java @@ -11,8 +11,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -29,7 +32,7 @@ public final class KorEntanglers extends CardImpl { // Rally — Whenever Kor Entanglers or another Ally you control enters, tap target creature an opponent controls. Ability ability = new AllyEntersBattlefieldTriggeredAbility(new TapTargetEffect(), false); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KorHookmaster.java b/Mage.Sets/src/mage/cards/k/KorHookmaster.java index 64e80a529d4..1e043d23e3b 100644 --- a/Mage.Sets/src/mage/cards/k/KorHookmaster.java +++ b/Mage.Sets/src/mage/cards/k/KorHookmaster.java @@ -11,8 +11,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author North @@ -31,7 +34,7 @@ public final class KorHookmaster extends CardImpl { // That creature doesn't untap during its controller's next untap step. EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("that creature")); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KorLineSlinger.java b/Mage.Sets/src/mage/cards/k/KorLineSlinger.java index 35c54e7594d..bf1f15cb734 100644 --- a/Mage.Sets/src/mage/cards/k/KorLineSlinger.java +++ b/Mage.Sets/src/mage/cards/k/KorLineSlinger.java @@ -15,6 +15,7 @@ import mage.constants.ComparisonType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class KorLineSlinger extends CardImpl { this.toughness = new MageInt(1); Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KorSanctifiers.java b/Mage.Sets/src/mage/cards/k/KorSanctifiers.java index a994489cd4e..91f211ac78f 100644 --- a/Mage.Sets/src/mage/cards/k/KorSanctifiers.java +++ b/Mage.Sets/src/mage/cards/k/KorSanctifiers.java @@ -1,10 +1,9 @@ - package mage.cards.k; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; @@ -17,13 +16,12 @@ import mage.target.TargetPermanent; import java.util.UUID; /** - * * @author Loki */ public final class KorSanctifiers extends CardImpl { - public KorSanctifiers (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + public KorSanctifiers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.KOR); this.subtype.add(SubType.CLERIC); @@ -34,9 +32,9 @@ public final class KorSanctifiers extends CardImpl { this.addAbility(new KickerAbility("{W}")); // When Kor Sanctifiers enters the battlefield, if it was kicked, destroy target artifact or enchantment. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), false); + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()).withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.ONCE, "When {this} enters, if it was kicked, destroy target artifact or enchantment.")); + this.addAbility(ability); } private KorSanctifiers(final KorSanctifiers card) { diff --git a/Mage.Sets/src/mage/cards/k/KoskunFalls.java b/Mage.Sets/src/mage/cards/k/KoskunFalls.java index 263c52f2a9e..085d753fb0e 100644 --- a/Mage.Sets/src/mage/cards/k/KoskunFalls.java +++ b/Mage.Sets/src/mage/cards/k/KoskunFalls.java @@ -1,51 +1,38 @@ - package mage.cards.k; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.TapTargetCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; import mage.abilities.effects.common.combat.CantAttackYouUnlessPayAllEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SuperType; +import mage.filter.StaticFilters; import java.util.UUID; /** - * * @author fireshoes */ public final class KoskunFalls extends CardImpl { - - private static final FilterControlledCreaturePermanent filterCreature = new FilterControlledCreaturePermanent("untapped creature you control"); - - static { - filterCreature.add(TappedPredicate.UNTAPPED); - } public KoskunFalls(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); this.supertype.add(SuperType.WORLD); // At the beginning of your upkeep, sacrifice Koskun Falls unless you tap an untapped creature you control. - Effect effect = new SacrificeSourceUnlessPaysEffect(new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filterCreature, true))); - effect.setText("sacrifice Koskun Falls unless you tap an untapped creature you control"); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(effect)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new SacrificeSourceUnlessPaysEffect(new TapTargetCost(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE)) + )); // Creatures can't attack you unless their controller pays {2} for each creature they control that's attacking you. - this.addAbility(new SimpleStaticAbility( - Zone.BATTLEFIELD, - new CantAttackYouUnlessPayAllEffect( - Duration.WhileOnBattlefield, - new ManaCostsImpl<>("{2}") - ) - )); + this.addAbility(new SimpleStaticAbility(new CantAttackYouUnlessPayAllEffect( + Duration.WhileOnBattlefield, new GenericManaCost(2) + ))); } private KoskunFalls(final KoskunFalls card) { diff --git a/Mage.Sets/src/mage/cards/k/KotisTheFangkeeper.java b/Mage.Sets/src/mage/cards/k/KotisTheFangkeeper.java index ff609acbfcb..a95d43efa36 100644 --- a/Mage.Sets/src/mage/cards/k/KotisTheFangkeeper.java +++ b/Mage.Sets/src/mage/cards/k/KotisTheFangkeeper.java @@ -80,6 +80,8 @@ class KotisTheFangkeeperEffect extends OneShotEffect { controller.moveCards(cards, Zone.EXILED, source, game); FilterCard filter = new FilterCard(); filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, xValue + 1)); + game.processAction(); + cards.retainZone(Zone.EXILED, game); CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, filter); return true; } diff --git a/Mage.Sets/src/mage/cards/k/KozilekTheGreatDistortion.java b/Mage.Sets/src/mage/cards/k/KozilekTheGreatDistortion.java index a23bd556cb5..b8842f6f4b9 100644 --- a/Mage.Sets/src/mage/cards/k/KozilekTheGreatDistortion.java +++ b/Mage.Sets/src/mage/cards/k/KozilekTheGreatDistortion.java @@ -1,16 +1,12 @@ - package mage.cards.k; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInHandCondition; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CastSourceTriggeredAbility; import mage.abilities.effects.common.CounterTargetEffect; @@ -18,12 +14,7 @@ import mage.abilities.keyword.MenaceAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.ComparisonType; -import mage.constants.Outcome; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.FilterSpell; import mage.filter.predicate.mageobject.ManaValuePredicate; @@ -34,24 +25,27 @@ import mage.players.Player; import mage.target.TargetSpell; import mage.target.common.TargetCardInHand; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class KozilekTheGreatDistortion extends CardImpl { + private static final Condition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 7); + public KozilekTheGreatDistortion(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{8}{C}{C}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{8}{C}{C}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.ELDRAZI); this.power = new MageInt(12); this.toughness = new MageInt(12); // When you cast Kozilek, the Great Distortion, if you have fewer than seven cards in hand, draw cards equal to the difference. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new CastSourceTriggeredAbility(new KozilekDrawEffect(), false), - new CardsInHandCondition(ComparisonType.FEWER_THAN, 7), - "When you cast this spell, if you have fewer than seven cards in hand, draw cards equal to the difference.")); + this.addAbility(new CastSourceTriggeredAbility(new KozilekDrawEffect(), false).withInterveningIf(condition)); + // Menace this.addAbility(new MenaceAbility(false)); @@ -75,7 +69,7 @@ class KozilekDrawEffect extends OneShotEffect { KozilekDrawEffect() { super(Outcome.DrawCard); - this.staticText = "if you have fewer than seven cards in hand, draw cards equal to the difference"; + this.staticText = "draw cards equal to the difference"; } private KozilekDrawEffect(final KozilekDrawEffect effect) { @@ -148,7 +142,7 @@ class KozilekDiscardCost extends CostImpl { } } Player controller = game.getPlayer(ability.getControllerId()); - if(controller != null) { + if (controller != null) { for (Card card : controller.getHand().getCards(game)) { if (stackCMC.contains(card.getManaValue())) { return true; diff --git a/Mage.Sets/src/mage/cards/k/KozileksCommand.java b/Mage.Sets/src/mage/cards/k/KozileksCommand.java index fd0c2b9c9fa..b66c2b9b32f 100644 --- a/Mage.Sets/src/mage/cards/k/KozileksCommand.java +++ b/Mage.Sets/src/mage/cards/k/KozileksCommand.java @@ -19,6 +19,7 @@ import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.game.permanent.token.EldraziSpawnToken; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.TargetPlayer; import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetCreaturePermanent; @@ -91,7 +92,7 @@ enum KozileksCommandAdjuster implements TargetAdjuster { mode.getTargets().clear(); FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with mana value " + xValue + " or less"); filter.add(new ManaValuePredicate(ComparisonType.OR_LESS, xValue)); - mode.addTarget(new TargetCreaturePermanent(filter)); + mode.addTarget(new TargetPermanent(filter)); } if (target instanceof TargetCardInGraveyard) { mode.getTargets().clear(); @@ -100,4 +101,4 @@ enum KozileksCommandAdjuster implements TargetAdjuster { } } } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/k/KrileBaldesion.java b/Mage.Sets/src/mage/cards/k/KrileBaldesion.java index 577dbb8e1aa..d903845063f 100644 --- a/Mage.Sets/src/mage/cards/k/KrileBaldesion.java +++ b/Mage.Sets/src/mage/cards/k/KrileBaldesion.java @@ -75,6 +75,7 @@ enum KrileBaldesionPredicate implements ObjectSourcePlayerPredicate { return CardUtil .getEffectValueFromAbility(input.getSource(), "spellCast", Spell.class) .map(Spell::getManaValue) - .equals(input.getObject().getManaValue()); + .filter(x -> x == input.getObject().getManaValue()) + .isPresent(); } } diff --git a/Mage.Sets/src/mage/cards/k/KronchWrangler.java b/Mage.Sets/src/mage/cards/k/KronchWrangler.java index d483ffdf91e..ce8efe9add9 100644 --- a/Mage.Sets/src/mage/cards/k/KronchWrangler.java +++ b/Mage.Sets/src/mage/cards/k/KronchWrangler.java @@ -1,7 +1,7 @@ package mage.cards.k; import mage.MageInt; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; @@ -22,7 +22,7 @@ import java.util.UUID; public final class KronchWrangler extends CardImpl { private static final FilterPermanent filter - = new FilterControlledCreaturePermanent("a creature with power 4 or greater"); + = new FilterControlledCreaturePermanent("a creature you control with power 4 or greater"); static { filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); @@ -40,7 +40,7 @@ public final class KronchWrangler extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Whenever a creature with power 4 or greater you control enters, put a +1/+1 counter on Kronch Wrangler. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + this.addAbility(new EntersBattlefieldAllTriggeredAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter )); } diff --git a/Mage.Sets/src/mage/cards/k/KrondTheDawnClad.java b/Mage.Sets/src/mage/cards/k/KrondTheDawnClad.java index f9b705c9a23..2a674c115ae 100644 --- a/Mage.Sets/src/mage/cards/k/KrondTheDawnClad.java +++ b/Mage.Sets/src/mage/cards/k/KrondTheDawnClad.java @@ -1,12 +1,10 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.EnchantedSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.VigilanceAbility; @@ -17,14 +15,17 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class KrondTheDawnClad extends CardImpl { + private static final Condition condition = new EnchantedSourceCondition(); + public KrondTheDawnClad(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}{G}{G}{W}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{G}{G}{W}{W}{W}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.ARCHON); @@ -36,10 +37,8 @@ public final class KrondTheDawnClad extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // Whenever Krond the Dawn-Clad attacks, if it's enchanted, exile target permanent. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new ExileTargetEffect(), false), - new EnchantedSourceCondition(), - "Whenever {this} attacks, if it's enchanted, exile target permanent."); + Ability ability = new AttacksTriggeredAbility(new ExileTargetEffect(), false) + .withInterveningIf(condition).withRuleTextReplacement(true); ability.addTarget(new TargetPermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KrosanAvenger.java b/Mage.Sets/src/mage/cards/k/KrosanAvenger.java index 1b66837f024..c809242615b 100644 --- a/Mage.Sets/src/mage/cards/k/KrosanAvenger.java +++ b/Mage.Sets/src/mage/cards/k/KrosanAvenger.java @@ -3,7 +3,7 @@ package mage.cards.k; import mage.MageInt; import mage.abilities.condition.common.ThresholdCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.RegenerateSourceEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; @@ -31,7 +31,7 @@ public final class KrosanAvenger extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Threshold - {1}{G}: Regenerate Krosan Avenger. Activate this ability only if seven or more cards are in your graveyard. - this.addAbility(new ConditionalActivatedAbility( + this.addAbility(new ActivateIfConditionActivatedAbility( new RegenerateSourceEffect(), new ManaCostsImpl<>("{1}{G}"), ThresholdCondition.instance ).setAbilityWord(AbilityWord.THRESHOLD)); } diff --git a/Mage.Sets/src/mage/cards/k/KrosanConstrictor.java b/Mage.Sets/src/mage/cards/k/KrosanConstrictor.java index fcdba83d14d..2da3d9bb40f 100644 --- a/Mage.Sets/src/mage/cards/k/KrosanConstrictor.java +++ b/Mage.Sets/src/mage/cards/k/KrosanConstrictor.java @@ -17,6 +17,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -41,7 +42,7 @@ public final class KrosanConstrictor extends CardImpl { this.addAbility(new SwampwalkAbility()); // {tap}: Target black creature gets -2/-0 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(-2, -0, Duration.EndOfTurn), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KrosanDruid.java b/Mage.Sets/src/mage/cards/k/KrosanDruid.java index 1cfa762d0fc..9e13a8c6738 100644 --- a/Mage.Sets/src/mage/cards/k/KrosanDruid.java +++ b/Mage.Sets/src/mage/cards/k/KrosanDruid.java @@ -1,20 +1,18 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.keyword.KickerAbility; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class KrosanDruid extends CardImpl { @@ -31,11 +29,7 @@ public final class KrosanDruid extends CardImpl { this.addAbility(new KickerAbility("{4}{G}")); // When Krosan Druid enters the battlefield, if it was kicked, you gain 10 life. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new GainLifeEffect(10)), - KickedCondition.ONCE, - "When {this} enters, if it was kicked, you gain 10 life" - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(10)).withInterveningIf(KickedCondition.ONCE)); } private KrosanDruid(final KrosanDruid card) { diff --git a/Mage.Sets/src/mage/cards/k/KrosanGroundshaker.java b/Mage.Sets/src/mage/cards/k/KrosanGroundshaker.java index 0a8a6417c7c..b65f877c0dd 100644 --- a/Mage.Sets/src/mage/cards/k/KrosanGroundshaker.java +++ b/Mage.Sets/src/mage/cards/k/KrosanGroundshaker.java @@ -15,6 +15,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class KrosanGroundshaker extends CardImpl { // {G}: Target Beast creature gains trample until end of turn. Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{G}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KrosanRestorer.java b/Mage.Sets/src/mage/cards/k/KrosanRestorer.java index bc9d0d5640a..6e54b624263 100644 --- a/Mage.Sets/src/mage/cards/k/KrosanRestorer.java +++ b/Mage.Sets/src/mage/cards/k/KrosanRestorer.java @@ -5,7 +5,7 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.ThresholdCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.UntapTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -34,7 +34,7 @@ public final class KrosanRestorer extends CardImpl { this.addAbility(ability); // Threshold - {tap}: Untap up to three target lands. Activate this ability only if seven or more cards are in your graveyard. - ability = new ConditionalActivatedAbility(new UntapTargetEffect(), new TapSourceCost(), ThresholdCondition.instance); + ability = new ActivateIfConditionActivatedAbility(new UntapTargetEffect(), new TapSourceCost(), ThresholdCondition.instance); ability.addTarget(new TargetLandPermanent(0, 3)); ability.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/k/KrosanWarchief.java b/Mage.Sets/src/mage/cards/k/KrosanWarchief.java index cc836a57493..4d0bb62d357 100644 --- a/Mage.Sets/src/mage/cards/k/KrosanWarchief.java +++ b/Mage.Sets/src/mage/cards/k/KrosanWarchief.java @@ -16,6 +16,7 @@ import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterCreaturePermanent; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -45,7 +46,7 @@ public final class KrosanWarchief extends CardImpl { SimpleActivatedAbility ability = new SimpleActivatedAbility( new RegenerateTargetEffect(), new ManaCostsImpl<>("{1}{G}")); - Target target = new TargetCreaturePermanent(filterTarget); + Target target = new TargetPermanent(filterTarget); ability.addTarget(target); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KrovikanPlague.java b/Mage.Sets/src/mage/cards/k/KrovikanPlague.java index ea0ee8d0be0..d0278d074a2 100644 --- a/Mage.Sets/src/mage/cards/k/KrovikanPlague.java +++ b/Mage.Sets/src/mage/cards/k/KrovikanPlague.java @@ -1,11 +1,10 @@ - package mage.cards.k; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.AttachedToMatchesFilterCondition; import mage.abilities.costs.common.TapAttachedCost; import mage.abilities.effects.common.AttachEffect; @@ -17,60 +16,63 @@ import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Outcome; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.TappedPredicate; import mage.target.TargetPermanent; -import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author L_J */ public final class KrovikanPlague extends CardImpl { - - private static final FilterControlledCreaturePermanent filterNonWall = new FilterControlledCreaturePermanent("non-Wall creature you control"); + + private static final FilterPermanent filterNonWall = new FilterControlledCreaturePermanent("non-Wall creature you control"); static { filterNonWall.add(Predicates.not(SubType.WALL.getPredicate())); } - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("enchanted creature is untapped"); - + private static final FilterPermanent filter = new FilterCreaturePermanent("enchanted creature is untapped"); + static { filter.add(TappedPredicate.UNTAPPED); } + private static final Condition condition = new AttachedToMatchesFilterCondition(filter); + public KrovikanPlague(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}"); this.subtype.add(SubType.AURA); // Enchant non-Wall creature you control - TargetPermanent auraTarget = new TargetControlledCreaturePermanent(filterNonWall); + TargetPermanent auraTarget = new TargetPermanent(filterNonWall); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget)); // When Krovikan Plague enters the battlefield, draw a card at the beginning of the next turn's upkeep. this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( - new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1), Duration.OneUse)) - .setText("draw a card at the beginning of the next turn's upkeep"), false)); + new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1), Duration.OneUse) + ).setText("draw a card at the beginning of the next turn's upkeep"), false)); // Tap enchanted creature: Tap enchanted creature: Krovikan Plague deals 1 damage to any target. Put a -0/-1 counter on enchanted creature. Activate this ability only if enchanted creature is untapped. - Ability ability2 = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new DamageTargetEffect(1), new TapAttachedCost(), new AttachedToMatchesFilterCondition(filter)); - ability2.addEffect(new AddCountersAttachedEffect(CounterType.M0M1.createInstance(),"enchanted creature")); - ability2.addTarget(new TargetAnyTarget()); - this.addAbility(ability2); - + Ability ability = new ActivateIfConditionActivatedAbility( + new DamageTargetEffect(1), new TapAttachedCost(), condition + ); + ability.addEffect(new AddCountersAttachedEffect( + CounterType.M0M1.createInstance(), "enchanted creature" + )); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); } private KrovikanPlague(final KrovikanPlague card) { diff --git a/Mage.Sets/src/mage/cards/k/KrovikanRot.java b/Mage.Sets/src/mage/cards/k/KrovikanRot.java index 126d4761177..e88e977b93f 100644 --- a/Mage.Sets/src/mage/cards/k/KrovikanRot.java +++ b/Mage.Sets/src/mage/cards/k/KrovikanRot.java @@ -11,6 +11,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -30,7 +31,7 @@ public final class KrovikanRot extends CardImpl { // Destroy target creature with power 2 or less. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Recover {1}{B}{B} this.addAbility(new RecoverAbility(new ManaCostsImpl<>("{1}{B}{B}"), this)); diff --git a/Mage.Sets/src/mage/cards/k/KrovikanVampire.java b/Mage.Sets/src/mage/cards/k/KrovikanVampire.java index c33596292f8..026b2777100 100644 --- a/Mage.Sets/src/mage/cards/k/KrovikanVampire.java +++ b/Mage.Sets/src/mage/cards/k/KrovikanVampire.java @@ -126,7 +126,7 @@ class KrovikanVampireInterveningIfCondition implements Condition { @Override public String toString() { - return "if a creature dealt damage by Krovikan Vampire this turn died"; + return "if a creature dealt damage by {this} this turn died"; } } diff --git a/Mage.Sets/src/mage/cards/k/KuldothaPhoenix.java b/Mage.Sets/src/mage/cards/k/KuldothaPhoenix.java index cebeb77a74d..8fa398e7cd2 100644 --- a/Mage.Sets/src/mage/cards/k/KuldothaPhoenix.java +++ b/Mage.Sets/src/mage/cards/k/KuldothaPhoenix.java @@ -3,17 +3,21 @@ package mage.cards.k; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.CompoundCondition; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.condition.common.MetalcraftCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; import mage.abilities.hint.common.MetalcraftHint; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; import java.util.UUID; @@ -22,6 +26,11 @@ import java.util.UUID; */ public final class KuldothaPhoenix extends CardImpl { + private static final Condition condition = new CompoundCondition( + "during your upkeep and only if you control three or more artifacts", + IsStepCondition.getMyUpkeep(), MetalcraftCondition.instance + ); + public KuldothaPhoenix(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}{R}"); this.subtype.add(SubType.PHOENIX); @@ -35,11 +44,9 @@ public final class KuldothaPhoenix extends CardImpl { // Metalcraft — {4}: Return Kuldotha Phoenix from your graveyard to the battlefield. // Activate this ability only during your upkeep and only if you control three or more artifacts. - Ability ability = new ConditionalActivatedAbility(Zone.GRAVEYARD, + Ability ability = new ActivateIfConditionActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(false, false), - new ManaCostsImpl<>("{4}"), - new CompoundCondition("during your upkeep and only if you control three or more artifacts", - new IsStepCondition(PhaseStep.UPKEEP), MetalcraftCondition.instance) + new ManaCostsImpl<>("{4}"), condition ); ability.setAbilityWord(AbilityWord.METALCRAFT); ability.addHint(MetalcraftHint.instance); @@ -54,5 +61,4 @@ public final class KuldothaPhoenix extends CardImpl { public KuldothaPhoenix copy() { return new KuldothaPhoenix(this); } - -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/k/KyloRen.java b/Mage.Sets/src/mage/cards/k/KyloRen.java index 0ae7cc7dac3..b6074fbd302 100644 --- a/Mage.Sets/src/mage/cards/k/KyloRen.java +++ b/Mage.Sets/src/mage/cards/k/KyloRen.java @@ -6,7 +6,6 @@ import mage.abilities.common.AttacksEachCombatStaticAbility; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.FirstStrikeAbility; @@ -23,7 +22,7 @@ import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPre import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -58,11 +57,9 @@ public final class KyloRen extends CardImpl { // Whenever Kylo Ren attacks, it gets +1/+0 for each creature in your graveyard and you may tap target creature defending player controls. CardsInControllerGraveyardCount value = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURE); - Effect effect = new BoostSourceEffect(value, StaticValue.get(0), Duration.WhileOnBattlefield); - effect.setText("it gets +1/+0 for each creature in your graveyard"); - Ability ability = new AttacksTriggeredAbility(effect, false); + Ability ability = new AttacksTriggeredAbility(new BoostSourceEffect(value, StaticValue.get(0), Duration.WhileOnBattlefield).setText("it gets +1/+0 for each creature in your graveyard")); ability.addEffect(new KyloRenTapTargetEffect()); - ability.addTarget(new TargetCreaturePermanent(0, 1, filter, false)); + ability.addTarget(new TargetPermanent(0, 1, filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KyloxVisionaryInventor.java b/Mage.Sets/src/mage/cards/k/KyloxVisionaryInventor.java index 871529737e2..00e094f447c 100644 --- a/Mage.Sets/src/mage/cards/k/KyloxVisionaryInventor.java +++ b/Mage.Sets/src/mage/cards/k/KyloxVisionaryInventor.java @@ -110,6 +110,8 @@ class KyloxVisionaryInventorEffect extends OneShotEffect { return true; } player.moveCards(cards, Zone.EXILED, source, game); + game.processAction(); + cards.retainZone(Zone.EXILED, game); CardUtil.castMultipleWithAttributeForFree( player, source, game, cards, StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY diff --git a/Mage.Sets/src/mage/cards/k/KyrenNegotiations.java b/Mage.Sets/src/mage/cards/k/KyrenNegotiations.java index 70b3f95e24e..a99463dd172 100644 --- a/Mage.Sets/src/mage/cards/k/KyrenNegotiations.java +++ b/Mage.Sets/src/mage/cards/k/KyrenNegotiations.java @@ -1,6 +1,5 @@ package mage.cards.k; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapTargetCost; @@ -8,31 +7,22 @@ import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.filter.StaticFilters; import mage.target.common.TargetPlayerOrPlaneswalker; +import java.util.UUID; + /** - * * @author ingmargoudt */ public final class KyrenNegotiations extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); - - static { - filter.add(TappedPredicate.UNTAPPED); - } - public KyrenNegotiations(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}{R}"); // Tap an untapped creature you control: Kyren Negotiations deals 1 damage to target player. Ability ability = new SimpleActivatedAbility( - new DamageTargetEffect(1), - new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, false)) + new DamageTargetEffect(1), new TapTargetCost(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE) ); ability.addTarget(new TargetPlayerOrPlaneswalker()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/k/KytheonHeroOfAkros.java b/Mage.Sets/src/mage/cards/k/KytheonHeroOfAkros.java index 7e0f854d9b6..56c4872994e 100644 --- a/Mage.Sets/src/mage/cards/k/KytheonHeroOfAkros.java +++ b/Mage.Sets/src/mage/cards/k/KytheonHeroOfAkros.java @@ -1,17 +1,11 @@ - package mage.cards.k; -import java.util.UUID; - import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; -import mage.constants.Pronoun; import mage.abilities.common.EndOfCombatTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ExileAndReturnSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.IndestructibleAbility; @@ -20,9 +14,10 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.watchers.common.AttackedOrBlockedThisCombatWatcher; +import java.util.UUID; + /** * @author LevelX2 */ @@ -41,12 +36,14 @@ public final class KytheonHeroOfAkros extends CardImpl { // At end of combat, if Kytheon, Hero of Akros and at least two other creatures attacked this combat, exile Kytheon, // then return him to the battlefield transformed under his owner's control. this.addAbility(new TransformAbility()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EndOfCombatTriggeredAbility(new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED,Pronoun.HE), false), - new KytheonHeroOfAkrosCondition(), "At end of combat, if {this} and at least two other creatures attacked this combat, exile {this}, " - + "then return him to the battlefield transformed under his owner's control."), new AttackedOrBlockedThisCombatWatcher()); + this.addAbility(new EndOfCombatTriggeredAbility( + new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.HE), false + ).withInterveningIf(KytheonHeroOfAkrosCondition.instance), new AttackedOrBlockedThisCombatWatcher()); // {2}{W}: Kytheon gains indestructible until end of turn. - this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{2}{W}"))); + this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl<>("{2}{W}"))); } @@ -60,27 +57,20 @@ public final class KytheonHeroOfAkros extends CardImpl { } } -class KytheonHeroOfAkrosCondition implements Condition { +enum KytheonHeroOfAkrosCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { - Permanent sourceObject = game.getPermanent(source.getSourceId()); - if (sourceObject != null) { - AttackedOrBlockedThisCombatWatcher watcher = game.getState().getWatcher(AttackedOrBlockedThisCombatWatcher.class); - if (watcher != null) { - boolean sourceFound = false; - int number = 0; - for (MageObjectReference mor : watcher.getAttackedThisTurnCreatures()) { - if (mor.refersTo(sourceObject, game)) { - sourceFound = true; - } else { - number++; - } - } - return sourceFound && number >= 2; - } - } - return false; + AttackedOrBlockedThisCombatWatcher watcher = game.getState().getWatcher(AttackedOrBlockedThisCombatWatcher.class); + return watcher != null + && watcher + .getAttackedThisTurnCreatures() + .stream() + .anyMatch(mor -> mor.refersTo(source, game)) + && watcher + .getAttackedThisTurnCreatures() + .size() >= 3; } @Override diff --git a/Mage.Sets/src/mage/cards/l/LadySun.java b/Mage.Sets/src/mage/cards/l/LadySun.java index 98110b6b2bf..a409c8bead9 100644 --- a/Mage.Sets/src/mage/cards/l/LadySun.java +++ b/Mage.Sets/src/mage/cards/l/LadySun.java @@ -1,13 +1,10 @@ - package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.MyTurnBeforeAttackersDeclaredCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.ReturnToHandSourceEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; @@ -15,24 +12,18 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author fireshoes */ public final class LadySun extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); - static { - filter.add(AnotherPredicate.instance); - } public LadySun(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ADVISOR); @@ -40,14 +31,12 @@ public final class LadySun extends CardImpl { this.toughness = new MageInt(1); // {tap}: Return Lady Sun and another target creature to their owners' hands. Activate this ability only during your turn, before attackers are declared. - Effect effect = new ReturnToHandSourceEffect(true); - effect.setText("Return Lady Sun"); - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - effect, new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); - effect = new ReturnToHandTargetEffect(); - effect.setText("and another target creature to their owners' hands"); - ability.addTarget(new TargetCreaturePermanent(filter)); - ability.addEffect(effect); + Ability ability = new ActivateIfConditionActivatedAbility( + new ReturnToHandSourceEffect(true).setText("return {this}"), + new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance + ); + ability.addEffect(new ReturnToHandTargetEffect().setText("and another target creature to their owners' hands")); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/l/LagomosHandOfHatred.java b/Mage.Sets/src/mage/cards/l/LagomosHandOfHatred.java index e86e80c5a35..3fd94e32bce 100644 --- a/Mage.Sets/src/mage/cards/l/LagomosHandOfHatred.java +++ b/Mage.Sets/src/mage/cards/l/LagomosHandOfHatred.java @@ -1,19 +1,21 @@ package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.SacrificeTargetEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; -import mage.constants.*; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.Elemental21TrampleHasteToken; @@ -22,8 +24,9 @@ import mage.target.common.TargetCardInLibrary; import mage.target.targetpointer.FixedTarget; import mage.watchers.common.CreaturesDiedWatcher; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class LagomosHandOfHatred extends CardImpl { @@ -41,11 +44,9 @@ public final class LagomosHandOfHatred extends CardImpl { this.addAbility(new BeginningOfCombatTriggeredAbility(new LagomosHandOfHatredEffect())); // {T}: Search your library for a card, put it into your hand, then shuffle. Activate only if five or more creatures died this turn. - this.addAbility(new ConditionalActivatedAbility( - Zone.BATTLEFIELD, + this.addAbility(new ActivateIfConditionActivatedAbility( new SearchLibraryPutInHandEffect(new TargetCardInLibrary(), false), - new TapSourceCost(), - LagomosHandOfHatredCondition.instance + new TapSourceCost(), LagomosHandOfHatredCondition.instance )); } diff --git a/Mage.Sets/src/mage/cards/l/LagonnaBandElder.java b/Mage.Sets/src/mage/cards/l/LagonnaBandElder.java index 2c6fba72e17..ac751cbcbe9 100644 --- a/Mage.Sets/src/mage/cards/l/LagonnaBandElder.java +++ b/Mage.Sets/src/mage/cards/l/LagonnaBandElder.java @@ -1,17 +1,15 @@ - package mage.cards.l; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledEnchantmentPermanent; import java.util.UUID; @@ -20,6 +18,10 @@ import java.util.UUID; */ public final class LagonnaBandElder extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledEnchantmentPermanent("you control an enchantment") + ); + public LagonnaBandElder(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.CENTAUR); @@ -29,11 +31,7 @@ public final class LagonnaBandElder extends CardImpl { this.toughness = new MageInt(2); // When Lagonna-Band Elder enters the battlefield, if you control an enchantment, you gain 3 life. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3), false), - new PermanentsOnTheBattlefieldCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), - "When Lagonna-Band Elder enters the battlefield, if you control an enchantment, you gain 3 life"); - this.addAbility(ability); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3), false).withInterveningIf(condition)); } private LagonnaBandElder(final LagonnaBandElder card) { diff --git a/Mage.Sets/src/mage/cards/l/LagonnaBandTrailblazer.java b/Mage.Sets/src/mage/cards/l/LagonnaBandTrailblazer.java index 16b57d7bd8a..0dbc89655be 100644 --- a/Mage.Sets/src/mage/cards/l/LagonnaBandTrailblazer.java +++ b/Mage.Sets/src/mage/cards/l/LagonnaBandTrailblazer.java @@ -26,7 +26,8 @@ public final class LagonnaBandTrailblazer extends CardImpl { this.toughness = new MageInt(4); // Heroic — Whenever you cast a spell that targets Lagonna-Band Trailblazer, put a +1/+1 counter on Lagonna-Band Trailblzer. - this.addAbility(new HeroicAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()))); + this.addAbility(new HeroicAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())) + .withRuleTextReplacement(true)); } private LagonnaBandTrailblazer(final LagonnaBandTrailblazer card) { diff --git a/Mage.Sets/src/mage/cards/l/LairwatchGiant.java b/Mage.Sets/src/mage/cards/l/LairwatchGiant.java index f4aa0406d1e..04e4a82d0c0 100644 --- a/Mage.Sets/src/mage/cards/l/LairwatchGiant.java +++ b/Mage.Sets/src/mage/cards/l/LairwatchGiant.java @@ -1,7 +1,6 @@ package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleStaticAbility; @@ -15,9 +14,10 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; +import java.util.UUID; + /** * * @author Styxo @@ -81,6 +81,6 @@ class LairwatchGiantTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever Lairwatch Giant blocks two or more creatures, it gains first strike until end of turn."; + return "Whenever {this} blocks two or more creatures, it gains first strike until end of turn."; } } diff --git a/Mage.Sets/src/mage/cards/l/LamplighterOfSelhoff.java b/Mage.Sets/src/mage/cards/l/LamplighterOfSelhoff.java index ba96ccaa275..400d96dcb94 100644 --- a/Mage.Sets/src/mage/cards/l/LamplighterOfSelhoff.java +++ b/Mage.Sets/src/mage/cards/l/LamplighterOfSelhoff.java @@ -1,47 +1,45 @@ - package mage.cards.l; import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import java.util.UUID; /** - * * @author fireshoes */ public final class LamplighterOfSelhoff extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("another Zombie"); + private static final FilterPermanent filter + = new FilterControlledPermanent(SubType.ZOMBIE, "you control another Zombie"); static { filter.add(AnotherPredicate.instance); - filter.add(SubType.ZOMBIE.getPredicate()); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + public LamplighterOfSelhoff(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.HORROR); this.power = new MageInt(3); this.toughness = new MageInt(5); // When Lamplighter of Selhoff enters the battlefield, if you control another Zombie, you may a draw card. If you do, discard a card. - TriggeredAbility triggeredAbility = new EntersBattlefieldTriggeredAbility(new DrawDiscardControllerEffect(1,1,true)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - triggeredAbility, - new PermanentsOnTheBattlefieldCondition(filter), - "When {this} enters, if you control another Zombie, you may draw a card. If you do, discard a card.")); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new DrawDiscardControllerEffect(1, 1, true) + ).withInterveningIf(condition)); } private LamplighterOfSelhoff(final LamplighterOfSelhoff card) { diff --git a/Mage.Sets/src/mage/cards/l/LandTax.java b/Mage.Sets/src/mage/cards/l/LandTax.java index 8c31da5582c..93bfd709c87 100644 --- a/Mage.Sets/src/mage/cards/l/LandTax.java +++ b/Mage.Sets/src/mage/cards/l/LandTax.java @@ -1,10 +1,9 @@ - package mage.cards.l; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.OpponentControlsMoreCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -14,21 +13,19 @@ import mage.target.common.TargetCardInLibrary; import java.util.UUID; /** - * * @author LevelX2 */ public final class LandTax extends CardImpl { + private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS); + public LandTax(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); // At the beginning of your upkeep, if an opponent controls more lands than you, you may search your library for up to three basic land cards, reveal them, and put them into your hand. If you do, shuffle your library. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(0, 3, StaticFilters.FILTER_CARD_BASIC_LAND), true), true), - new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS), - "At the beginning of your upkeep, if an opponent controls more lands than you, you may search your library for up to three basic land cards, reveal them, put them into your hand, then shuffle." - )); - + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SearchLibraryPutInHandEffect( + new TargetCardInLibrary(0, 3, StaticFilters.FILTER_CARD_BASIC_LANDS), true + ), true).withInterveningIf(condition)); } private LandTax(final LandTax card) { diff --git a/Mage.Sets/src/mage/cards/l/LandoCalrissian.java b/Mage.Sets/src/mage/cards/l/LandoCalrissian.java index 4be46578402..99f7224a10e 100644 --- a/Mage.Sets/src/mage/cards/l/LandoCalrissian.java +++ b/Mage.Sets/src/mage/cards/l/LandoCalrissian.java @@ -13,6 +13,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -46,7 +47,7 @@ public final class LandoCalrissian extends CardImpl { effect = new GainAbilityTargetEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn); effect.setText("and gains vigilance until end of turn"); ability.addEffect(effect); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/l/LandrovalHorizonWitness.java b/Mage.Sets/src/mage/cards/l/LandrovalHorizonWitness.java index 2766a625627..324ac56eca3 100644 --- a/Mage.Sets/src/mage/cards/l/LandrovalHorizonWitness.java +++ b/Mage.Sets/src/mage/cards/l/LandrovalHorizonWitness.java @@ -1,19 +1,18 @@ package mage.cards.l; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.common.AttacksPlayerWithCreaturesTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterAttackingCreature; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.game.Game; -import mage.game.events.DefenderAttackedEvent; -import mage.game.events.GameEvent; import mage.target.TargetPermanent; import java.util.UUID; @@ -23,6 +22,12 @@ import java.util.UUID; */ public final class LandrovalHorizonWitness extends CardImpl { + private static final FilterPermanent filter + = new FilterAttackingCreature("attacking creature without flying"); + + static { + filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); + } public LandrovalHorizonWitness(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); @@ -36,7 +41,11 @@ public final class LandrovalHorizonWitness extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever two or more creatures you control attack a player, target attacking creature without flying gains flying until end of turn. - this.addAbility(new LandrovalHorizonWitnessTriggeredAbility()); + Ability ability = new AttacksPlayerWithCreaturesTriggeredAbility( + new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), + 2, StaticFilters.FILTER_CONTROLLED_CREATURES, SetTargetPointer.NONE, false); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); } private LandrovalHorizonWitness(final LandrovalHorizonWitness card) { @@ -48,40 +57,3 @@ public final class LandrovalHorizonWitness extends CardImpl { return new LandrovalHorizonWitness(this); } } - -class LandrovalHorizonWitnessTriggeredAbility extends TriggeredAbilityImpl { - - private static final FilterPermanent filter - = new FilterAttackingCreature("attacking creature without flying"); - - static { - filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); - } - - LandrovalHorizonWitnessTriggeredAbility() { - super(Zone.BATTLEFIELD, new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); - this.addTarget(new TargetPermanent(filter)); - setTriggerPhrase("Whenever two or more creatures you control attack a player, "); - } - - private LandrovalHorizonWitnessTriggeredAbility(final LandrovalHorizonWitnessTriggeredAbility ability) { - super(ability); - } - - @Override - public LandrovalHorizonWitnessTriggeredAbility copy() { - return new LandrovalHorizonWitnessTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DEFENDER_ATTACKED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - return isControlledBy(event.getPlayerId()) - && game.getPlayer(event.getTargetId()) != null - && ((DefenderAttackedEvent) event).getAttackers(game).size() >= 2; - } -} diff --git a/Mage.Sets/src/mage/cards/l/LashOut.java b/Mage.Sets/src/mage/cards/l/LashOut.java index addead2ad54..7efb79e5419 100644 --- a/Mage.Sets/src/mage/cards/l/LashOut.java +++ b/Mage.Sets/src/mage/cards/l/LashOut.java @@ -42,7 +42,7 @@ class LashOutEffect extends OneShotEffect { LashOutEffect() { super(Outcome.Damage); - this.staticText = "Lash Out deals 3 damage to target creature. Clash with an opponent. If you win, Lash Out deals 3 damage to that creature's controller"; + this.staticText = "{this} deals 3 damage to target creature. Clash with an opponent. If you win, {this} deals 3 damage to that creature's controller"; } private LashOutEffect(final LashOutEffect effect) { diff --git a/Mage.Sets/src/mage/cards/l/LastNightTogether.java b/Mage.Sets/src/mage/cards/l/LastNightTogether.java index 3b804fc0b31..c1efbf98e17 100644 --- a/Mage.Sets/src/mage/cards/l/LastNightTogether.java +++ b/Mage.Sets/src/mage/cards/l/LastNightTogether.java @@ -134,4 +134,4 @@ class LastNightTogetherDelayedCantAttackAbility extends DelayedTriggeredAbility public String getRule() { return "Only the chosen creatures can attack during that combat phase"; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/l/LastStand.java b/Mage.Sets/src/mage/cards/l/LastStand.java index 80540eff916..5d7e868c46a 100644 --- a/Mage.Sets/src/mage/cards/l/LastStand.java +++ b/Mage.Sets/src/mage/cards/l/LastStand.java @@ -1,7 +1,6 @@ package mage.cards.l; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; @@ -18,6 +17,8 @@ import mage.players.Player; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** * * @author LevelX2 @@ -60,7 +61,7 @@ class LastStandEffect extends OneShotEffect { public LastStandEffect() { super(Outcome.Benefit); - this.staticText = "Target opponent loses 2 life for each Swamp you control. Last Stand deals damage to target creature equal to the number of Mountains you control. Create a 1/1 green Saproling creature token for each Forest you control. You gain 2 life for each Plains you control. Draw a card for each Island you control, then discard that many cards"; + this.staticText = "Target opponent loses 2 life for each Swamp you control. {this} deals damage to target creature equal to the number of Mountains you control. Create a 1/1 green Saproling creature token for each Forest you control. You gain 2 life for each Plains you control. Draw a card for each Island you control, then discard that many cards"; } private LastStandEffect(final LastStandEffect effect) { diff --git a/Mage.Sets/src/mage/cards/l/LatchkeyFaerie.java b/Mage.Sets/src/mage/cards/l/LatchkeyFaerie.java index 7773d7ee2c8..d6bc12909d0 100644 --- a/Mage.Sets/src/mage/cards/l/LatchkeyFaerie.java +++ b/Mage.Sets/src/mage/cards/l/LatchkeyFaerie.java @@ -3,7 +3,6 @@ package mage.cards.l; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.ProwlCostWasPaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.hint.common.ProwlCostWasPaidHint; import mage.abilities.keyword.FlyingAbility; @@ -35,11 +34,8 @@ public final class LatchkeyFaerie extends CardImpl { this.addAbility(new ProwlAbility("{2}{U}")); // When Latchkey Faerie enters the battlefield, if its prowl cost was paid, draw a card. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1), false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, ProwlCostWasPaidCondition.instance, - "When {this} enters, if its prowl cost was paid, draw a card.") - .addHint(ProwlCostWasPaidHint.instance)); - + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1), false) + .withInterveningIf(ProwlCostWasPaidCondition.instance).addHint(ProwlCostWasPaidHint.instance)); } private LatchkeyFaerie(final LatchkeyFaerie card) { diff --git a/Mage.Sets/src/mage/cards/l/LathielTheBounteousDawn.java b/Mage.Sets/src/mage/cards/l/LathielTheBounteousDawn.java index 20e73478ede..60cbe63c923 100644 --- a/Mage.Sets/src/mage/cards/l/LathielTheBounteousDawn.java +++ b/Mage.Sets/src/mage/cards/l/LathielTheBounteousDawn.java @@ -2,21 +2,19 @@ package mage.cards.l; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.YouGainedLifeCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.effects.Effect; +import mage.abilities.dynamicvalue.common.ControllerGainedLifeCount; import mage.abilities.effects.common.counter.DistributeCountersEffect; -import mage.abilities.hint.Hint; -import mage.abilities.hint.ValueHint; import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.TargetController; import mage.filter.StaticFilters; -import mage.game.Game; import mage.target.common.TargetCreaturePermanentAmount; import mage.watchers.common.PlayerGainedLifeWatcher; @@ -41,15 +39,17 @@ public final class LathielTheBounteousDawn extends CardImpl { this.addAbility(LifelinkAbility.getInstance()); // At the beginning of each end step, if you gained life this turn, distribute up to that many +1/+1 counters among any number of other target creatures. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility(TargetController.ANY, new DistributeCountersEffect(), false), - condition, "At the beginning of each end step, if you gained life this turn, " + - "distribute up to that many +1/+1 counters among any number of other target creatures." - ); + Ability ability = new BeginningOfEndStepTriggeredAbility( + TargetController.ANY, new DistributeCountersEffect() + .setText("distribute up to that many +1/+1 counters " + + "among any number of other target creatures"), + false + ).withInterveningIf(condition); ability.addTarget(new TargetCreaturePermanentAmount( - LathielTheBounteousDawnValue.instance, - StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); - this.addAbility(ability.addHint(LathielTheBounteousDawnValue.getHint()), new PlayerGainedLifeWatcher()); + ControllerGainedLifeCount.instance, + StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE + )); + this.addAbility(ability.addHint(ControllerGainedLifeCount.getHint()), new PlayerGainedLifeWatcher()); } private LathielTheBounteousDawn(final LathielTheBounteousDawn card) { @@ -61,28 +61,3 @@ public final class LathielTheBounteousDawn extends CardImpl { return new LathielTheBounteousDawn(this); } } - -enum LathielTheBounteousDawnValue implements DynamicValue { - instance; - private static final Hint hint = new ValueHint("Life gained this turn", instance); - - @Override - public int calculate(Game game, Ability sourceAbility, Effect effect) { - PlayerGainedLifeWatcher watcher = game.getState().getWatcher(PlayerGainedLifeWatcher.class); - return watcher == null ? 0 : watcher.getLifeGained(sourceAbility.getControllerId()); - } - - @Override - public LathielTheBounteousDawnValue copy() { - return instance; - } - - @Override - public String getMessage() { - return ""; - } - - public static Hint getHint() { - return hint; - } -} diff --git a/Mage.Sets/src/mage/cards/l/LavaFieldOverlord.java b/Mage.Sets/src/mage/cards/l/LavaFieldOverlord.java index 2b35f2cb28b..857bb390e1a 100644 --- a/Mage.Sets/src/mage/cards/l/LavaFieldOverlord.java +++ b/Mage.Sets/src/mage/cards/l/LavaFieldOverlord.java @@ -13,8 +13,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author TheElk801 @@ -36,7 +39,7 @@ public final class LavaFieldOverlord extends CardImpl { // When Lava-Field Overlord enters the battlefield, it deals 4 damage to target creature an opponent controls. Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(4), false); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/l/LavabornMuse.java b/Mage.Sets/src/mage/cards/l/LavabornMuse.java index 13808b30afe..e63bccc138b 100644 --- a/Mage.Sets/src/mage/cards/l/LavabornMuse.java +++ b/Mage.Sets/src/mage/cards/l/LavabornMuse.java @@ -1,13 +1,10 @@ - package mage.cards.l; -import java.util.UUID; import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.condition.common.CardsInHandCondition; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.CardsInHandCondition; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -15,23 +12,27 @@ import mage.constants.ComparisonType; import mage.constants.SubType; import mage.constants.TargetController; +import java.util.UUID; + /** - * * @author ilcartographer */ public final class LavabornMuse extends CardImpl { + private static final Condition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 3, TargetController.ACTIVE); + public LavabornMuse(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.subtype.add(SubType.SPIRIT); this.power = new MageInt(3); this.toughness = new MageInt(3); // At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, Lavaborn Muse deals 3 damage to that player. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(TargetController.OPPONENT, new DamageTargetEffect(3), false), - (Condition)new CardsInHandCondition(ComparisonType.FEWER_THAN, 3, TargetController.ACTIVE), - "At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, {this} deals 3 damage to that player.")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.OPPONENT, + new DamageTargetEffect(3, true, "that player"), + false + ).withInterveningIf(condition)); } private LavabornMuse(final LavabornMuse card) { diff --git a/Mage.Sets/src/mage/cards/l/Lawbringer.java b/Mage.Sets/src/mage/cards/l/Lawbringer.java index ef8f63002d1..710887457d3 100644 --- a/Mage.Sets/src/mage/cards/l/Lawbringer.java +++ b/Mage.Sets/src/mage/cards/l/Lawbringer.java @@ -16,6 +16,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class Lawbringer extends CardImpl { // {tap}, Sacrifice Lawbringer: Exile target red creature. Ability ability = new SimpleActivatedAbility(new ExileTargetEffect(), new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/l/LeadBellyChimera.java b/Mage.Sets/src/mage/cards/l/LeadBellyChimera.java index 4765a6e3fc2..b116720c92d 100644 --- a/Mage.Sets/src/mage/cards/l/LeadBellyChimera.java +++ b/Mage.Sets/src/mage/cards/l/LeadBellyChimera.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -45,7 +46,7 @@ public final class LeadBellyChimera extends CardImpl { Ability ability = new SimpleActivatedAbility(new AddCountersTargetEffect(CounterType.P2P2.createInstance()), new SacrificeSourceCost()); ability.addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.WhileOnBattlefield) .setText("It gains trample. (This effect lasts indefinitely.)")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/l/LeafArrow.java b/Mage.Sets/src/mage/cards/l/LeafArrow.java index 52b6fe9d383..b80bd3e4b88 100644 --- a/Mage.Sets/src/mage/cards/l/LeafArrow.java +++ b/Mage.Sets/src/mage/cards/l/LeafArrow.java @@ -9,6 +9,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -27,7 +28,7 @@ public final class LeafArrow extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{G}"); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DamageTargetEffect(3)); } diff --git a/Mage.Sets/src/mage/cards/l/LedevChampion.java b/Mage.Sets/src/mage/cards/l/LedevChampion.java index eef9be75efe..2a59b165cae 100644 --- a/Mage.Sets/src/mage/cards/l/LedevChampion.java +++ b/Mage.Sets/src/mage/cards/l/LedevChampion.java @@ -10,13 +10,15 @@ import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.SoldierLifelinkToken; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -57,13 +59,6 @@ public final class LedevChampion extends CardImpl { class LedevChampionEffect extends OneShotEffect { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("untapped creatures you control"); - - static { - filter.add(TargetController.YOU.getControllerPredicate()); - filter.add(TappedPredicate.UNTAPPED); - } - public LedevChampionEffect() { super(Outcome.GainLife); staticText = "you may tap any number of untapped creatures you control. " @@ -76,16 +71,14 @@ class LedevChampionEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { + TargetPermanent target = new TargetPermanent(0, Integer.MAX_VALUE, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES, true); + target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), source, game); int tappedAmount = 0; - TargetCreaturePermanent target = new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, true); - if (target.canChoose(source.getControllerId(), source, game) - && target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), source, game)) { - for (UUID creatureId : target.getTargets()) { - Permanent creature = game.getPermanent(creatureId); - if (creature != null) { - creature.tap(source, game); - tappedAmount++; - } + for (UUID creatureId : target.getTargets()) { + Permanent creature = game.getPermanent(creatureId); + if (creature != null) { + creature.tap(source, game); + tappedAmount++; } } if (tappedAmount > 0) { diff --git a/Mage.Sets/src/mage/cards/l/Leeches.java b/Mage.Sets/src/mage/cards/l/Leeches.java index 705441d1fab..eb2ee6617f9 100644 --- a/Mage.Sets/src/mage/cards/l/Leeches.java +++ b/Mage.Sets/src/mage/cards/l/Leeches.java @@ -40,7 +40,7 @@ class LeechesEffect extends OneShotEffect { LeechesEffect() { super(Outcome.Benefit); - this.staticText = "Target player loses all poison counters. Leeches deals that much damage to that player"; + this.staticText = "Target player loses all poison counters. {this} deals that much damage to that player"; } private LeechesEffect(final LeechesEffect effect) { diff --git a/Mage.Sets/src/mage/cards/l/LeechingBite.java b/Mage.Sets/src/mage/cards/l/LeechingBite.java index 73c1444b5c2..b20f8c1afcf 100644 --- a/Mage.Sets/src/mage/cards/l/LeechingBite.java +++ b/Mage.Sets/src/mage/cards/l/LeechingBite.java @@ -1,45 +1,29 @@ - package mage.cards.l; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.other.AnotherTargetPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; /** - * * @author North */ public final class LeechingBite extends CardImpl { public LeechingBite(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); - // Target creature gets +1/+1 until end of turn. Another target creature gets -1/-1 until end of turn. - this.getSpellAbility().addEffect(new LeechingBiteEffect()); - - FilterCreaturePermanent filter1 = new FilterCreaturePermanent("creature to get +1/+1"); - TargetCreaturePermanent target1 = new TargetCreaturePermanent(filter1); - target1.setTargetTag(1); - this.getSpellAbility().addTarget(target1); - - FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another creature to get -1/-1"); - filter2.add(new AnotherTargetPredicate(2)); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter2); - target2.setTargetTag(2); - this.getSpellAbility().addTarget(target2); + this.getSpellAbility().addEffect(new BoostTargetEffect(1, 1)); + this.getSpellAbility().addEffect(new BoostTargetEffect(-1, -1).setTargetPointer(new SecondTargetPointer()).setText("Another target creature gets -1/-1 until end of turn")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("+1/+1").setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2).withChooseHint("-1/-1").setTargetTag(2)); } private LeechingBite(final LeechingBite card) { @@ -51,35 +35,3 @@ public final class LeechingBite extends CardImpl { return new LeechingBite(this); } } - -class LeechingBiteEffect extends ContinuousEffectImpl { - - public LeechingBiteEffect() { - super(Duration.EndOfTurn, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.BoostCreature); - this.staticText = "Target creature gets +1/+1 until end of turn. Another target creature gets -1/-1 until end of turn"; - } - - private LeechingBiteEffect(final LeechingBiteEffect effect) { - super(effect); - } - - @Override - public LeechingBiteEffect copy() { - return new LeechingBiteEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent != null) { - permanent.addPower(1); - permanent.addToughness(1); - } - permanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - if (permanent != null) { - permanent.addPower(-1); - permanent.addToughness(-1); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/l/LeechriddenSwamp.java b/Mage.Sets/src/mage/cards/l/LeechriddenSwamp.java index fdbebd4d9be..4217e7169d4 100644 --- a/Mage.Sets/src/mage/cards/l/LeechriddenSwamp.java +++ b/Mage.Sets/src/mage/cards/l/LeechriddenSwamp.java @@ -1,60 +1,54 @@ package mage.cards.l; -import java.util.UUID; - -import mage.Mana; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.mana.SimpleManaAbility; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.abilities.mana.BlackManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.ColorPredicate; -import mage.game.Game; -import mage.players.Player; + +import java.util.UUID; /** * @author jeffwadsworth */ public final class LeechriddenSwamp extends CardImpl { - private static final FilterControlledPermanent filter = + private static final FilterPermanent filter = new FilterControlledPermanent("you control two or more black permanents"); static { filter.add(new ColorPredicate(ObjectColor.BLACK)); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); + public LeechriddenSwamp(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); this.subtype.add(SubType.SWAMP); // ({tap}: Add {B}.) - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.BlackMana(1), new TapSourceCost())); + this.addAbility(new BlackManaAbility()); // Leechridden Swamp enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); // {B}, {tap}: Each opponent loses 1 life. Activate this ability only if you control two or more black permanents. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new LeechriddenSwampLoseLifeEffect(), - new ManaCostsImpl<>("{B}"), - new PermanentsOnTheBattlefieldCondition( - filter, - ComparisonType.MORE_THAN, - 1)); + new LoseLifeOpponentsEffect(1), new ManaCostsImpl<>("{B}"), condition + ); ability.addCost(new TapSourceCost()); this.addAbility(ability); } @@ -68,35 +62,3 @@ public final class LeechriddenSwamp extends CardImpl { return new LeechriddenSwamp(this); } } - -class LeechriddenSwampLoseLifeEffect extends OneShotEffect { - - LeechriddenSwampLoseLifeEffect() { - super(Outcome.Benefit); - staticText = "each opponent loses 1 life"; - } - - private LeechriddenSwampLoseLifeEffect(final LeechriddenSwampLoseLifeEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - for (UUID opponentId : game.getOpponents(controller.getId())) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null) { - opponent.loseLife(1, game, source, false); - } - } - return true; - } - return false; - } - - @Override - public LeechriddenSwampLoseLifeEffect copy() { - return new LeechriddenSwampLoseLifeEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LegacysAllure.java b/Mage.Sets/src/mage/cards/l/LegacysAllure.java index 8f168ae6d8f..731001d099d 100644 --- a/Mage.Sets/src/mage/cards/l/LegacysAllure.java +++ b/Mage.Sets/src/mage/cards/l/LegacysAllure.java @@ -12,6 +12,7 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.PowerTargetAdjuster; @@ -33,7 +34,7 @@ public final class LegacysAllure extends CardImpl { // Sacrifice Legacy's Allure: Gain control of target creature with power less than or equal to the number of treasure counters on Legacy's Allure. Ability ability = new SimpleActivatedAbility(new GainControlTargetEffect(Duration.EndOfGame, true), new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); ability.setTargetAdjuster(new PowerTargetAdjuster(new CountersSourceCount(CounterType.TREASURE), ComparisonType.OR_LESS)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/l/LegionGuildmage.java b/Mage.Sets/src/mage/cards/l/LegionGuildmage.java index 419ff3fd814..2a7b982683e 100644 --- a/Mage.Sets/src/mage/cards/l/LegionGuildmage.java +++ b/Mage.Sets/src/mage/cards/l/LegionGuildmage.java @@ -14,8 +14,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TargetController; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * * @author TheElk801 @@ -44,7 +47,7 @@ public final class LegionGuildmage extends CardImpl { new ManaCostsImpl<>("{2}{W}") ); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/l/LegolasCounterOfKills.java b/Mage.Sets/src/mage/cards/l/LegolasCounterOfKills.java index 272ea6fb749..cf3119e5f00 100644 --- a/Mage.Sets/src/mage/cards/l/LegolasCounterOfKills.java +++ b/Mage.Sets/src/mage/cards/l/LegolasCounterOfKills.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.common.ScryTriggeredAbility; import mage.abilities.condition.common.SourceTappedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.UntapSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.ReachAbility; @@ -36,10 +35,8 @@ public final class LegolasCounterOfKills extends CardImpl { this.addAbility(ReachAbility.getInstance()); // Whenever you scry, if Legolas, Counter of Kills is tapped, you may untap it. Do this only once each turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new ScryTriggeredAbility(new UntapSourceEffect()).setDoOnlyOnceEachTurn(true), SourceTappedCondition.TAPPED, - "Whenever you scry, if {this} is tapped, you may untap it. Do this only once each turn." - )); + this.addAbility(new ScryTriggeredAbility(new UntapSourceEffect().setText("untap it"), true) + .withInterveningIf(SourceTappedCondition.TAPPED).setDoOnlyOnceEachTurn(true)); // Whenever a creature an opponent controls dies, put a +1/+1 counter on Legolas. this.addAbility(new DiesCreatureTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/l/LeoninVanguard.java b/Mage.Sets/src/mage/cards/l/LeoninVanguard.java index 7809d688a1c..8c36c632504 100644 --- a/Mage.Sets/src/mage/cards/l/LeoninVanguard.java +++ b/Mage.Sets/src/mage/cards/l/LeoninVanguard.java @@ -1,27 +1,32 @@ package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.constants.SubType; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.Duration; -import mage.filter.StaticFilters; +import mage.constants.SubType; +import mage.filter.common.FilterControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class LeoninVanguard extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledCreaturePermanent("you control three or more creatures"), + ComparisonType.MORE_THAN, 2 + ); + public LeoninVanguard(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); @@ -31,19 +36,10 @@ public final class LeoninVanguard extends CardImpl { this.toughness = new MageInt(1); // At the beginning of combat on your turn, if you control three or more creatures, Leonin Vanguard gets +1/+1 until end of turn and you gain 1 life. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - new BoostSourceEffect(1, 1, Duration.EndOfTurn) - ), - new PermanentsOnTheBattlefieldCondition( - StaticFilters.FILTER_CONTROLLED_CREATURES, - ComparisonType.MORE_THAN, 2 - ), - "At the beginning of combat on your turn, " - + "if you control three or more creatures, " - + "{this} gets +1/+1 until end of turn and you gain 1 life." - ); - ability.addEffect(new GainLifeEffect(1)); + Ability ability = new BeginningOfCombatTriggeredAbility( + new BoostSourceEffect(1, 1, Duration.EndOfTurn) + ).withInterveningIf(condition); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/l/LeovoldsOperative.java b/Mage.Sets/src/mage/cards/l/LeovoldsOperative.java index b448f16364b..32bbf0cc942 100644 --- a/Mage.Sets/src/mage/cards/l/LeovoldsOperative.java +++ b/Mage.Sets/src/mage/cards/l/LeovoldsOperative.java @@ -1,14 +1,15 @@ package mage.cards.l; -import java.util.UUID; import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.InfoEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.InfoEffect; + +import java.util.UUID; /** * @@ -27,11 +28,11 @@ public final class LeovoldsOperative extends CardImpl { // TODO: Draft specific abilities not implemented // Draft Leovold’s Operative face up. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft Leovold's Operative face up - not implemented."))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft {this} face up - not implemented."))); // As you draft a card, you may draft an additional card from that booster pack. If you do, turn Leovold's Operative face down, then pass the next booster pack without drafting a card from it. this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("As you draft a card, you may draft an additional card from that booster pack. " - + "If you do, turn Leovold's Operative face down, then pass the next booster pack without drafting a card from it - not implemented."))); + + "If you do, turn {this} face down, then pass the next booster pack without drafting a card from it - not implemented."))); } private LeovoldsOperative(final LeovoldsOperative card) { diff --git a/Mage.Sets/src/mage/cards/l/LesserWerewolf.java b/Mage.Sets/src/mage/cards/l/LesserWerewolf.java index 25f4f90f75f..c617a9ae948 100644 --- a/Mage.Sets/src/mage/cards/l/LesserWerewolf.java +++ b/Mage.Sets/src/mage/cards/l/LesserWerewolf.java @@ -2,9 +2,10 @@ package mage.cards.l; import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; @@ -34,6 +35,8 @@ public final class LesserWerewolf extends CardImpl { filter.add(BlockingOrBlockedBySourcePredicate.EITHER); } + private static final Condition condition = new IsStepCondition(PhaseStep.DECLARE_BLOCKERS, false); + public LesserWerewolf(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.subtype.add(SubType.WEREWOLF); @@ -41,9 +44,8 @@ public final class LesserWerewolf extends CardImpl { this.toughness = new MageInt(4); // {B}: If Lesser Werewolf’s power is 1 or more, it gets -1/-0 until end of turn and put a -0/-1 counter on target creature blocking or blocked by Lesser Werewolf. Activate this ability only during the declare blockers step. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new LesserWerewolfEffect(), new ManaCostsImpl<>("{B}"), - new IsStepCondition(PhaseStep.DECLARE_BLOCKERS, false) + Ability ability = new ActivateIfConditionActivatedAbility( + new LesserWerewolfEffect(), new ManaCostsImpl<>("{B}"), condition ); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/l/LiberatedDwarf.java b/Mage.Sets/src/mage/cards/l/LiberatedDwarf.java index e4ad8a4f955..ad4f14a6a58 100644 --- a/Mage.Sets/src/mage/cards/l/LiberatedDwarf.java +++ b/Mage.Sets/src/mage/cards/l/LiberatedDwarf.java @@ -20,6 +20,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -47,7 +48,7 @@ public final class LiberatedDwarf extends CardImpl { effect = new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn); effect.setText("and gains first strike until end of turn"); ability.addEffect(effect); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/l/LiberatorUrzasBattlethopter.java b/Mage.Sets/src/mage/cards/l/LiberatorUrzasBattlethopter.java index bca173b619d..1fdd65cf3dd 100644 --- a/Mage.Sets/src/mage/cards/l/LiberatorUrzasBattlethopter.java +++ b/Mage.Sets/src/mage/cards/l/LiberatorUrzasBattlethopter.java @@ -1,12 +1,13 @@ package mage.cards.l; import mage.MageInt; +import mage.Mana; import mage.abilities.Ability; +import mage.abilities.AbilityImpl; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.Effects; +import mage.abilities.costs.mana.ManaCost; import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashAllEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.FlashAbility; @@ -22,7 +23,7 @@ import mage.filter.predicate.mageobject.ColorlessPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.stack.Spell; -import mage.watchers.common.ManaPaidSourceWatcher; +import mage.util.CardUtil; import java.util.UUID; @@ -60,15 +61,10 @@ public final class LiberatorUrzasBattlethopter extends CardImpl { // Whenever you cast a spell, if the amount of mana spent to cast that spell is greater // than Liberator, Urza's Battlethopter's power, put a +1/+1 counter on Liberator. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new SpellCastControllerTriggeredAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance()), - StaticFilters.FILTER_SPELL_A, false, SetTargetPointer.SPELL - ), - LiberatorUrzasBattlethopterCondition.instance, - "Whenever you cast a spell, if the amount of mana spent to cast " - + "that spell is greater than {this}'s power, put a +1/+1 counter on {this}" - )); + this.addAbility(new SpellCastControllerTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + StaticFilters.FILTER_SPELL_A, false, SetTargetPointer.SPELL + ).withInterveningIf(LiberatorUrzasBattlethopterCondition.instance)); } private LiberatorUrzasBattlethopter(final LiberatorUrzasBattlethopter card) { @@ -87,17 +83,19 @@ enum LiberatorUrzasBattlethopterCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Permanent permanent = source.getSourcePermanentIfItStillExists(game); - if (permanent == null) { - return false; - } - Effects effects = source.getEffects(); - if (effects.isEmpty()) { - return false; - } - Object spell = effects.get(0).getValue("spellCast"); - if (spell instanceof Spell) { - return (ManaPaidSourceWatcher.getTotalPaid(((Spell) spell).getId(), game) > permanent.getPower().getValue()); - } - return false; + return permanent != null + && CardUtil + .getEffectValueFromAbility(source, "spellCast", Spell.class) + .map(Spell::getSpellAbility) + .map(AbilityImpl::getManaCostsToPay) + .map(ManaCost::getUsedManaToPay) + .map(Mana::count) + .filter(x -> x > permanent.getPower().getValue()) + .isPresent(); + } + + @Override + public String toString() { + return "the amount of mana spent to cast that spell is greater than {this}'s power"; } } diff --git a/Mage.Sets/src/mage/cards/l/LibraryOfAlexandria.java b/Mage.Sets/src/mage/cards/l/LibraryOfAlexandria.java index 18813e48d48..5e8b3c6b060 100644 --- a/Mage.Sets/src/mage/cards/l/LibraryOfAlexandria.java +++ b/Mage.Sets/src/mage/cards/l/LibraryOfAlexandria.java @@ -1,35 +1,35 @@ - package mage.cards.l; -import java.util.UUID; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInHandCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; -import mage.constants.Zone; + +import java.util.UUID; /** * @author LevelX2 */ public final class LibraryOfAlexandria extends CardImpl { + private static final Condition condition = new CardsInHandCondition(ComparisonType.EQUAL_TO, 7); + public LibraryOfAlexandria(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // {tap}: Add {C}. this.addAbility(new ColorlessManaAbility()); + // {tap}: Draw a card. Activate this ability only if you have exactly seven cards in hand. - this.addAbility(new ConditionalActivatedAbility( - Zone.BATTLEFIELD, - new DrawCardSourceControllerEffect(1), - new TapSourceCost(), - new CardsInHandCondition(ComparisonType.EQUAL_TO, 7), - "")); + this.addAbility(new ActivateIfConditionActivatedAbility( + new DrawCardSourceControllerEffect(1), new TapSourceCost(), condition + )); } private LibraryOfAlexandria(final LibraryOfAlexandria card) { diff --git a/Mage.Sets/src/mage/cards/l/Lich.java b/Mage.Sets/src/mage/cards/l/Lich.java index 9c7afe8ef73..d5dbf9136f8 100644 --- a/Mage.Sets/src/mage/cards/l/Lich.java +++ b/Mage.Sets/src/mage/cards/l/Lich.java @@ -36,7 +36,7 @@ public final class Lich extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}{B}{B}{B}"); // As Lich enters the battlefield, you lose life equal to your life total. - this.addAbility(new EntersBattlefieldAbility(new LoseLifeSourceControllerEffect(ControllerLifeCount.instance), null, "As Lich enters the battlefield, you lose life equal to your life total.", null)); + this.addAbility(new EntersBattlefieldAbility(new LoseLifeSourceControllerEffect(ControllerLifeCount.instance), null, "As {this} enters the battlefield, you lose life equal to your life total.", null)); // You don't lose the game for having 0 or less life. this.addAbility(new SimpleStaticAbility(new DontLoseByZeroOrLessLifeEffect(Duration.WhileOnBattlefield))); diff --git a/Mage.Sets/src/mage/cards/l/Lictor.java b/Mage.Sets/src/mage/cards/l/Lictor.java index 2ae66495dfb..6a066125e72 100644 --- a/Mage.Sets/src/mage/cards/l/Lictor.java +++ b/Mage.Sets/src/mage/cards/l/Lictor.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.FlashAbility; import mage.cards.CardImpl; @@ -12,7 +11,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.game.Game; -import mage.game.permanent.token.TyranidToken; import mage.game.permanent.token.TyranidWarriorToken; import mage.watchers.common.CreatureEnteredControllerWatcher; @@ -34,12 +32,8 @@ public final class Lictor extends CardImpl { this.addAbility(FlashAbility.getInstance()); // Pheromone Trail -- When Lictor enters the battlefield, if a creature entered the battlefield under an opponent's control this turn, create a 3/3 green Tyranid Warrior creature token with trample. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new TyranidWarriorToken())), - LictorCondition.instance, "When {this} enters, " + - "if a creature entered the battlefield under an opponent's control this turn, " + - "create a 3/3 green Tyranid Warrior creature token with trample." - ).withFlavorWord("Pheromone Trail"), new CreatureEnteredControllerWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new TyranidWarriorToken())) + .withInterveningIf(LictorCondition.instance).withFlavorWord("Pheromone Trail"), new CreatureEnteredControllerWatcher()); } private Lictor(final Lictor card) { @@ -62,4 +56,9 @@ enum LictorCondition implements Condition { .stream() .anyMatch(uuid -> CreatureEnteredControllerWatcher.enteredCreatureForPlayer(uuid, game)); } + + @Override + public String toString() { + return "a creature entered the battlefield under an opponent's control this turn"; + } } diff --git a/Mage.Sets/src/mage/cards/l/LifeBurst.java b/Mage.Sets/src/mage/cards/l/LifeBurst.java index 8593838ee91..d6433150126 100644 --- a/Mage.Sets/src/mage/cards/l/LifeBurst.java +++ b/Mage.Sets/src/mage/cards/l/LifeBurst.java @@ -1,7 +1,6 @@ package mage.cards.l; -import java.util.UUID; import mage.abilities.dynamicvalue.MultipliedValue; import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount; import mage.abilities.effects.Effect; @@ -13,12 +12,13 @@ import mage.filter.FilterCard; import mage.filter.predicate.mageobject.NamePredicate; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class LifeBurst extends CardImpl { - + private static final FilterCard filter = new FilterCard("card named Life Burst"); static { @@ -26,12 +26,12 @@ public final class LifeBurst extends CardImpl { } public LifeBurst(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); // Target player gains 4 life, then gains 4 life for each card named Life Burst in each graveyard. this.getSpellAbility().addEffect(new GainLifeTargetEffect(4)); Effect effect = new GainLifeTargetEffect(new MultipliedValue(new CardsInAllGraveyardsCount(filter), 4)); - effect.setText(", then gains 4 life for each card named {this} in each graveyard"); + effect.setText(", then gains 4 life for each card named Life Burst in each graveyard"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetPlayer()); } diff --git a/Mage.Sets/src/mage/cards/l/LifeChisel.java b/Mage.Sets/src/mage/cards/l/LifeChisel.java index 062f2f2ac2a..5156d828b3a 100644 --- a/Mage.Sets/src/mage/cards/l/LifeChisel.java +++ b/Mage.Sets/src/mage/cards/l/LifeChisel.java @@ -1,25 +1,18 @@ - package mage.cards.l; -import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.condition.common.IsStepCondition; -import mage.abilities.costs.Cost; import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.decorator.ConditionalActivatedAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.dynamicvalue.common.SacrificeCostCreaturesToughness; +import mage.abilities.effects.common.GainLifeEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.PhaseStep; -import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class LifeChisel extends CardImpl { @@ -28,13 +21,12 @@ public final class LifeChisel extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // Sacrifice a creature: You gain life equal to the sacrificed creature's toughness. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, - new LifeChiselEffect(), + this.addAbility(new ActivateIfConditionActivatedAbility( + new GainLifeEffect(SacrificeCostCreaturesToughness.instance) + .setText("you gain life equal to the sacrificed creature's toughness"), new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE), - new IsStepCondition(PhaseStep.UPKEEP) - ); - this.addAbility(ability); + IsStepCondition.getMyUpkeep() + )); } private LifeChisel(final LifeChisel card) { @@ -46,37 +38,3 @@ public final class LifeChisel extends CardImpl { return new LifeChisel(this); } } - -class LifeChiselEffect extends OneShotEffect { - - LifeChiselEffect() { - super(Outcome.GainLife); - this.staticText = "You gain life equal to the sacrificed creature's toughness"; - } - - private LifeChiselEffect(final LifeChiselEffect effect) { - super(effect); - } - - @Override - public LifeChiselEffect copy() { - return new LifeChiselEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - for (Cost cost : source.getCosts()) { - if (cost instanceof SacrificeTargetCost) { - int amount = ((SacrificeTargetCost) cost).getPermanents().get(0).getToughness().getValue(); - if (amount > 0) { - controller.gainLife(amount, game, source); - } - } - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/l/LifeFindsAWay.java b/Mage.Sets/src/mage/cards/l/LifeFindsAWay.java index fef2799b80c..bae0ebab0be 100644 --- a/Mage.Sets/src/mage/cards/l/LifeFindsAWay.java +++ b/Mage.Sets/src/mage/cards/l/LifeFindsAWay.java @@ -1,25 +1,24 @@ package mage.cards.l; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.PopulateEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.filter.predicate.permanent.TokenPredicate; import java.util.UUID; /** - * * @author notgreat */ public final class LifeFindsAWay extends CardImpl { - private static final FilterPermanent filter = new FilterCreaturePermanent("nontoken creature with power 4 or greater"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("nontoken creature you control with power 4 or greater"); static { filter.add(TokenPredicate.FALSE); @@ -30,7 +29,7 @@ public final class LifeFindsAWay extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); // Whenever a nontoken creature with power 4 or greater you control enters, populate. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new PopulateEffect(), filter)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility(new PopulateEffect(), filter)); } private LifeFindsAWay(final LifeFindsAWay card) { diff --git a/Mage.Sets/src/mage/cards/l/LifeMatrix.java b/Mage.Sets/src/mage/cards/l/LifeMatrix.java index 803cc8a4f74..0be55f638af 100644 --- a/Mage.Sets/src/mage/cards/l/LifeMatrix.java +++ b/Mage.Sets/src/mage/cards/l/LifeMatrix.java @@ -6,7 +6,7 @@ import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.RemoveCountersSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.RegenerateSourceEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; @@ -14,8 +14,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.PhaseStep; -import mage.constants.Zone; import mage.counters.CounterType; import mage.target.common.TargetCreaturePermanent; @@ -32,17 +30,16 @@ public final class LifeMatrix extends CardImpl { // {4}, {T}: Put a matrix counter on target creature and that creature gains // “Remove a matrix counter from this creature: Regenerate this creature.” // Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, + Ability ability = new ActivateIfConditionActivatedAbility( new AddCountersTargetEffect(CounterType.MATRIX.createInstance()), - new GenericManaCost(4), - new IsStepCondition(PhaseStep.UPKEEP), "{4}, {T}: Put a matrix counter on target creature and " - + "that creature gains \"Remove a matrix counter from this creature: " - + "Regenerate this creature.\" Activate only during your upkeep."); - Ability ability2 = new SimpleActivatedAbility( - new RegenerateSourceEffect(), - new RemoveCountersSourceCost(CounterType.MATRIX.createInstance())); - ability.addEffect(new GainAbilityTargetEffect(ability2, Duration.Custom)); + new GenericManaCost(4), IsStepCondition.getMyUpkeep() + ); + ability.addEffect(new GainAbilityTargetEffect( + new SimpleActivatedAbility( + new RegenerateSourceEffect(), + new RemoveCountersSourceCost(CounterType.MATRIX.createInstance()) + ), Duration.Custom + ).setText("and that creature gains \"Remove a matrix counter from this creature: Regenerate this creature.\"")); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/l/Lifeline.java b/Mage.Sets/src/mage/cards/l/Lifeline.java index cbdfb9b0447..ae0768b795b 100644 --- a/Mage.Sets/src/mage/cards/l/Lifeline.java +++ b/Mage.Sets/src/mage/cards/l/Lifeline.java @@ -3,16 +3,19 @@ package mage.cards.l; import mage.abilities.Ability; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.target.targetpointer.FixedTarget; @@ -23,17 +26,18 @@ import java.util.UUID; */ public final class Lifeline extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterCreaturePermanent("another creature is on the battlefield"), false + ); public Lifeline(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); - // Whenever a creature dies, if another creature is on the battlefield, return the first card to the battlefield under its owner's control at the beginning of the next end step. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new DiesCreatureTriggeredAbility(new LifelineEffect(), false, StaticFilters.FILTER_PERMANENT_CREATURE, true), - new PermanentsOnTheBattlefieldCondition(StaticFilters.FILTER_PERMANENT_CREATURE, false), - "Whenever a creature dies, if another creature is on the battlefield, return the first card to the battlefield under its owner's control at the beginning of the next end step."); - this.addAbility(ability); + this.addAbility(new DiesCreatureTriggeredAbility( + new LifelineEffect(), false, + StaticFilters.FILTER_PERMANENT_A_CREATURE, true + ).withInterveningIf(condition)); } private Lifeline(final Lifeline card) { @@ -50,7 +54,7 @@ class LifelineEffect extends OneShotEffect { LifelineEffect() { super(Outcome.PutCardInPlay); - this.staticText = ""; + this.staticText = "return the first card to the battlefield under its owner's control at the beginning of the next end step"; } private LifelineEffect(final LifelineEffect effect) { diff --git a/Mage.Sets/src/mage/cards/l/Lightbringer.java b/Mage.Sets/src/mage/cards/l/Lightbringer.java index 434c8d603ba..39a10dd475e 100644 --- a/Mage.Sets/src/mage/cards/l/Lightbringer.java +++ b/Mage.Sets/src/mage/cards/l/Lightbringer.java @@ -16,6 +16,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class Lightbringer extends CardImpl { // {tap}, Sacrifice Lightbringer: Exile target black creature. Ability ability = new SimpleActivatedAbility(new ExileTargetEffect(), new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/l/LightningDart.java b/Mage.Sets/src/mage/cards/l/LightningDart.java index 05b1a28aada..c6b8b06ec4f 100644 --- a/Mage.Sets/src/mage/cards/l/LightningDart.java +++ b/Mage.Sets/src/mage/cards/l/LightningDart.java @@ -1,7 +1,6 @@ package mage.cards.l; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -13,6 +12,8 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * * @author Derpthemeus @@ -40,7 +41,7 @@ public final class LightningDart extends CardImpl { 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"; + this.staticText = "{this} deals 1 damage to target creature. If that creature is white or blue, {this} deals 4 damage to it instead"; } private LightningDartEffect(final LightningDartEffect effect) { diff --git a/Mage.Sets/src/mage/cards/l/LightningPhoenix.java b/Mage.Sets/src/mage/cards/l/LightningPhoenix.java index 8a849151d89..efc41e9c2e0 100644 --- a/Mage.Sets/src/mage/cards/l/LightningPhoenix.java +++ b/Mage.Sets/src/mage/cards/l/LightningPhoenix.java @@ -2,15 +2,14 @@ package mage.cards.l; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.CantBlockAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HasteAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -44,15 +43,11 @@ public final class LightningPhoenix extends CardImpl { this.addAbility(new CantBlockAbility()); // At the beginning of your end step, if an opponent was dealt 3 or more damage this turn, you may pay {R}. If you do, return Lightning Phoenix from your graveyard to the battlefield. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - Zone.GRAVEYARD, - TargetController.YOU, new DoIfCostPaid( - new ReturnSourceFromGraveyardToBattlefieldEffect(), new ManaCostsImpl<>("{R}") - ), false, null - ), LightningPhoenixCondition.instance, "At the beginning of your end step, " + - "if an opponent was dealt 3 or more damage this turn, you may pay {R}. " + - "If you do, return {this} from your graveyard to the battlefield." + this.addAbility(new BeginningOfEndStepTriggeredAbility( + Zone.GRAVEYARD, TargetController.YOU, + new DoIfCostPaid( + new ReturnSourceFromGraveyardToBattlefieldEffect(), new ManaCostsImpl<>("{R}") + ), false, LightningPhoenixCondition.instance ), new LightningPhoenixWatcher()); } @@ -74,6 +69,11 @@ enum LightningPhoenixCondition implements Condition { LightningPhoenixWatcher watcher = game.getState().getWatcher(LightningPhoenixWatcher.class); return watcher != null && watcher.checkDamage(source.getControllerId()); } + + @Override + public String toString() { + return "an opponent was dealt 3 or more damage this turn"; + } } class LightningPhoenixWatcher extends Watcher { diff --git a/Mage.Sets/src/mage/cards/l/LightningSerpent.java b/Mage.Sets/src/mage/cards/l/LightningSerpent.java index 584890d3cd9..70c8791ea22 100644 --- a/Mage.Sets/src/mage/cards/l/LightningSerpent.java +++ b/Mage.Sets/src/mage/cards/l/LightningSerpent.java @@ -1,23 +1,22 @@ - package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.effects.common.EntersBattlefieldWithXCountersEffect; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.TargetController; import mage.counters.CounterType; -import mage.game.events.GameEvent; + +import java.util.UUID; /** - * * @author LoneFox */ public final class LightningSerpent extends CardImpl { @@ -31,12 +30,17 @@ public final class LightningSerpent extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); + // Haste this.addAbility(HasteAbility.getInstance()); + // Lightning Serpent enters the battlefield with X +1/+0 counters on it. this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.P1P0.createInstance()))); + // At the beginning of the end step, sacrifice Lightning Serpent. - this.addAbility(new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new SacrificeSourceEffect())); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.NEXT, new SacrificeSourceEffect(), false + )); } private LightningSerpent(final LightningSerpent card) { diff --git a/Mage.Sets/src/mage/cards/l/LightningSkelemental.java b/Mage.Sets/src/mage/cards/l/LightningSkelemental.java index 0e5a681f693..3d0ce2b3f90 100644 --- a/Mage.Sets/src/mage/cards/l/LightningSkelemental.java +++ b/Mage.Sets/src/mage/cards/l/LightningSkelemental.java @@ -2,16 +2,16 @@ package mage.cards.l; import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.events.GameEvent; +import mage.constants.TargetController; import java.util.UUID; @@ -40,9 +40,8 @@ public final class LightningSkelemental extends CardImpl { )); // At the beginning of the end step, sacrifice Lightning Skelemental. - this.addAbility(new OnEventTriggeredAbility( - GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", - true, new SacrificeSourceEffect() + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.NEXT, new SacrificeSourceEffect(), false )); } diff --git a/Mage.Sets/src/mage/cards/l/LilianaDeathWielder.java b/Mage.Sets/src/mage/cards/l/LilianaDeathWielder.java index e5a56b63e23..88d6a0945fa 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaDeathWielder.java +++ b/Mage.Sets/src/mage/cards/l/LilianaDeathWielder.java @@ -12,6 +12,7 @@ import mage.constants.SuperType; import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -42,7 +43,7 @@ public final class LilianaDeathWielder extends CardImpl { // -3: Destroy target creature with a -1/-1 counter on it. ability = new LoyaltyAbility(new DestroyTargetEffect(), -3); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // -10: Return all creature cards from your graveyard to the battlefield. diff --git a/Mage.Sets/src/mage/cards/l/LilianaTheNecromancer.java b/Mage.Sets/src/mage/cards/l/LilianaTheNecromancer.java index 10e768d736b..0f941198204 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaTheNecromancer.java +++ b/Mage.Sets/src/mage/cards/l/LilianaTheNecromancer.java @@ -44,7 +44,7 @@ public final class LilianaTheNecromancer extends CardImpl { // −7: Destroy up to two target creatures. Put up to two creature cards from graveyards onto the battlefield under your control. ability = new LoyaltyAbility(new DestroyTargetEffect(), -7); - ability.addTarget(new TargetCreaturePermanent(0, 2, StaticFilters.FILTER_PERMANENT_CREATURES, false)); + ability.addTarget(new TargetCreaturePermanent(0, 2)); ability.addEffect(new LilianaTheNecromancerEffect()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/l/LilianasContract.java b/Mage.Sets/src/mage/cards/l/LilianasContract.java index ef6b3616681..77f572540c3 100644 --- a/Mage.Sets/src/mage/cards/l/LilianasContract.java +++ b/Mage.Sets/src/mage/cards/l/LilianasContract.java @@ -1,16 +1,12 @@ package mage.cards.l; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.WinGameSourceControllerEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -18,8 +14,11 @@ import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class LilianasContract extends CardImpl { @@ -28,25 +27,13 @@ public final class LilianasContract extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}{B}"); // When Liliana's Contract enters the battlefield, you draw four cards and you lose 4 life. - Ability ability = new EntersBattlefieldTriggeredAbility( - new DrawCardSourceControllerEffect(4) - .setText("you draw four cards") - ); - ability.addEffect( - new LoseLifeSourceControllerEffect(4) - .setText("and you lose 4 life") - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(4, true)); + ability.addEffect(new LoseLifeSourceControllerEffect(4).setText("and you lose 4 life")); this.addAbility(ability); // At the beginning of your upkeep, if you control four or more Demons with different names, you win the game. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - new WinGameSourceControllerEffect(), false - ), LilianasContractCondition.instance, - "At the beginning of your upkeep, " - + "if you control four or more Demons with different names, " - + "you win the game." - )); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect()) + .withInterveningIf(LilianasContractCondition.instance)); } private LilianasContract(final LilianasContract card) { diff --git a/Mage.Sets/src/mage/cards/l/LilianasScrounger.java b/Mage.Sets/src/mage/cards/l/LilianasScrounger.java index 3def5d14982..30825b347fe 100644 --- a/Mage.Sets/src/mage/cards/l/LilianasScrounger.java +++ b/Mage.Sets/src/mage/cards/l/LilianasScrounger.java @@ -2,11 +2,10 @@ package mage.cards.l; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.common.MorbidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.hint.common.MorbidHint; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -37,10 +36,9 @@ public final class LilianasScrounger extends CardImpl { this.toughness = new MageInt(2); // At the beginning of each end step, if a creature died this turn, you may put a loyalty counter on a Liliana planeswalker you control. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new BeginningOfEndStepTriggeredAbility( - TargetController.ANY, new LilianasScroungerEffect(), false - ), MorbidCondition.instance, "At the beginning of each end step, " + - "if a creature died this turn, you may put a loyalty counter on a Liliana planeswalker you control." + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.ANY, new LilianasScroungerEffect(), + false, MorbidCondition.instance ).addHint(MorbidHint.instance)); } @@ -61,6 +59,7 @@ class LilianasScroungerEffect extends OneShotEffect { LilianasScroungerEffect() { super(Outcome.Benefit); + staticText = "you may put a loyalty counter on a Liliana planeswalker you control"; } private LilianasScroungerEffect(final LilianasScroungerEffect effect) { diff --git a/Mage.Sets/src/mage/cards/l/LilysplashMentor.java b/Mage.Sets/src/mage/cards/l/LilysplashMentor.java index 68e008a0fa7..1a442a90862 100644 --- a/Mage.Sets/src/mage/cards/l/LilysplashMentor.java +++ b/Mage.Sets/src/mage/cards/l/LilysplashMentor.java @@ -19,20 +19,19 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.util.CardUtil; import java.util.UUID; /** - * * @author notgreat */ public final class LilysplashMentor extends CardImpl { public LilysplashMentor(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); - + this.subtype.add(SubType.FROG); this.subtype.add(SubType.DRUID); this.power = new MageInt(4); @@ -43,7 +42,7 @@ public final class LilysplashMentor extends CardImpl { // {1}{G}{U}: Exile another target creature you control, then return it to the battlefield under its owner's control with a +1/+1 counter on it. Activate only as a sorcery. Ability ability = new ActivateAsSorceryActivatedAbility(new LilysplashMentorEffect(), new ManaCostsImpl<>("{1}{G}{U}")); - ability.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); this.addAbility(ability); } @@ -56,6 +55,7 @@ public final class LilysplashMentor extends CardImpl { return new LilysplashMentor(this); } } + //Copied from Planar Incision class LilysplashMentorEffect extends OneShotEffect { diff --git a/Mage.Sets/src/mage/cards/l/LinvalaShieldOfSeaGate.java b/Mage.Sets/src/mage/cards/l/LinvalaShieldOfSeaGate.java index dafe59292ad..3b5928755c2 100644 --- a/Mage.Sets/src/mage/cards/l/LinvalaShieldOfSeaGate.java +++ b/Mage.Sets/src/mage/cards/l/LinvalaShieldOfSeaGate.java @@ -2,11 +2,9 @@ package mage.cards.l; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.FullPartyCondition; import mage.abilities.costs.common.SacrificeSourceCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -14,6 +12,7 @@ import mage.abilities.hint.common.PartyCountHint; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HexproofAbility; import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -52,13 +51,8 @@ public final class LinvalaShieldOfSeaGate extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // At the beginning of combat on your turn, if you have a full party, choose target nonland permanent an opponent controls. Until your next turn, it can't attack or block, and its activated abilities can't be activated. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - new LinvalaShieldOfSeaGateRestrictionEffect() - ), FullPartyCondition.instance, "At the beginning of combat on your turn, " + - "if you have a full party, choose target nonland permanent an opponent controls. " + - "Until your next turn, it can't attack or block, and its activated abilities can't be activated." - ); + Ability ability = new BeginningOfCombatTriggeredAbility(new LinvalaShieldOfSeaGateRestrictionEffect()) + .withInterveningIf(FullPartyCondition.instance); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability.addHint(PartyCountHint.instance)); @@ -80,6 +74,8 @@ class LinvalaShieldOfSeaGateRestrictionEffect extends RestrictionEffect { LinvalaShieldOfSeaGateRestrictionEffect() { super(Duration.UntilYourNextTurn, Outcome.UnboostCreature); + staticText = "choose target nonland permanent an opponent controls. Until your next turn, " + + "it can't attack or block, and its activated abilities can't be activated"; } private LinvalaShieldOfSeaGateRestrictionEffect(final LinvalaShieldOfSeaGateRestrictionEffect effect) { diff --git a/Mage.Sets/src/mage/cards/l/LinvalaThePreserver.java b/Mage.Sets/src/mage/cards/l/LinvalaThePreserver.java index b63ee29897c..ec96f5c4b89 100644 --- a/Mage.Sets/src/mage/cards/l/LinvalaThePreserver.java +++ b/Mage.Sets/src/mage/cards/l/LinvalaThePreserver.java @@ -1,12 +1,10 @@ - package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.OpponentControlsMoreCondition; import mage.abilities.condition.common.OpponentHasMoreLifeCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.keyword.FlyingAbility; @@ -15,15 +13,18 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; import mage.game.permanent.token.Angel33Token; +import java.util.UUID; + /** - * * @author fireshoes */ public final class LinvalaThePreserver extends CardImpl { + private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_PERMANENT_CREATURES); + public LinvalaThePreserver(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}"); this.supertype.add(SuperType.LEGENDARY); @@ -35,14 +36,12 @@ public final class LinvalaThePreserver extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Linvala, the Preserver enters the battlefield, if an opponent has more life than you, you gain 5 life. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(5), false), - OpponentHasMoreLifeCondition.instance, - "When {this} enters, if an opponent has more life than you, you gain 5 life.")); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(5)) + .withInterveningIf(OpponentHasMoreLifeCondition.instance)); // When Linvala enters the battlefield, if an opponent controls more creatures than you, create a 3/3 white Angel creature token with flying. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new Angel33Token()), false), - new OpponentControlsMoreCondition(new FilterCreaturePermanent()), - "When {this} enters, if an opponent controls more creatures than you, create a 3/3 white Angel creature token with flying.")); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new Angel33Token())) + .withInterveningIf(condition)); } private LinvalaThePreserver(final LinvalaThePreserver card) { diff --git a/Mage.Sets/src/mage/cards/l/LittjaraKinseekers.java b/Mage.Sets/src/mage/cards/l/LittjaraKinseekers.java index 285066909de..cd8f520cf49 100644 --- a/Mage.Sets/src/mage/cards/l/LittjaraKinseekers.java +++ b/Mage.Sets/src/mage/cards/l/LittjaraKinseekers.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.GreatestSharedCreatureTypeCount; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.keyword.ScryEffect; @@ -34,14 +33,9 @@ public final class LittjaraKinseekers extends CardImpl { this.addAbility(new ChangelingAbility()); // When Littjara Kinseekers enters the battlefield, if you control three or more creatures that share a creature type, put a +1/+1 counter on Littjara Kinseekers, then scry 1. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance()) - ), LittjaraKinseekersCondition.instance, "When {this} enters, " + - "if you control three or more creatures that share a creature type, " + - "put a +1/+1 counter on {this}, then scry 1." - ); - ability.addEffect(new ScryEffect(1)); + Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())) + .withInterveningIf(LittjaraKinseekersCondition.instance); + ability.addEffect(new ScryEffect(1).concatBy(", then")); this.addAbility(ability.addHint(GreatestSharedCreatureTypeCount.getHint())); } @@ -62,4 +56,9 @@ enum LittjaraKinseekersCondition implements Condition { public boolean apply(Game game, Ability source) { return GreatestSharedCreatureTypeCount.instance.calculate(game, source, null) >= 3; } + + @Override + public String toString() { + return "you control three or more creatures that share a creature type"; + } } diff --git a/Mage.Sets/src/mage/cards/l/LivingTotem.java b/Mage.Sets/src/mage/cards/l/LivingTotem.java index 7722b0441d2..2590c3131b8 100644 --- a/Mage.Sets/src/mage/cards/l/LivingTotem.java +++ b/Mage.Sets/src/mage/cards/l/LivingTotem.java @@ -13,8 +13,11 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * * @author LevelX2 @@ -33,7 +36,7 @@ public final class LivingTotem extends CardImpl { this.addAbility(new ConvokeAbility()); // When Living Totem enters the battlefield, you may put a +1/+1 counter on another target creature. Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), true); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/l/LlanowarAugur.java b/Mage.Sets/src/mage/cards/l/LlanowarAugur.java index 6514434c983..f4d496e7692 100644 --- a/Mage.Sets/src/mage/cards/l/LlanowarAugur.java +++ b/Mage.Sets/src/mage/cards/l/LlanowarAugur.java @@ -1,33 +1,29 @@ - package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.SacrificeSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; -import mage.abilities.effects.Effect; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.PhaseStep; -import mage.constants.Zone; +import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class LlanowarAugur extends CardImpl { public LlanowarAugur(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.SHAMAN); @@ -36,15 +32,14 @@ public final class LlanowarAugur extends CardImpl { // Sacrifice Llanowar Augur: Target creature gets +3/+3 and gains trample until end of turn. // Activate this ability only during your upkeep. - Effect effect = new BoostTargetEffect(3, 3, Duration.EndOfTurn); - effect.setText("Target creature gets +3/+3"); - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, - effect, - new SacrificeSourceCost(), - new IsStepCondition(PhaseStep.UPKEEP) + Ability ability = new ActivateIfConditionActivatedAbility( + new BoostTargetEffect(3, 3).setText("Target creature gets +3/+3"), + new SacrificeSourceCost(), IsStepCondition.getMyUpkeep() ); - effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn, "and gains trample until end of turn"); - ability.addEffect(effect); + ability.addEffect(new GainAbilityTargetEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, + "and gains trample until end of turn" + )); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/l/LlanowarBehemoth.java b/Mage.Sets/src/mage/cards/l/LlanowarBehemoth.java index c5264808242..f22a89318d5 100644 --- a/Mage.Sets/src/mage/cards/l/LlanowarBehemoth.java +++ b/Mage.Sets/src/mage/cards/l/LlanowarBehemoth.java @@ -1,7 +1,5 @@ - package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapTargetCost; @@ -9,33 +7,29 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author Plopman */ public final class LlanowarBehemoth extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); - static { - filter.add(TappedPredicate.UNTAPPED); - } - public LlanowarBehemoth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(4); this.toughness = new MageInt(4); // Tap an untapped creature you control: Llanowar Behemoth gets +1/+1 until end of turn. - this.addAbility(new SimpleActivatedAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn), new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, false)))); + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(1, 1, Duration.EndOfTurn), + new TapTargetCost(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE) + )); } private LlanowarBehemoth(final LlanowarBehemoth card) { diff --git a/Mage.Sets/src/mage/cards/l/LoamDryad.java b/Mage.Sets/src/mage/cards/l/LoamDryad.java index 510ba342a9e..d2859b1c33b 100644 --- a/Mage.Sets/src/mage/cards/l/LoamDryad.java +++ b/Mage.Sets/src/mage/cards/l/LoamDryad.java @@ -1,7 +1,6 @@ package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.costs.common.TapTargetCost; @@ -10,24 +9,17 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class LoamDryad extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); - - static { - filter.add(TappedPredicate.UNTAPPED); - } - public LoamDryad(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); this.subtype.add(SubType.DRYAD); this.subtype.add(SubType.HORROR); this.power = new MageInt(1); @@ -35,7 +27,7 @@ public final class LoamDryad extends CardImpl { // {T}, Tap an untapped creature you control: Add one mana of any color. Ability ability = new AnyColorManaAbility(); - ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, false))); + ability.addCost(new TapTargetCost(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/l/LoanShark.java b/Mage.Sets/src/mage/cards/l/LoanShark.java index ed4334b58a6..0165297bc9f 100644 --- a/Mage.Sets/src/mage/cards/l/LoanShark.java +++ b/Mage.Sets/src/mage/cards/l/LoanShark.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.PlotAbility; import mage.abilities.keyword.StormAbility; @@ -31,11 +30,8 @@ public final class LoanShark extends CardImpl { this.toughness = new MageInt(4); // When Loan Shark enters the battlefield, if you've cast two or more spells this turn, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)), - LoanSharkCondition.instance, "When {this} enters, " + - "if you've cast two or more spells this turn, draw a card." - ).addHint(StormAbility.getHint())); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .withInterveningIf(LoanSharkCondition.instance).addHint(StormAbility.getHint())); // Plot {3}{U} this.addAbility(new PlotAbility("{3}{U}")); @@ -61,4 +57,9 @@ enum LoanSharkCondition implements Condition { .getWatcher(SpellsCastWatcher.class) .getCount(source.getControllerId()) >= 2; } + + @Override + public String toString() { + return "you've cast two or more spells this turn"; + } } diff --git a/Mage.Sets/src/mage/cards/l/LobeLobber.java b/Mage.Sets/src/mage/cards/l/LobeLobber.java index 6c975bdff91..a7317f1d778 100644 --- a/Mage.Sets/src/mage/cards/l/LobeLobber.java +++ b/Mage.Sets/src/mage/cards/l/LobeLobber.java @@ -5,18 +5,20 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.UntapSourceEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EquipAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.TargetPlayer; +import mage.target.common.TargetPlayerOrPlaneswalker; import java.util.UUID; @@ -29,10 +31,10 @@ public final class LobeLobber extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); this.subtype.add(SubType.EQUIPMENT); - // Equipped creature has "T: This creature deals 1 damage to target player. Roll a six-sided die. On a 5 or higher, untap it." - Effect effect = new LobeLobberEffect(); - SimpleActivatedAbility ability = new SimpleActivatedAbility(effect, new TapSourceCost()); - ability.addTarget(new TargetPlayer()); + // Equipped creature has "T: This creature deals 1 damage to target player or planeswalker. Roll a six-sided die. On a 5 or higher, untap it." + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new TapSourceCost()); + ability.addTarget(new TargetPlayerOrPlaneswalker()); + ability.addEffect(new LobeLobberEffect()); this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect(ability, AttachmentType.EQUIPMENT))); // Equip 2 @@ -53,7 +55,7 @@ class LobeLobberEffect extends OneShotEffect { LobeLobberEffect() { super(Outcome.Benefit); - this.staticText = "This creature deals 1 damage to target player. Roll a six-sided die. On a 5 or higher, untap it"; + this.staticText = "Roll a six-sided die. On a 5 or higher, untap it"; } private LobeLobberEffect(final LobeLobberEffect effect) { @@ -68,18 +70,13 @@ class LobeLobberEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent equipment = game.getPermanent(source.getSourceId()); - Player player = game.getPlayer(source.getFirstTarget()); - - if (controller != null && equipment != null && player != null) { - player.damage(1, source.getSourceId(), source, game); + if (controller != null) { int amount = controller.rollDice(outcome, source, game, 6); if (amount >= 5) { new UntapSourceEffect().apply(game, source); } return true; } - return false; } } diff --git a/Mage.Sets/src/mage/cards/l/LockedInTheCemetery.java b/Mage.Sets/src/mage/cards/l/LockedInTheCemetery.java index dc64fd80d07..219754fee65 100644 --- a/Mage.Sets/src/mage/cards/l/LockedInTheCemetery.java +++ b/Mage.Sets/src/mage/cards/l/LockedInTheCemetery.java @@ -1,11 +1,9 @@ package mage.cards.l; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.DontUntapInControllersUntapStepEnchantedEffect; import mage.abilities.effects.common.TapEnchantedEffect; @@ -36,15 +34,10 @@ public final class LockedInTheCemetery extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget)); // When Locked in the Cemetery enters the battlefield, if there are five or more cards in your graveyard, tap enchanted creature. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new TapEnchantedEffect()), - condition, "When {this} enters, if there are " + - "five or more cards in your graveyard, tap enchanted creature." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new TapEnchantedEffect()).withInterveningIf(condition)); // Enchanted creature doesn't untap during its controller's untap step. this.addAbility(new SimpleStaticAbility(new DontUntapInControllersUntapStepEnchantedEffect())); diff --git a/Mage.Sets/src/mage/cards/l/LoneRevenant.java b/Mage.Sets/src/mage/cards/l/LoneRevenant.java index 3250bcab753..3d35cf453fb 100644 --- a/Mage.Sets/src/mage/cards/l/LoneRevenant.java +++ b/Mage.Sets/src/mage/cards/l/LoneRevenant.java @@ -1,11 +1,9 @@ package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.keyword.HexproofAbility; import mage.cards.CardImpl; @@ -14,19 +12,27 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.PutCards; import mage.constants.SubType; -import mage.filter.StaticFilters; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; + +import java.util.UUID; /** - * * @author awjackson */ public final class LoneRevenant extends CardImpl { - private static final Condition condition = new PermanentsOnTheBattlefieldCondition( - StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, ComparisonType.EQUAL_TO, 0); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("you control no other creatures"); + + static { + filter.add(AnotherPredicate.instance); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0); public LoneRevenant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); this.subtype.add(SubType.SPIRIT); this.power = new MageInt(4); @@ -37,14 +43,9 @@ public final class LoneRevenant extends CardImpl { // Whenever Lone Revenant deals combat damage to a player, // if you control no other creatures, look at the top four cards of your library. // Put one of them into your hand and the rest on the bottom of your library in any order. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new DealsCombatDamageToAPlayerTriggeredAbility( - new LookLibraryAndPickControllerEffect(4, 1, PutCards.HAND, PutCards.BOTTOM_ANY), - false - ), condition, "Whenever {this} deals combat damage to a player, " + - "if you control no other creatures, look at the top four cards of your library. " + - "Put one of them into your hand and the rest on the bottom of your library in any order." - )); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new LookLibraryAndPickControllerEffect( + 4, 1, PutCards.HAND, PutCards.BOTTOM_ANY + )).withInterveningIf(condition)); } private LoneRevenant(final LoneRevenant card) { diff --git a/Mage.Sets/src/mage/cards/l/LoneRider.java b/Mage.Sets/src/mage/cards/l/LoneRider.java index 1d2c7db5c86..4043af88cec 100644 --- a/Mage.Sets/src/mage/cards/l/LoneRider.java +++ b/Mage.Sets/src/mage/cards/l/LoneRider.java @@ -1,16 +1,15 @@ package mage.cards.l; import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.YouGainedLifeCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.LifelinkAbility; import mage.abilities.keyword.TransformAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -26,9 +25,8 @@ import java.util.UUID; */ public final class LoneRider extends CardImpl { - private static final String ruleText = "At the beginning of the end step, if you gained 3 or more life this turn, transform {this}"; private static final Condition condition = new YouGainedLifeCondition(ComparisonType.MORE_THAN, 2); - private static final Hint hint = new ConditionHint(condition, "You gained 3 or more life this turn"); + private static final Hint hint = new ConditionHint(condition); public LoneRider(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); @@ -47,11 +45,9 @@ public final class LoneRider extends CardImpl { // At the beginning of the end step, if you gained 3 or more life this turn, transform Lone Rider. this.addAbility(new TransformAbility()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - TargetController.NEXT, new TransformSourceEffect(), false - ), condition, ruleText - ).addHint(hint), new PlayerGainedLifeWatcher()); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.NEXT, new TransformSourceEffect(), false + ).withInterveningIf(condition).addHint(hint), new PlayerGainedLifeWatcher()); } private LoneRider(final LoneRider card) { diff --git a/Mage.Sets/src/mage/cards/l/LordSkittersBlessing.java b/Mage.Sets/src/mage/cards/l/LordSkittersBlessing.java index dc87fa4fd3a..facdafff66a 100644 --- a/Mage.Sets/src/mage/cards/l/LordSkittersBlessing.java +++ b/Mage.Sets/src/mage/cards/l/LordSkittersBlessing.java @@ -1,16 +1,15 @@ package mage.cards.l; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfDrawTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateRoleAttachedTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; +import mage.abilities.triggers.BeginningOfDrawTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -28,14 +27,14 @@ import java.util.UUID; */ public final class LordSkittersBlessing extends CardImpl { - private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("you control an enchanted creature"); static { filter.add(EnchantedPredicate.instance); } private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); - private static final Hint hint = new ConditionHint(condition, "You control an enchanted creature"); + private static final Hint hint = new ConditionHint(condition); public LordSkittersBlessing(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); @@ -46,13 +45,10 @@ public final class LordSkittersBlessing extends CardImpl { this.addAbility(ability); // At the beginning of your draw step, if you control an enchanted creature, you lose 1 life and you draw an additional card. - ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfDrawTriggeredAbility( - TargetController.YOU, new LoseLifeSourceControllerEffect(1), false - ), condition, "At the beginning of your draw step, if you control " + - "an enchanted creature, you lose 1 life and you draw an additional card." - ); - ability.addEffect(new DrawCardSourceControllerEffect(1)); + ability = new BeginningOfDrawTriggeredAbility( + TargetController.YOU, new LoseLifeSourceControllerEffect(1), false + ).withInterveningIf(condition); + ability.addEffect(new DrawCardSourceControllerEffect(1).setText("and you draw an additional card")); this.addAbility(ability.addHint(hint)); } diff --git a/Mage.Sets/src/mage/cards/l/LoreSeeker.java b/Mage.Sets/src/mage/cards/l/LoreSeeker.java index 5daea234c55..90a43705adf 100644 --- a/Mage.Sets/src/mage/cards/l/LoreSeeker.java +++ b/Mage.Sets/src/mage/cards/l/LoreSeeker.java @@ -1,15 +1,16 @@ package mage.cards.l; -import java.util.UUID; import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.InfoEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.InfoEffect; + +import java.util.UUID; /** * @@ -27,8 +28,8 @@ public final class LoreSeeker extends CardImpl { // TODO: Draft specific abilities not implemented // Reveal Lore Seeker as you draft it. After you draft Lore Seeker, you may add a booster pack to the draft. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Reveal Lore Seeker as you draft it. " - + "After you draft Lore Seeker, you may add a booster pack to the draft - not implemented."))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Reveal {this} as you draft it. " + + "After you draft {this}, you may add a booster pack to the draft - not implemented."))); } private LoreSeeker(final LoreSeeker card) { diff --git a/Mage.Sets/src/mage/cards/l/LosheelClockworkScholar.java b/Mage.Sets/src/mage/cards/l/LosheelClockworkScholar.java index de570733b88..3a59a5889e1 100644 --- a/Mage.Sets/src/mage/cards/l/LosheelClockworkScholar.java +++ b/Mage.Sets/src/mage/cards/l/LosheelClockworkScholar.java @@ -1,7 +1,7 @@ package mage.cards.l; import mage.MageInt; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.PreventAllDamageToAllEffect; @@ -22,7 +22,7 @@ public final class LosheelClockworkScholar extends CardImpl { private static final FilterPermanent filter = new FilterArtifactCreaturePermanent("attacking artifact creatures you control"); private static final FilterPermanent filter2 - = new FilterArtifactCreaturePermanent("one or more artifact creatures"); + = new FilterArtifactCreaturePermanent("one or more artifact creatures you control"); static { filter.add(TargetController.YOU.getControllerPredicate()); @@ -45,7 +45,7 @@ public final class LosheelClockworkScholar extends CardImpl { ))); // Whenever one or more artifact creatures enter the battlefield under your control, draw a card. This ability triggers only once each turn. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + this.addAbility(new EntersBattlefieldAllTriggeredAbility( new DrawCardSourceControllerEffect(1), filter2 ).setTriggersLimitEachTurn(1)); } diff --git a/Mage.Sets/src/mage/cards/l/LostMonarchOfIfnir.java b/Mage.Sets/src/mage/cards/l/LostMonarchOfIfnir.java index 68b5d63384f..31bd9c446bd 100644 --- a/Mage.Sets/src/mage/cards/l/LostMonarchOfIfnir.java +++ b/Mage.Sets/src/mage/cards/l/LostMonarchOfIfnir.java @@ -1,26 +1,22 @@ package mage.cards.l; -import java.util.Optional; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; +import mage.abilities.keyword.AfflictAbility; import mage.abilities.triggers.BeginningOfSecondMainTriggeredAbility; import mage.cards.Card; -import mage.constants.*; -import mage.abilities.keyword.AfflictAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.filter.FilterCard; -import mage.filter.common.FilterCreatureCard; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.events.DamagedEvent; @@ -31,17 +27,20 @@ import mage.target.TargetCard; import mage.target.common.TargetCardInYourGraveyard; import mage.watchers.Watcher; +import java.util.Optional; +import java.util.UUID; + /** * @author sobiech */ public final class LostMonarchOfIfnir extends CardImpl { - private final static Hint hint = new ConditionHint(LostMonarchOfIfnirCondition.instance, "Player was dealt combat damage by a Zombie this turn"); - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.ZOMBIE, "Zombies"); + private final static FilterPermanent filter = new FilterCreaturePermanent(SubType.ZOMBIE, "Zombies"); + private final static Hint hint = new ConditionHint(LostMonarchOfIfnirCondition.instance); public LostMonarchOfIfnir(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); - + this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.NOBLE); this.power = new MageInt(4); @@ -52,28 +51,15 @@ public final class LostMonarchOfIfnir extends CardImpl { // Other Zombies you control have afflict 3. this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - new AfflictAbility(3), - Duration.WhileOnBattlefield, - filter, - true + new AfflictAbility(3), Duration.WhileOnBattlefield, filter, true ))); - final TriggeredAbility ability = new BeginningOfSecondMainTriggeredAbility( - Zone.BATTLEFIELD, - TargetController.YOU, - new LostMonarchOfIfnirEffect(), - false - ); - ability.addHint(hint); - // At the beginning of your second main phase, if a player was dealt combat damage by a Zombie this turn, mill three cards, then you may return a creature card from your graveyard to your hand. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - ability, - LostMonarchOfIfnirCondition.instance, - "at the beginning of your second main phase, " + - "if a player was dealt combat damage by a Zombie this turn, " + - "mill three cards, then you may return a creature card from your graveyard to your hand" - ), new LostMonarchOfIfnirWatcher()); + Ability ability = new BeginningOfSecondMainTriggeredAbility( + new MillCardsControllerEffect(3), false + ).withInterveningIf(LostMonarchOfIfnirCondition.instance); + ability.addEffect(new LostMonarchOfIfnirEffect()); + this.addAbility(ability.addHint(hint), new LostMonarchOfIfnirWatcher()); } private LostMonarchOfIfnir(final LostMonarchOfIfnir card) { @@ -87,38 +73,28 @@ public final class LostMonarchOfIfnir extends CardImpl { } class LostMonarchOfIfnirEffect extends OneShotEffect { - private static final FilterCard filter = new FilterCreatureCard(); LostMonarchOfIfnirEffect() { super(Outcome.Benefit); + staticText = ", then you may return a creature card from your graveyard to your hand"; } - private LostMonarchOfIfnirEffect(OneShotEffect effect){ + + private LostMonarchOfIfnirEffect(LostMonarchOfIfnirEffect effect) { super(effect); } @Override public boolean apply(Game game, Ability source) { - new MillCardsControllerEffect(3).apply(game, source); - - final TargetCard target = new TargetCardInYourGraveyard(0, 1, filter, true); - final Player player = game.getPlayer(source.getControllerId()); - + Player player = game.getPlayer(source.getControllerId()); if (player == null) { return false; } - - if (!player.choose(Outcome.ReturnToHand, target, source, game)) { - return true; - } - - final Card card = game.getCard(target.getFirstTarget()); - if (card == null) { - return true; - } - - player.moveCards(card, Zone.HAND, source, game); - - return true; + TargetCard target = new TargetCardInYourGraveyard( + 0, 1, StaticFilters.FILTER_CARD_CREATURE, true + ); + player.choose(Outcome.ReturnToHand, target, source, game); + Card card = game.getCard(target.getFirstTarget()); + return card != null && player.moveCards(card, Zone.HAND, source, game); } @Override @@ -132,39 +108,34 @@ enum LostMonarchOfIfnirCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - final LostMonarchOfIfnirWatcher watcher = game.getState().getWatcher(LostMonarchOfIfnirWatcher.class); - return watcher != null && watcher.wasDealtDamage(); + return game + .getState() + .getWatcher(LostMonarchOfIfnirWatcher.class) + .conditionMet(); + } + + @Override + public String toString() { + return "a player was dealt combat damage by a Zombie this turn"; } } class LostMonarchOfIfnirWatcher extends Watcher { - private boolean dealtDamage; //by a zombie this turn - LostMonarchOfIfnirWatcher() { - super(WatcherScope.GAME); - this.dealtDamage = false; + LostMonarchOfIfnirWatcher() { + super(WatcherScope.GAME); } @Override public void watch(GameEvent event, Game game) { Optional.of(event) .filter(e -> e.getType() == GameEvent.EventType.DAMAGED_PLAYER) - .filter(e -> e instanceof DamagedPlayerEvent) + .filter(DamagedPlayerEvent.class::isInstance) .map(DamagedPlayerEvent.class::cast) .filter(DamagedEvent::isCombatDamage) - .map(damagedPlayerEvent -> game.getPermanentOrLKIBattlefield(event.getSourceId())) + .map(GameEvent::getSourceId) + .map(game::getPermanentOrLKIBattlefield) .filter(permanent -> permanent.hasSubtype(SubType.ZOMBIE, game)) - .ifPresent(ignored -> this.dealtDamage = true); - } - - @Override - public void reset() { - super.reset(); - this.dealtDamage = false; - } - - boolean wasDealtDamage() { - return this.dealtDamage; + .ifPresent(ignored -> this.condition = true); } } - diff --git a/Mage.Sets/src/mage/cards/l/LothlorienBlade.java b/Mage.Sets/src/mage/cards/l/LothlorienBlade.java index bb1dbec9197..ca3814f9f50 100644 --- a/Mage.Sets/src/mage/cards/l/LothlorienBlade.java +++ b/Mage.Sets/src/mage/cards/l/LothlorienBlade.java @@ -15,7 +15,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.DefendingPlayerControlsAttachedAttackingPredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -34,16 +34,16 @@ public final class LothlorienBlade extends CardImpl { public LothlorienBlade(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); - + this.subtype.add(SubType.EQUIPMENT); // Whenever equipped creature attacks, it deals damage equal to its power to target creature defending player controls. Ability ability = new AttacksAttachedTriggeredAbility(new LothlorienBladeEffect()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Equip Elf {2} - this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2), new TargetControlledCreaturePermanent(filterElf), false)); + this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2), new TargetPermanent(filterElf), false)); // Equip {5} this.addAbility(new EquipAbility(5, false)); diff --git a/Mage.Sets/src/mage/cards/l/LouisoixsSacrifice.java b/Mage.Sets/src/mage/cards/l/LouisoixsSacrifice.java index 1e01f063bad..e01d3c9339d 100644 --- a/Mage.Sets/src/mage/cards/l/LouisoixsSacrifice.java +++ b/Mage.Sets/src/mage/cards/l/LouisoixsSacrifice.java @@ -1,6 +1,6 @@ package mage.cards.l; -import mage.abilities.costs.CompositeCost; +import mage.abilities.costs.OrCost; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.CounterTargetEffect; @@ -33,9 +33,10 @@ public final class LouisoixsSacrifice extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); // As an additional cost to cast this spell, sacrifice a legendary creature or pay {2}. - this.getSpellAbility().addCost(new CompositeCost( + this.getSpellAbility().addCost(new OrCost( + "sacrifice a legendary creature or pay {2}", new SacrificeTargetCost(StaticFilters.FILTER_CREATURE_LEGENDARY), - new GenericManaCost(2), "sacrifice a legendary creature or pay {2}" + new GenericManaCost(2) )); // Counter target activated ability, triggered ability, or noncreature spell. diff --git a/Mage.Sets/src/mage/cards/l/LowlandOaf.java b/Mage.Sets/src/mage/cards/l/LowlandOaf.java index 9ccd0920168..2d53361e007 100644 --- a/Mage.Sets/src/mage/cards/l/LowlandOaf.java +++ b/Mage.Sets/src/mage/cards/l/LowlandOaf.java @@ -20,6 +20,7 @@ import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -52,7 +53,7 @@ public final class LowlandOaf extends CardImpl { effect.setText("and gains flying until end of turn."); ability.addEffect(effect); ability.addEffect(new LowlandOafEffect()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/l/LoyalRetainers.java b/Mage.Sets/src/mage/cards/l/LoyalRetainers.java index 8d3b5f5649c..f7ed104d7a1 100644 --- a/Mage.Sets/src/mage/cards/l/LoyalRetainers.java +++ b/Mage.Sets/src/mage/cards/l/LoyalRetainers.java @@ -1,7 +1,5 @@ - package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -13,24 +11,25 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; +import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class LoyalRetainers extends CardImpl { - private static final FilterCreatureCard filter = new FilterCreatureCard("legendary creature card from your graveyard"); + private static final FilterCard filter = new FilterCreatureCard("legendary creature card from your graveyard"); static { filter.add(SuperType.LEGENDARY.getPredicate()); } public LoyalRetainers(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ADVISOR); @@ -38,10 +37,12 @@ public final class LoyalRetainers extends CardImpl { this.toughness = new MageInt(1); // Sacrifice Loyal Retainers: Return target legendary creature card from your graveyard to the battlefield. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect(), new SacrificeSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect(), + new SacrificeSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance + ); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); - } private LoyalRetainers(final LoyalRetainers card) { diff --git a/Mage.Sets/src/mage/cards/l/LoyalWarhound.java b/Mage.Sets/src/mage/cards/l/LoyalWarhound.java index 9f2162ccca8..b4939d4e19e 100644 --- a/Mage.Sets/src/mage/cards/l/LoyalWarhound.java +++ b/Mage.Sets/src/mage/cards/l/LoyalWarhound.java @@ -1,33 +1,29 @@ package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.OpponentControlsMoreCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; -import mage.constants.SubType; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SuperType; +import mage.constants.SubType; import mage.filter.FilterCard; import mage.filter.StaticFilters; +import mage.filter.common.FilterBasicLandCard; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class LoyalWarhound extends CardImpl { - private static final FilterCard filter = new FilterCard("basic Plains card"); - - static { - filter.add(SuperType.BASIC.getPredicate()); - filter.add(SubType.PLAINS.getPredicate()); - } + private static final FilterCard filter = new FilterBasicLandCard(SubType.PLAINS); + private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS); public LoyalWarhound(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); @@ -41,12 +37,9 @@ public final class LoyalWarhound extends CardImpl { // When Loyal Warhound enters the battlefield, if an opponent controls more lands than you, // search your library for a basic Plains card, put it onto the battlefield tapped, then shuffle. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true)), - new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS), - "When {this} enters, if an opponent controls more lands than you, " - + "search your library for a basic Plains card, put it onto the battlefield tapped, then shuffle." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true) + ).withInterveningIf(condition)); } private LoyalWarhound(final LoyalWarhound card) { diff --git a/Mage.Sets/src/mage/cards/l/LuSuWuAdvisor.java b/Mage.Sets/src/mage/cards/l/LuSuWuAdvisor.java index 0159246fb6c..6c1d058c8f3 100644 --- a/Mage.Sets/src/mage/cards/l/LuSuWuAdvisor.java +++ b/Mage.Sets/src/mage/cards/l/LuSuWuAdvisor.java @@ -1,9 +1,6 @@ - package mage.cards.l; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.MyTurnBeforeAttackersDeclaredCondition; import mage.abilities.costs.common.TapSourceCost; @@ -13,16 +10,16 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; + +import java.util.UUID; /** - * * @author fireshoes */ public final class LuSuWuAdvisor extends CardImpl { public LuSuWuAdvisor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ADVISOR); @@ -30,9 +27,10 @@ public final class LuSuWuAdvisor extends CardImpl { this.toughness = new MageInt(2); // {tap}: Draw a card. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new DrawCardSourceControllerEffect(1), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); - this.addAbility(ability); + this.addAbility(new ActivateIfConditionActivatedAbility( + new DrawCardSourceControllerEffect(1), new TapSourceCost(), + MyTurnBeforeAttackersDeclaredCondition.instance + )); } private LuSuWuAdvisor(final LuSuWuAdvisor card) { diff --git a/Mage.Sets/src/mage/cards/l/LumengridDrake.java b/Mage.Sets/src/mage/cards/l/LumengridDrake.java index 4b2bc03fc9e..459fd8f5923 100644 --- a/Mage.Sets/src/mage/cards/l/LumengridDrake.java +++ b/Mage.Sets/src/mage/cards/l/LumengridDrake.java @@ -1,10 +1,9 @@ package mage.cards.l; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.MetalcraftCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.hint.common.MetalcraftHint; import mage.abilities.keyword.FlyingAbility; @@ -22,8 +21,6 @@ import java.util.UUID; */ public final class LumengridDrake extends CardImpl { - private static final String ruleText = "When {this} enters, if you control three or more artifacts, return target creature to its owner's hand."; - public LumengridDrake(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); this.subtype.add(SubType.DRAKE); @@ -36,12 +33,10 @@ public final class LumengridDrake extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Metalcraft — When Lumengrid Drake enters the battlefield, if you control three or more artifacts, return target creature to its owner's hand. - TriggeredAbility conditional = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()), MetalcraftCondition.instance, ruleText); - conditional.addTarget(new TargetCreaturePermanent()); - conditional.setAbilityWord(AbilityWord.METALCRAFT); - conditional.addHint(MetalcraftHint.instance); - this.addAbility(conditional); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()) + .withInterveningIf(MetalcraftCondition.instance); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability.setAbilityWord(AbilityWord.METALCRAFT).addHint(MetalcraftHint.instance)); } private LumengridDrake(final LumengridDrake card) { diff --git a/Mage.Sets/src/mage/cards/l/LuminarchAscension.java b/Mage.Sets/src/mage/cards/l/LuminarchAscension.java index fdef9d188a2..326f1c55688 100644 --- a/Mage.Sets/src/mage/cards/l/LuminarchAscension.java +++ b/Mage.Sets/src/mage/cards/l/LuminarchAscension.java @@ -1,20 +1,17 @@ - package mage.cards.l; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TargetController; -import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.token.AngelToken; @@ -27,25 +24,21 @@ import java.util.UUID; */ public final class LuminarchAscension extends CardImpl { - private static final String rule = "At the beginning of each opponent's end step, " + - "if you didn't lose life this turn, you may put a quest counter on {this}."; private static final Condition condition = new SourceHasCounterCondition(CounterType.QUEST, 4); public LuminarchAscension(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); // At the beginning of each opponent's end step, if you didn't lose life this turn, you may put a quest counter on Luminarch Ascension. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - TargetController.OPPONENT, new AddCountersSourceEffect(CounterType.QUEST.createInstance()), - true - ), LuminarchAscensionCondition.instance, rule + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.OPPONENT, + new AddCountersSourceEffect(CounterType.QUEST.createInstance()), + true, LuminarchAscensionCondition.instance )); // {1}{W}: Create a 4/4 white Angel creature token with flying. Activate this ability only if Luminarch Ascension has four or more quest counters on it. this.addAbility(new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new CreateTokenEffect(new AngelToken()), - new ManaCostsImpl<>("{1}{W}"), condition + new CreateTokenEffect(new AngelToken()), new ManaCostsImpl<>("{1}{W}"), condition )); } @@ -64,10 +57,14 @@ enum LuminarchAscensionCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class); - if (watcher != null) { - return (watcher.getLifeLost(source.getControllerId()) == 0); - } - return false; + return game + .getState() + .getWatcher(PlayerLostLifeWatcher.class) + .getLifeLost(source.getControllerId()) == 0; + } + + @Override + public String toString() { + return "you didn't lose life this turn"; } } diff --git a/Mage.Sets/src/mage/cards/l/LurkingArynx.java b/Mage.Sets/src/mage/cards/l/LurkingArynx.java index 510b8d5c25e..7b85b2a6065 100644 --- a/Mage.Sets/src/mage/cards/l/LurkingArynx.java +++ b/Mage.Sets/src/mage/cards/l/LurkingArynx.java @@ -1,7 +1,5 @@ - package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -12,19 +10,19 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class LurkingArynx extends CardImpl { public LurkingArynx(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); this.subtype.add(SubType.CAT); this.subtype.add(SubType.BEAST); this.power = new MageInt(3); @@ -32,13 +30,11 @@ public final class LurkingArynx extends CardImpl { // Formidable — {2}{G}: Target creature blocks Lurking Arynx this turn if able. Activate this ability only if creatures you control have total power 8 or greater. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new MustBeBlockedByTargetSourceEffect(Duration.EndOfTurn), - new ManaCostsImpl<>("{2}{G}"), - FormidableCondition.instance); - ability.setAbilityWord(AbilityWord.FORMIDABLE); + new ManaCostsImpl<>("{2}{G}"), FormidableCondition.instance + ); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability); + this.addAbility(ability.setAbilityWord(AbilityWord.FORMIDABLE)); } private LurkingArynx(final LurkingArynx card) { diff --git a/Mage.Sets/src/mage/cards/l/LurkingChupacabra.java b/Mage.Sets/src/mage/cards/l/LurkingChupacabra.java index 3e993717b3a..651b38cec79 100644 --- a/Mage.Sets/src/mage/cards/l/LurkingChupacabra.java +++ b/Mage.Sets/src/mage/cards/l/LurkingChupacabra.java @@ -12,8 +12,11 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author TheElk801 @@ -30,7 +33,7 @@ public final class LurkingChupacabra extends CardImpl { // Whenever a creature you control explores, target creature an opponent controls gets -2/-2 until end of turn Ability ability = new CreatureExploresTriggeredAbility(new BoostTargetEffect(-2, -2, Duration.EndOfTurn)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/l/LurkingJackals.java b/Mage.Sets/src/mage/cards/l/LurkingJackals.java index e10149b40a0..d7022a2c54d 100644 --- a/Mage.Sets/src/mage/cards/l/LurkingJackals.java +++ b/Mage.Sets/src/mage/cards/l/LurkingJackals.java @@ -1,7 +1,7 @@ package mage.cards.l; -import mage.MageInt; import mage.abilities.StateTriggeredAbility; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -11,7 +11,8 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; +import mage.players.Player; import java.util.UUID; @@ -40,9 +41,12 @@ public final class LurkingJackals extends CardImpl { class LurkingJackalsStateTriggeredAbility extends StateTriggeredAbility { public LurkingJackalsStateTriggeredAbility() { - super(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new LurkingJackalsToken(), null, Duration.Custom)); - setTriggerPhrase("When an opponent has 10 or less life, if {this} is an enchantment, "); + super(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new CreatureToken( + 3, 2, "3/2 Jackal creature", SubType.JACKAL + ), null, Duration.Custom)); + this.withInterveningIf(SourceIsEnchantmentCondition.instance); this.withRuleTextReplacement(true); + this.setTriggerPhrase("When an opponent has 10 or less life, "); } private LurkingJackalsStateTriggeredAbility(final LurkingJackalsStateTriggeredAbility ability) { @@ -56,42 +60,11 @@ class LurkingJackalsStateTriggeredAbility extends StateTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (game.getOpponents(getControllerId()) != null) { - for (UUID opponentId : game.getOpponents(getControllerId())) { - if (game.getPlayer(opponentId).getLife() <= 10) { - return true; - } - } - } - return false; - } - - @Override - public boolean checkInterveningIfClause(Game game) { - if (getSourcePermanentIfItStillExists(game) != null) { - return getSourcePermanentIfItStillExists(game).isEnchantment(game); - } - return false; - } - -} - -class LurkingJackalsToken extends TokenImpl { - - public LurkingJackalsToken() { - super("Dog", "3/2 Jackal creature"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.JACKAL); - power = new MageInt(3); - toughness = new MageInt(2); - } - - private LurkingJackalsToken(final LurkingJackalsToken token) { - super(token); - } - - @Override - public LurkingJackalsToken copy() { - return new LurkingJackalsToken(this); + return game + .getOpponents(getControllerId()) + .stream() + .map(game::getPlayer) + .mapToInt(Player::getLife) + .anyMatch(x -> x <= 10); } } diff --git a/Mage.Sets/src/mage/cards/l/LurkingSkirge.java b/Mage.Sets/src/mage/cards/l/LurkingSkirge.java index e1ed2ce781a..0dc66fc1257 100644 --- a/Mage.Sets/src/mage/cards/l/LurkingSkirge.java +++ b/Mage.Sets/src/mage/cards/l/LurkingSkirge.java @@ -1,11 +1,7 @@ package mage.cards.l; -import java.util.UUID; -import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.PutIntoGraveFromBattlefieldAllTriggeredAbility; -import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -14,18 +10,18 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.constants.TargetController; -import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class LurkingSkirge extends CardImpl { - + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - + static { filter.add(TargetController.OPPONENT.getOwnerPredicate()); } @@ -34,9 +30,14 @@ public final class LurkingSkirge extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); // When a creature is put into an opponent's graveyard from the battlefield, if Lurking Skirge is an enchantment, Lurking Skirge becomes a 3/2 Imp creature with flying. - TriggeredAbility ability = new PutIntoGraveFromBattlefieldAllTriggeredAbility(new BecomesCreatureSourceEffect(new LurkingSkirgeToken(), null, Duration.WhileOnBattlefield), false, filter, false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), - "When a creature is put into an opponent's graveyard from the battlefield, if {this} is an enchantment, {this} becomes a 3/2 Phyrexian Imp creature with flying.")); + this.addAbility(new PutIntoGraveFromBattlefieldAllTriggeredAbility(new BecomesCreatureSourceEffect( + new CreatureToken( + 3, 2, "3/2 Phyrexian Imp creature with flying", SubType.PHYREXIAN, SubType.IMP + ).withAbility(FlyingAbility.getInstance()), null, Duration.WhileOnBattlefield + ), false, filter, false) + .withInterveningIf(SourceIsEnchantmentCondition.instance) + .withRuleTextReplacement(true) + .setTriggerPhrase("When a creature is put into an opponent's graveyard from the battlefield, ")); } private LurkingSkirge(final LurkingSkirge card) { @@ -48,24 +49,3 @@ public final class LurkingSkirge extends CardImpl { return new LurkingSkirge(this); } } - -class LurkingSkirgeToken extends TokenImpl { - - public LurkingSkirgeToken() { - super("Phyrexian Imp", "3/2 Phyrexian Imp with flying."); - cardType.add(CardType.CREATURE); - subtype.add(SubType.PHYREXIAN); - subtype.add(SubType.IMP); - power = new MageInt(3); - toughness = new MageInt(2); - this.addAbility(FlyingAbility.getInstance()); - } - - private LurkingSkirgeToken(final LurkingSkirgeToken token) { - super(token); - } - - public LurkingSkirgeToken copy() { - return new LurkingSkirgeToken(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LutriTheSpellchaser.java b/Mage.Sets/src/mage/cards/l/LutriTheSpellchaser.java index 818845b3be4..8d0c7c65af5 100644 --- a/Mage.Sets/src/mage/cards/l/LutriTheSpellchaser.java +++ b/Mage.Sets/src/mage/cards/l/LutriTheSpellchaser.java @@ -5,7 +5,6 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CopyTargetStackObjectEffect; import mage.abilities.keyword.CompanionAbility; import mage.abilities.keyword.CompanionCondition; @@ -54,12 +53,8 @@ public final class LutriTheSpellchaser extends CardImpl { this.addAbility(FlashAbility.getInstance()); // When Lutri, the Spellchaser enters the battlefield, if you cast it, copy target instant or sorcery spell you control. You may choose new targets for the copy. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CopyTargetStackObjectEffect(), false), - CastFromEverywhereSourceCondition.instance, "When {this} enters, " + - "if you cast it, copy target instant or sorcery spell you control. " + - "You may choose new targets for the copy." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new CopyTargetStackObjectEffect()) + .withInterveningIf(CastFromEverywhereSourceCondition.instance); ability.addTarget(new TargetSpell(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/l/LuxaRiverShrine.java b/Mage.Sets/src/mage/cards/l/LuxaRiverShrine.java index 44b5a6d7b5f..f18c3661555 100644 --- a/Mage.Sets/src/mage/cards/l/LuxaRiverShrine.java +++ b/Mage.Sets/src/mage/cards/l/LuxaRiverShrine.java @@ -6,7 +6,7 @@ import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; @@ -33,7 +33,7 @@ public final class LuxaRiverShrine extends CardImpl { this.addAbility(ability); // {T}: You gain 2 life. Activate this ability only if there are three or more brick counters on Luxa River Shrine. - this.addAbility(new ConditionalActivatedAbility(new GainLifeEffect(2), new TapSourceCost(), condition)); + this.addAbility(new ActivateIfConditionActivatedAbility(new GainLifeEffect(2), new TapSourceCost(), condition)); } private LuxaRiverShrine(final LuxaRiverShrine card) { diff --git a/Mage.Sets/src/mage/cards/l/LysAlanaBowmaster.java b/Mage.Sets/src/mage/cards/l/LysAlanaBowmaster.java index 25e31c5d426..d031b08afd3 100644 --- a/Mage.Sets/src/mage/cards/l/LysAlanaBowmaster.java +++ b/Mage.Sets/src/mage/cards/l/LysAlanaBowmaster.java @@ -13,6 +13,7 @@ import mage.constants.SubType; import mage.filter.FilterSpell; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -40,7 +41,7 @@ public final class LysAlanaBowmaster extends CardImpl { this.addAbility(ReachAbility.getInstance()); Ability ability = new SpellCastControllerTriggeredAbility(new DamageTargetEffect(2) .setText("{this} deal 2 damage to target creature with flying"), filterElf, true); - ability.addTarget(new TargetCreaturePermanent(filterFlying)); + ability.addTarget(new TargetPermanent(filterFlying)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MabelsMettle.java b/Mage.Sets/src/mage/cards/m/MabelsMettle.java index 81f1690ff91..f19ce6ac47a 100644 --- a/Mage.Sets/src/mage/cards/m/MabelsMettle.java +++ b/Mage.Sets/src/mage/cards/m/MabelsMettle.java @@ -5,6 +5,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.SecondTargetPointer; @@ -18,12 +19,11 @@ public final class MabelsMettle extends CardImpl { public MabelsMettle(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); - // Target creature gets +2/+2 until end of turn. Up to one other target creature gets +1/+1 until end of turn. this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2)); this.getSpellAbility().addTarget(new TargetCreaturePermanent().setTargetTag(1)); this.getSpellAbility().addEffect(new BoostTargetEffect(1, 1).setTargetPointer(new SecondTargetPointer())); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1, StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2, false).setTargetTag(2)); + this.getSpellAbility().addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2).setTargetTag(2)); } private MabelsMettle(final MabelsMettle card) { diff --git a/Mage.Sets/src/mage/cards/m/MadAuntie.java b/Mage.Sets/src/mage/cards/m/MadAuntie.java index 19aa0e37958..f6790689ed1 100644 --- a/Mage.Sets/src/mage/cards/m/MadAuntie.java +++ b/Mage.Sets/src/mage/cards/m/MadAuntie.java @@ -18,6 +18,7 @@ import mage.constants.Zone; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -46,7 +47,7 @@ public final class MadAuntie extends CardImpl { // {T}: Regenerate another target Goblin. Ability ability = new SimpleActivatedAbility(new RegenerateTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter1)); + ability.addTarget(new TargetPermanent(filter1)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MadDog.java b/Mage.Sets/src/mage/cards/m/MadDog.java index f8d45d22f2b..17ee7d1312c 100644 --- a/Mage.Sets/src/mage/cards/m/MadDog.java +++ b/Mage.Sets/src/mage/cards/m/MadDog.java @@ -1,27 +1,24 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.condition.InvertCondition; -import mage.abilities.condition.OrCondition; import mage.abilities.condition.common.AttackedThisTurnSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.SacrificeSourceEffect; -import mage.constants.SubType; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.Optional; +import java.util.UUID; + /** * @author xenohedron */ - public final class MadDog extends CardImpl { public MadDog(UUID ownerId, CardSetInfo setInfo) { @@ -32,12 +29,9 @@ public final class MadDog extends CardImpl { this.toughness = new MageInt(2); // At the beginning of your end step, if Mad Dog didn't attack or come under your control this turn, sacrifice it. - Condition condition = new InvertCondition(new OrCondition(AttackedThisTurnSourceCondition.instance, MadDogCondition.instance)); - Ability ability = new ConditionalInterveningIfTriggeredAbility(new BeginningOfEndStepTriggeredAbility( - new SacrificeSourceEffect()), condition, - "At the beginning of your end step, if {this} didn't attack or come under your control this turn, sacrifice it"); - this.addAbility(ability); - + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new SacrificeSourceEffect().setText("sacrifice it") + ).withInterveningIf(MadDogCondition.instance)); } private MadDog(final MadDog card) { @@ -55,8 +49,15 @@ enum MadDogCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = source.getSourcePermanentOrLKI(game); - // TRUE if came under your control this turn - return permanent != null && !permanent.wasControlledFromStartOfControllerTurn(); + return !AttackedThisTurnSourceCondition.instance.apply(game, source) + && Optional + .ofNullable(source.getSourcePermanentOrLKI(game)) + .filter(Permanent::wasControlledFromStartOfControllerTurn) + .isPresent(); + } + + @Override + public String toString() { + return "{this} didn't attack or come under your control this turn"; } } diff --git a/Mage.Sets/src/mage/cards/m/MadblindMountain.java b/Mage.Sets/src/mage/cards/m/MadblindMountain.java index f635a3fb40c..e20d6b4ba2c 100644 --- a/Mage.Sets/src/mage/cards/m/MadblindMountain.java +++ b/Mage.Sets/src/mage/cards/m/MadblindMountain.java @@ -1,39 +1,40 @@ - package mage.cards.m; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.ShuffleLibrarySourceEffect; import mage.abilities.mana.RedManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; -import mage.constants.Zone; +import mage.constants.SubType; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class MadblindMountain extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("if you control two or more red permanents"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("you control two or more red permanents"); static { filter.add(new ColorPredicate(ObjectColor.RED)); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); + public MadblindMountain(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); this.subtype.add(SubType.MOUNTAIN); // ({tap}: Add {R}.) @@ -43,13 +44,11 @@ public final class MadblindMountain extends CardImpl { this.addAbility(new EntersBattlefieldTappedAbility()); // {R}, {tap}: Shuffle your library. Activate this ability only if you control two or more red permanents. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new ShuffleLibrarySourceEffect(), - new ManaCostsImpl<>("{R}"), - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1)); + Ability ability = new ActivateIfConditionActivatedAbility( + new ShuffleLibrarySourceEffect(), new ManaCostsImpl<>("{R}"), condition + ); ability.addCost(new TapSourceCost()); this.addAbility(ability); - } private MadblindMountain(final MadblindMountain card) { diff --git a/Mage.Sets/src/mage/cards/m/MaddeningImp.java b/Mage.Sets/src/mage/cards/m/MaddeningImp.java index 06a989f264d..569389556ce 100644 --- a/Mage.Sets/src/mage/cards/m/MaddeningImp.java +++ b/Mage.Sets/src/mage/cards/m/MaddeningImp.java @@ -1,18 +1,15 @@ - package mage.cards.m; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.OpponentsTurnCondition; import mage.abilities.condition.common.TargetAttackedThisTurnCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.combat.AttacksIfAbleAllEffect; import mage.abilities.keyword.FlyingAbility; @@ -26,18 +23,20 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.watchers.common.AttackedThisTurnWatcher; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author L_J */ public final class MaddeningImp extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Wall creatures"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Wall creatures the active player controls"); static { filter.add(Predicates.not(SubType.WALL.getPredicate())); filter.add(TargetController.ACTIVE.getControllerPredicate()); - filter.setMessage("non-Wall creatures the active player controls"); } public MaddeningImp(UUID ownerId, CardSetInfo setInfo) { @@ -50,14 +49,12 @@ public final class MaddeningImp extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // {T}: Non-Wall creatures the active player controls attack this turn if able. At the beginning of the next end step, destroy each of those creatures that didn't attack this turn. Activate this ability only during an opponent's turn and only before combat. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new AttacksIfAbleAllEffect(filter, Duration.EndOfTurn), - new TapSourceCost(), new MaddeningImpTurnCondition(), - "{T}: Non-Wall creatures the active player controls attack this turn if able. " - + "At the beginning of the next end step, destroy each of those creatures that didn't attack this turn. " - + "Activate only during an opponent's turn and only before combat."); + Ability ability = new ActivateIfConditionActivatedAbility( + new AttacksIfAbleAllEffect(filter, Duration.EndOfTurn), + new TapSourceCost(), MaddeningImpTurnCondition.instance + ); ability.addEffect(new MaddeningImpCreateDelayedTriggeredAbilityEffect()); this.addAbility(ability); - } private MaddeningImp(final MaddeningImp card) { @@ -70,17 +67,17 @@ public final class MaddeningImp extends CardImpl { } } -class MaddeningImpTurnCondition implements Condition { +enum MaddeningImpTurnCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { - Player activePlayer = game.getPlayer(game.getActivePlayerId()); - return activePlayer != null && activePlayer.hasOpponent(source.getControllerId(), game) && game.getPhase().getStep().getType().getIndex() < 5; + return OpponentsTurnCondition.instance.apply(game, source) && !game.getTurn().isDeclareAttackersStepStarted(); } @Override public String toString() { - return ""; + return "during an opponent's turn and only before combat"; } } @@ -150,7 +147,7 @@ class MaddeningImpDelayedDestroyEffect extends OneShotEffect { Player player = game.getPlayer(game.getActivePlayerId()); if (player != null) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(player.getId())) { - + MageObjectReference mor = new MageObjectReference(permanent, game); // Only affect permanents present when the ability resolved if (!activeCreatures.contains(mor)) { diff --git a/Mage.Sets/src/mage/cards/m/MaestrosDiabolist.java b/Mage.Sets/src/mage/cards/m/MaestrosDiabolist.java index 85596a1765f..e965f604851 100644 --- a/Mage.Sets/src/mage/cards/m/MaestrosDiabolist.java +++ b/Mage.Sets/src/mage/cards/m/MaestrosDiabolist.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.HasteAbility; @@ -25,7 +24,7 @@ import java.util.UUID; */ public final class MaestrosDiabolist extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent(SubType.DEVIL); + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.DEVIL, "you don't control a Devil token"); static { filter.add(TokenPredicate.TRUE); @@ -49,13 +48,9 @@ public final class MaestrosDiabolist extends CardImpl { this.addAbility(HasteAbility.getInstance()); // Whenever Maestros Diabolist attacks, if you don't control a Devil token, create a tapped and attacking 1/1 red Devil creature token with "When this creature dies, it deals 1 damage to any target." - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility( - new CreateTokenEffect(new DevilToken(), 1, true, true) - ), condition, "Whenever {this} attacks, if you don't control a Devil token, " + - "create a tapped and attacking 1/1 red Devil creature token with " + - "\"When this creature dies, it deals 1 damage to any target.\"" - )); + this.addAbility(new AttacksTriggeredAbility( + new CreateTokenEffect(new DevilToken(), 1, true, true) + ).withInterveningIf(condition)); } private MaestrosDiabolist(final MaestrosDiabolist card) { diff --git a/Mage.Sets/src/mage/cards/m/MageRingResponder.java b/Mage.Sets/src/mage/cards/m/MageRingResponder.java index 56ce5c14dca..86bab2ed384 100644 --- a/Mage.Sets/src/mage/cards/m/MageRingResponder.java +++ b/Mage.Sets/src/mage/cards/m/MageRingResponder.java @@ -1,9 +1,8 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -13,23 +12,24 @@ import mage.abilities.effects.common.UntapSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SetTargetPointer; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; + +import java.util.UUID; /** - * * @author fireshoes */ public final class MageRingResponder extends CardImpl { + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creature defending player controls"); + public MageRingResponder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{7}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{7}"); this.subtype.add(SubType.GOLEM); this.power = new MageInt(7); this.toughness = new MageInt(7); @@ -41,7 +41,10 @@ public final class MageRingResponder extends CardImpl { this.addAbility(new SimpleActivatedAbility(new UntapSourceEffect(), new ManaCostsImpl<>("{7}"))); // Whenever Mage-Ring Responder attacks, it deals 7 damage to target creature defending player controls. - this.addAbility(new MageRingResponderAbility()); + Ability ability = new AttacksTriggeredAbility(new DamageTargetEffect(7), false, null, SetTargetPointer.PLAYER); + ability.addTarget(new TargetPermanent(filter)); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); + this.addAbility(ability); } private MageRingResponder(final MageRingResponder card) { @@ -53,44 +56,3 @@ public final class MageRingResponder extends CardImpl { return new MageRingResponder(this); } } - -class MageRingResponderAbility extends TriggeredAbilityImpl { - - public MageRingResponderAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(7)); - } - - private MageRingResponderAbility(final MageRingResponderAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ATTACKER_DECLARED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getSourceId().equals(this.getSourceId())) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); - UUID defenderId = game.getCombat().getDefenderId(sourceId); - filter.add(new ControllerIdPredicate(defenderId)); - - this.getTargets().clear(); - TargetCreaturePermanent target = new TargetCreaturePermanent(filter); - this.addTarget(target); - return true; - } - return false; - } - - @Override - public String getRule() { - return "Whenever {this} attacks, it deals 7 damage to target creature defending player controls."; - } - - @Override - public MageRingResponderAbility copy() { - return new MageRingResponderAbility(this); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MagewrightsStone.java b/Mage.Sets/src/mage/cards/m/MagewrightsStone.java index 64467e9ceb9..95a789e6842 100644 --- a/Mage.Sets/src/mage/cards/m/MagewrightsStone.java +++ b/Mage.Sets/src/mage/cards/m/MagewrightsStone.java @@ -16,6 +16,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicate; import mage.game.Game; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -37,7 +38,7 @@ public final class MagewrightsStone extends CardImpl { // {1}, {T}: Untap target creature that has an activated ability with {T} in its cost. Ability ability = new SimpleActivatedAbility(new UntapTargetEffect(), new ManaCostsImpl<>("{1}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MagmaSliver.java b/Mage.Sets/src/mage/cards/m/MagmaSliver.java index d5d4217f715..6bacede7d4a 100644 --- a/Mage.Sets/src/mage/cards/m/MagmaSliver.java +++ b/Mage.Sets/src/mage/cards/m/MagmaSliver.java @@ -20,8 +20,11 @@ import mage.constants.Zone; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.constants.SubType.SLIVER; + /** * * @author cbt33 @@ -42,8 +45,7 @@ public final class MagmaSliver extends CardImpl { StaticFilters.FILTER_PERMANENT_ALL_SLIVERS), StaticValue.get(0), Duration.EndOfTurn), new TapSourceCost()); - Target target = new TargetCreaturePermanent( - new FilterCreaturePermanent(SubType.SLIVER, "Sliver creature")); + Target target = new TargetPermanent(new FilterCreaturePermanent(SLIVER, "Sliver creature")); ability.addTarget(target); Effect effect = new GainAbilityAllEffect(ability, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_ALL_SLIVERS); diff --git a/Mage.Sets/src/mage/cards/m/MagneticMountain.java b/Mage.Sets/src/mage/cards/m/MagneticMountain.java index bc2aa00d7f2..69cfeeb18ca 100644 --- a/Mage.Sets/src/mage/cards/m/MagneticMountain.java +++ b/Mage.Sets/src/mage/cards/m/MagneticMountain.java @@ -1,16 +1,19 @@ - package mage.cards.m; import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.Cost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DontUntapInControllersUntapStepAllEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; @@ -19,7 +22,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; import mage.util.ManaUtil; import java.util.UUID; @@ -29,7 +32,7 @@ import java.util.UUID; */ public final class MagneticMountain extends CardImpl { - static final FilterCreaturePermanent filter = new FilterCreaturePermanent("blue creatures"); + static final FilterPermanent filter = new FilterCreaturePermanent("blue creatures"); static { filter.add(new ColorPredicate(ObjectColor.BLUE)); @@ -80,28 +83,27 @@ class MagneticMountainEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - - Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (player != null && sourcePermanent != null) { - int countBattlefield = game.getBattlefield().getAllActivePermanents(filter2, game.getActivePlayerId(), game).size(); - while (player.canRespond() && countBattlefield > 0 && player.chooseUse(Outcome.Benefit, "Pay {4} and untap a tapped blue creature under your control?", source, game)) { - Target tappedCreatureTarget = new TargetControlledCreaturePermanent(1, 1, filter2, true); - if (player.choose(Outcome.Untap, tappedCreatureTarget, source, game)) { - Cost cost = ManaUtil.createManaCost(4, false); - Permanent tappedCreature = game.getPermanent(tappedCreatureTarget.getFirstTarget()); - if (tappedCreature != null && cost.pay(source, game, source, player.getId(), false)) { - tappedCreature.untap(game); - } else { - break; - } + Player player = game.getPlayer(game.getActivePlayerId()); + if (player == null) { + return false; + } + int countBattlefield = game.getBattlefield().getAllActivePermanents(filter2, game.getActivePlayerId(), game).size(); + while (player.canRespond() && countBattlefield > 0 && player.chooseUse(Outcome.Benefit, "Pay {4} and untap a tapped blue creature under your control?", source, game)) { + Target tappedCreatureTarget = new TargetControlledPermanent(filter2); + tappedCreatureTarget.withNotTarget(true); + if (player.choose(Outcome.Untap, tappedCreatureTarget, source, game)) { + Cost cost = ManaUtil.createManaCost(4, false); + Permanent tappedCreature = game.getPermanent(tappedCreatureTarget.getFirstTarget()); + if (tappedCreature != null && cost.pay(source, game, source, player.getId(), false)) { + tappedCreature.untap(game); } else { break; } - countBattlefield = game.getBattlefield().getAllActivePermanents(filter2, game.getActivePlayerId(), game).size(); + } else { + break; } - return true; + countBattlefield = game.getBattlefield().getAllActivePermanents(filter2, game.getActivePlayerId(), game).size(); } - return false; + return true; } } diff --git a/Mage.Sets/src/mage/cards/m/MagusOfTheAbyss.java b/Mage.Sets/src/mage/cards/m/MagusOfTheAbyss.java index 2d293a138d2..37b91a639c2 100644 --- a/Mage.Sets/src/mage/cards/m/MagusOfTheAbyss.java +++ b/Mage.Sets/src/mage/cards/m/MagusOfTheAbyss.java @@ -1,39 +1,45 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; -import mage.game.events.GameEvent; -import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; +import mage.target.targetpointer.FirstTargetPointer; + +import java.util.UUID; /** - * * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class MagusOfTheAbyss extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent("nonartifact creature that player controls of their choice"); + public MagusOfTheAbyss(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(4); this.toughness = new MageInt(3); // At the beginning of each player's upkeep, destroy target nonartifact creature that player controls of their choice. It can't be regenerated. - this.addAbility(new MagusOfTheAbyssTriggeredAbility()); + Ability ability = new BeginningOfUpkeepTriggeredAbility(TargetController.EACH_PLAYER, + new DestroyTargetEffect(true), false).withTargetPointerSet(true); + ability.addTarget(new TargetPermanent(filter)); // Only used for text generation + ability.setTargetAdjuster(MagusOfTheAbyssTargetAdjuster.instance); + this.addAbility(ability); } private MagusOfTheAbyss(final MagusOfTheAbyss card) { @@ -46,45 +52,27 @@ public final class MagusOfTheAbyss extends CardImpl { } } -class MagusOfTheAbyssTriggeredAbility extends TriggeredAbilityImpl { +enum MagusOfTheAbyssTargetAdjuster implements TargetAdjuster { + instance; - MagusOfTheAbyssTriggeredAbility() { - super(Zone.BATTLEFIELD, new DestroyTargetEffect(true), false); - } + private static final FilterPermanent filter + = new FilterPermanent("nonartifact creature that player controls of their choice"); - private MagusOfTheAbyssTriggeredAbility(final MagusOfTheAbyssTriggeredAbility ability) { - super(ability); + static { + filter.add(Predicates.not(CardType.ARTIFACT.getPredicate())); + filter.add(CardType.CREATURE.getPredicate()); } @Override - public MagusOfTheAbyssTriggeredAbility copy() { - return new MagusOfTheAbyssTriggeredAbility(this); - } + public void adjustTargets(Ability ability, Game game) { + UUID opponentId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability); + ability.getTargets().clear(); + ability.getAllEffects().setTargetPointer(new FirstTargetPointer()); - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE; + FilterPermanent adjustedFilter = filter.copy(); + adjustedFilter.add(new ControllerIdPredicate(opponentId)); + Target newTarget = new TargetPermanent(adjustedFilter); + newTarget.setTargetController(opponentId); + ability.addTarget(newTarget); } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Player player = game.getPlayer(event.getPlayerId()); - if (player != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("nonartifact creature you control"); - filter.add(Predicates.not(CardType.ARTIFACT.getPredicate())); - filter.add(new ControllerIdPredicate(player.getId())); - Target target = new TargetCreaturePermanent(filter); - target.setAbilityController(getControllerId()); - target.setTargetController(player.getId()); - this.getTargets().clear(); - this.getTargets().add(target); - return true; - } - return false; - } - - @Override - public String getRule() { - return "At the beginning of each player's upkeep, destroy target nonartifact creature that player controls of their choice. It can't be regenerated."; - } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/m/MagusOfTheLibrary.java b/Mage.Sets/src/mage/cards/m/MagusOfTheLibrary.java index a6e0bca334b..9c61c7fc0ed 100644 --- a/Mage.Sets/src/mage/cards/m/MagusOfTheLibrary.java +++ b/Mage.Sets/src/mage/cards/m/MagusOfTheLibrary.java @@ -1,28 +1,29 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInHandCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; -import mage.constants.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author fireshoes */ public final class MagusOfTheLibrary extends CardImpl { + private static final Condition condition = new CardsInHandCondition(ComparisonType.EQUAL_TO, 7); + public MagusOfTheLibrary(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{G}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(1); @@ -30,14 +31,11 @@ public final class MagusOfTheLibrary extends CardImpl { // {tap}: Add {C}. this.addAbility(new ColorlessManaAbility()); - + // {tap}: Draw a card. Activate this ability only if you have exactly seven cards in hand. - this.addAbility(new ConditionalActivatedAbility( - Zone.BATTLEFIELD, - new DrawCardSourceControllerEffect(1), - new TapSourceCost(), - new CardsInHandCondition(ComparisonType.EQUAL_TO, 7), - "")); + this.addAbility(new ActivateIfConditionActivatedAbility( + new DrawCardSourceControllerEffect(1), new TapSourceCost(), condition + )); } private MagusOfTheLibrary(final MagusOfTheLibrary card) { diff --git a/Mage.Sets/src/mage/cards/m/MagusOfTheMirror.java b/Mage.Sets/src/mage/cards/m/MagusOfTheMirror.java index 2583026ea28..e354c4a6f96 100644 --- a/Mage.Sets/src/mage/cards/m/MagusOfTheMirror.java +++ b/Mage.Sets/src/mage/cards/m/MagusOfTheMirror.java @@ -1,24 +1,21 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.ExchangeLifeControllerTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.PhaseStep; -import mage.constants.Zone; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class MagusOfTheMirror extends CardImpl { @@ -31,11 +28,9 @@ public final class MagusOfTheMirror extends CardImpl { this.toughness = new MageInt(2); // {tap}, Sacrifice Magus of the Mirror: Exchange life totals with target opponent. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, + Ability ability = new ActivateIfConditionActivatedAbility( new ExchangeLifeControllerTargetEffect(), - new TapSourceCost(), - new IsStepCondition(PhaseStep.UPKEEP) + new TapSourceCost(), IsStepCondition.getMyUpkeep() ); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetOpponent()); diff --git a/Mage.Sets/src/mage/cards/m/MagusOfTheOrder.java b/Mage.Sets/src/mage/cards/m/MagusOfTheOrder.java index 2a76e8cbe86..f2c185a3ce2 100644 --- a/Mage.Sets/src/mage/cards/m/MagusOfTheOrder.java +++ b/Mage.Sets/src/mage/cards/m/MagusOfTheOrder.java @@ -17,10 +17,9 @@ import mage.constants.SubType; import mage.filter.FilterCard; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetCardInLibrary; -import mage.target.common.TargetControlledPermanent; import java.util.UUID; @@ -55,7 +54,7 @@ public final class MagusOfTheOrder extends CardImpl { ability.addCost(new TapSourceCost()); ability.addCost(new CompositeCost( new SacrificeSourceCost(), new SacrificeTargetCost(filter2), - "sacrifice Magus of the Order and another green creature" + "sacrifice {this} and another green creature" )); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MajesticMyriarch.java b/Mage.Sets/src/mage/cards/m/MajesticMyriarch.java index 872bc34dd09..5cd12311a23 100644 --- a/Mage.Sets/src/mage/cards/m/MajesticMyriarch.java +++ b/Mage.Sets/src/mage/cards/m/MajesticMyriarch.java @@ -2,7 +2,6 @@ package mage.cards.m; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.MultipliedValue; @@ -12,6 +11,7 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; import mage.abilities.keyword.*; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -87,7 +87,7 @@ class MajesticMyriarchEffect extends OneShotEffect { MajesticMyriarchEffect() { super(Outcome.BoostCreature); - this.staticText = "if you control a creature with flying, Majestic Myriarch gains flying until end of turn. " + + this.staticText = "if you control a creature with flying, {this} gains flying until end of turn. " + "The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, reach, trample, and vigilance."; } diff --git a/Mage.Sets/src/mage/cards/m/MalametVeteran.java b/Mage.Sets/src/mage/cards/m/MalametVeteran.java index d88a452d28a..00d00aea653 100644 --- a/Mage.Sets/src/mage/cards/m/MalametVeteran.java +++ b/Mage.Sets/src/mage/cards/m/MalametVeteran.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.DescendCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; @@ -24,7 +23,7 @@ public final class MalametVeteran extends CardImpl { public MalametVeteran(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); - + this.subtype.add(SubType.CAT); this.subtype.add(SubType.WARRIOR); this.power = new MageInt(5); @@ -34,13 +33,9 @@ public final class MalametVeteran extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Descend 4 -- Whenever Malamet Veteran attacks, if there are four or more permanent cards in your graveyard, put a +1/+1 counter on target creature. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new AttacksTriggeredAbility( - new AddCountersTargetEffect(CounterType.P1P1.createInstance())), DescendCondition.FOUR, - "Whenever {this} attacks, if there are four or more permanent cards in your graveyard, put a +1/+1 counter on target creature." - ); + Ability ability = new AttacksTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())).withInterveningIf(DescendCondition.FOUR); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability.setAbilityWord(AbilityWord.DESCEND_4).addHint(DescendCondition.getHint())); - } private MalametVeteran(final MalametVeteran card) { diff --git a/Mage.Sets/src/mage/cards/m/MaliciousAffliction.java b/Mage.Sets/src/mage/cards/m/MaliciousAffliction.java index e537e4dd686..25669eb4fa8 100644 --- a/Mage.Sets/src/mage/cards/m/MaliciousAffliction.java +++ b/Mage.Sets/src/mage/cards/m/MaliciousAffliction.java @@ -1,20 +1,22 @@ package mage.cards.m; -import mage.abilities.Ability; import mage.abilities.condition.common.MorbidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CastSourceTriggeredAbility; import mage.abilities.effects.common.CopySourceSpellEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.hint.common.MorbidHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * @author LevelX2 */ @@ -24,17 +26,13 @@ public final class MaliciousAffliction extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}{B}"); // Morbid — When you cast Malicious Affliction, if a creature died this turn, you may copy Malicious Affliction and may choose a new target for the copy. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new CastSourceTriggeredAbility(new CopySourceSpellEffect(), true), - MorbidCondition.instance, "Morbid — When you cast this spell, " + - "if a creature died this turn, you may copy {this} and may choose a new target for the copy." - ); - ability.setRuleAtTheTop(true); - this.addAbility(ability.addHint(MorbidHint.instance)); + this.addAbility(new CastSourceTriggeredAbility( + new CopySourceSpellEffect().setText("copy {this} and may choose a new target for the copy"), true + ).withInterveningIf(MorbidCondition.instance).setAbilityWord(AbilityWord.MORBID).addHint(MorbidHint.instance).setRuleAtTheTop(true)); // Destroy target nonblack creature. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); } private MaliciousAffliction(final MaliciousAffliction card) { diff --git a/Mage.Sets/src/mage/cards/m/ManaCache.java b/Mage.Sets/src/mage/cards/m/ManaCache.java index 3bc422f2550..b6592f70579 100644 --- a/Mage.Sets/src/mage/cards/m/ManaCache.java +++ b/Mage.Sets/src/mage/cards/m/ManaCache.java @@ -1,40 +1,52 @@ package mage.cards.m; import mage.Mana; -import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.costs.common.RemoveCountersSourceCost; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.mana.BasicManaEffect; import mage.abilities.mana.ActivatedManaAbilityImpl; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.constants.TargetController; +import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; import mage.players.Player; import java.util.UUID; -import mage.abilities.dynamicvalue.common.CountersSourceCount; /** * @author L_J */ public final class ManaCache extends CardImpl { + private static final FilterPermanent filter = new FilterLandPermanent("untapped land that player controls"); + + static { + filter.add(TappedPredicate.UNTAPPED); + filter.add(TargetController.ACTIVE.getControllerPredicate()); + } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + public ManaCache(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}{R}"); // At the beginning of each player's end step, put a charge counter on Mana Cache for each untapped land that player controls. - TriggeredAbility ability = new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of each player's end step", true, new ManaCacheEffect()); - this.addAbility(ability); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.EACH_PLAYER, + new AddCountersSourceEffect(CounterType.CHARGE.createInstance(), xValue), + false + )); // Remove a charge counter from Mana Cache: Add {C}. Any player may activate this ability but only during their turn before the end step. this.addAbility(new ManaCacheManaAbility()); @@ -50,41 +62,6 @@ public final class ManaCache extends CardImpl { } } -class ManaCacheEffect extends OneShotEffect { - - private static final FilterPermanent filter = new FilterControlledLandPermanent(); - - static { - filter.add(TappedPredicate.UNTAPPED); - } - - public ManaCacheEffect() { - super(Outcome.Damage); - this.staticText = "put a charge counter on {this} for each untapped land that player controls"; - } - - private ManaCacheEffect(final ManaCacheEffect effect) { - super(effect); - } - - @Override - public ManaCacheEffect copy() { - return new ManaCacheEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(game.getActivePlayerId()); - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (player != null && sourcePermanent != null) { - int controlledUntappedLands = game.getBattlefield().countAll(filter, game.getActivePlayerId(), game); - sourcePermanent.addCounters(CounterType.CHARGE.createInstance(controlledUntappedLands), source.getControllerId(), source, game); - return true; - } - return false; - } -} - class ManaCacheManaAbility extends ActivatedManaAbilityImpl { public ManaCacheManaAbility() { diff --git a/Mage.Sets/src/mage/cards/m/ManaSkimmer.java b/Mage.Sets/src/mage/cards/m/ManaSkimmer.java index 17e473baede..2cff22f5320 100644 --- a/Mage.Sets/src/mage/cards/m/ManaSkimmer.java +++ b/Mage.Sets/src/mage/cards/m/ManaSkimmer.java @@ -1,9 +1,9 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToAPlayerTriggeredAbility; import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.keyword.FlyingAbility; @@ -11,13 +11,10 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterLandPermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.target.TargetPermanent; +import mage.target.common.TargetLandPermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; + +import java.util.UUID; /** * @@ -34,7 +31,11 @@ public final class ManaSkimmer extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Whenever Mana Skimmer deals damage to a player, tap target land that player controls. That land doesn't untap during its controller's next untap step. - this.addAbility(new ManaSkimmerTriggeredAbility()); + Ability ability = new DealsDamageToAPlayerTriggeredAbility(new TapTargetEffect(), false, true); + ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("That land")); + ability.addTarget(new TargetLandPermanent().withTargetName("target land that player controls")); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); + this.addAbility(ability); } private ManaSkimmer(final ManaSkimmer card) { @@ -46,44 +47,3 @@ public final class ManaSkimmer extends CardImpl { return new ManaSkimmer(this); } } - -class ManaSkimmerTriggeredAbility extends TriggeredAbilityImpl { - - ManaSkimmerTriggeredAbility() { - super(Zone.BATTLEFIELD, new TapTargetEffect(), false); - addEffect(new DontUntapInControllersNextUntapStepTargetEffect()); - } - - private ManaSkimmerTriggeredAbility(final ManaSkimmerTriggeredAbility ability) { - super(ability); - } - - @Override - public ManaSkimmerTriggeredAbility copy() { - return new ManaSkimmerTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Permanent source = game.getPermanent(event.getSourceId()); - if (source != null && source.getId().equals(this.getSourceId())) { - FilterLandPermanent filter = new FilterLandPermanent("land that player controls"); - filter.add(new ControllerIdPredicate(event.getPlayerId())); - filter.setMessage("land controlled by " + game.getPlayer(event.getTargetId()).getLogName()); - this.getTargets().clear(); - this.addTarget(new TargetPermanent(filter)); - return true; - } - return false; - } - - @Override - public String getRule() { - return "Whenever {this} deals damage to a player, tap target land that player controls. That land doesn't untap during its controller's next untap step."; - } -} diff --git a/Mage.Sets/src/mage/cards/m/ManicScribe.java b/Mage.Sets/src/mage/cards/m/ManicScribe.java index 78767f93007..3050860269d 100644 --- a/Mage.Sets/src/mage/cards/m/ManicScribe.java +++ b/Mage.Sets/src/mage/cards/m/ManicScribe.java @@ -1,19 +1,18 @@ package mage.cards.m; import mage.MageInt; -import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.MillCardsEachPlayerEffect; import mage.abilities.effects.common.MillCardsTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; -import mage.constants.Zone; import java.util.UUID; @@ -36,13 +35,9 @@ public final class ManicScribe extends CardImpl { // Delirium — At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, // that player puts the top three cards of their library into their graveyard. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - Zone.BATTLEFIELD, TargetController.OPPONENT, new MillCardsTargetEffect(3), - false - ), DeliriumCondition.instance, "Delirium — At the beginning of each opponent's upkeep, " + - "if there are four or more card types among cards in your graveyard, that player mills three cards." - ).addHint(CardTypesInGraveyardCount.YOU.getHint())); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.OPPONENT, new MillCardsTargetEffect(3), false + ).withInterveningIf(DeliriumCondition.instance).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); } private ManicScribe(final ManicScribe card) { diff --git a/Mage.Sets/src/mage/cards/m/MantleOfTheAncients.java b/Mage.Sets/src/mage/cards/m/MantleOfTheAncients.java index 7f41fa32cc8..d01b21e9f6f 100644 --- a/Mage.Sets/src/mage/cards/m/MantleOfTheAncients.java +++ b/Mage.Sets/src/mage/cards/m/MantleOfTheAncients.java @@ -15,22 +15,32 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.predicate.Predicate; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.TargetCard; import mage.target.TargetPermanent; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetControlledCreaturePermanent; import java.util.Objects; +import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; /** * @author TheElk801 */ public final class MantleOfTheAncients extends CardImpl { + private static final FilterCard filter = new FilterPermanentCard(); + + static { + filter.add(Predicates.or( + SubType.AURA.getPredicate(), + SubType.EQUIPMENT.getPredicate() + )); + } public MantleOfTheAncients(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}{W}"); @@ -41,11 +51,12 @@ public final class MantleOfTheAncients extends CardImpl { TargetPermanent auraTarget = new TargetControlledCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget)); // When Mantle of the Ancients enters the battlefield, return any number of target Aura and/or Equipment cards from your graveyard to the battlefield attached to enchanted creature. - this.addAbility(new EntersBattlefieldTriggeredAbility(new MantleOfTheAncientsEffect())); + Ability ability = new EntersBattlefieldTriggeredAbility(new MantleOfTheAncientsEffect()); + ability.addTarget(new TargetCardInYourGraveyard(0, Integer.MAX_VALUE, filter)); + this.addAbility(ability); // Enchanted creature gets +1/+1 for each Aura and Equipment attached to it. this.addAbility(new SimpleStaticAbility(new BoostEnchantedEffect( @@ -68,8 +79,7 @@ class MantleOfTheAncientsEffect extends OneShotEffect { MantleOfTheAncientsEffect() { super(Outcome.Benefit); staticText = "return any number of target Aura and/or Equipment cards " + - "that could be attached to enchanted creature from your graveyard " + - "to the battlefield attached to enchanted creature"; + "from your graveyard to the battlefield attached to enchanted creature"; } private MantleOfTheAncientsEffect(final MantleOfTheAncientsEffect effect) { @@ -92,46 +102,21 @@ class MantleOfTheAncientsEffect extends OneShotEffect { if (permanent == null) { return false; } - FilterCard filter = new FilterCard("Aura or Equipment card that can be attached to " + permanent.getName()); - filter.add(new MantleOfTheAncientsPredicate(permanent)); - TargetCard target = new TargetCardInYourGraveyard(0, Integer.MAX_VALUE, filter, true); - player.choose(outcome, target, source, game); - Cards cards = new CardsImpl(target.getTargets()); + Set cards = getTargetPointer().getTargets(game, source).stream().map(game::getCard).filter(Objects::nonNull) + .filter(card -> !permanent.cantBeAttachedBy(card, source, game, true)).collect(Collectors.toSet()); if (cards.isEmpty()) { return false; } - cards.getCards(game) - .stream() - .forEach(card -> game.getState().setValue("attachTo:" + card.getId(), permanent)); + + cards.forEach(card -> game.getState().setValue("attachTo:" + card.getId(), permanent)); player.moveCards(cards, Zone.BATTLEFIELD, source, game); - for (UUID cardId : cards) { - permanent.addAttachment(cardId, source, game); - } + Cards movedCards = new CardsImpl(cards); + movedCards.retainZone(Zone.BATTLEFIELD, game); + movedCards.forEach(card -> permanent.addAttachment(card, source, game)); return true; } } -class MantleOfTheAncientsPredicate implements Predicate { - - private final Permanent permanent; - - MantleOfTheAncientsPredicate(Permanent permanent) { - this.permanent = permanent; - } - - @Override - public boolean apply(Card input, Game game) { - if (input.hasSubtype(SubType.AURA, game)) { - return input - .getSpellAbility() - .getTargets() - .stream() - .anyMatch(target -> target.getFilter().match(permanent, game)); - } - return input.hasSubtype(SubType.EQUIPMENT, game); - } -} - enum MantleOfTheAncientsValue implements DynamicValue { instance; diff --git a/Mage.Sets/src/mage/cards/m/MaraudingLooter.java b/Mage.Sets/src/mage/cards/m/MaraudingLooter.java index d3500d59ff1..b7ff7e2f97b 100644 --- a/Mage.Sets/src/mage/cards/m/MaraudingLooter.java +++ b/Mage.Sets/src/mage/cards/m/MaraudingLooter.java @@ -1,12 +1,10 @@ package mage.cards.m; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.abilities.hint.common.RaidHint; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; @@ -30,15 +28,9 @@ public final class MaraudingLooter extends CardImpl { this.toughness = new MageInt(3); // Raid - At the beginning of your end step, if you attacked this turn, you may draw a card. If you do, discard a card. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility(new DrawDiscardControllerEffect(1, 1, true)), - RaidCondition.instance, - "At the beginning of your end step, " - + "if you attacked this turn, " - + "you may draw a card. If you do, discard a card."); - ability.setAbilityWord(AbilityWord.RAID); - ability.addHint(RaidHint.instance); - this.addAbility(ability, new PlayerAttackedWatcher()); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new DrawDiscardControllerEffect(1, 1, true) + ).withInterveningIf(RaidCondition.instance).setAbilityWord(AbilityWord.RAID).addHint(RaidHint.instance), new PlayerAttackedWatcher()); } private MaraudingLooter(final MaraudingLooter card) { diff --git a/Mage.Sets/src/mage/cards/m/MarchOfTheCanonized.java b/Mage.Sets/src/mage/cards/m/MarchOfTheCanonized.java index 47841d26fd3..c05b3e22254 100644 --- a/Mage.Sets/src/mage/cards/m/MarchOfTheCanonized.java +++ b/Mage.Sets/src/mage/cards/m/MarchOfTheCanonized.java @@ -1,22 +1,21 @@ package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.condition.IntCompareCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.dynamicvalue.common.DevotionCount; import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ComparisonType; import mage.game.Game; import mage.game.permanent.token.IxalanVampireToken; import mage.game.permanent.token.VampireDemonToken; +import java.util.UUID; + /** * @author arcox */ @@ -29,13 +28,8 @@ public final class MarchOfTheCanonized extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new IxalanVampireToken(), GetXValue.instance))); // At the beginning of your upkeep, if your devotion to white and black is seven or greater, create a 4/3 white and black Vampire Demon creature token with flying. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new VampireDemonToken())), - new MarchOfTheCanonizedCondition(), - "At the beginning of your upkeep, " - + "if your devotion to white and black is seven or greater, " - + "create a 4/3 white and black Vampire Demon creature token with flying." - ).addHint(DevotionCount.WB.getHint())); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new VampireDemonToken())) + .withInterveningIf(MarchOfTheCanonizedCondition.instance).addHint(DevotionCount.WB.getHint())); } private MarchOfTheCanonized(final MarchOfTheCanonized card) { @@ -48,14 +42,16 @@ public final class MarchOfTheCanonized extends CardImpl { } } -class MarchOfTheCanonizedCondition extends IntCompareCondition { +enum MarchOfTheCanonizedCondition implements Condition { + instance; - MarchOfTheCanonizedCondition() { - super(ComparisonType.OR_GREATER, 7); + @Override + public boolean apply(Game game, Ability source) { + return DevotionCount.WB.calculate(game, source, null) >= 7; } @Override - protected int getInputValue(Game game, Ability source) { - return DevotionCount.WB.calculate(game, source, null); + public String toString() { + return "your devotion to white and black is seven or greater"; } } diff --git a/Mage.Sets/src/mage/cards/m/MarchesaResoluteMonarch.java b/Mage.Sets/src/mage/cards/m/MarchesaResoluteMonarch.java index aeca802c7fd..37cea498d81 100644 --- a/Mage.Sets/src/mage/cards/m/MarchesaResoluteMonarch.java +++ b/Mage.Sets/src/mage/cards/m/MarchesaResoluteMonarch.java @@ -3,16 +3,19 @@ package mage.cards.m; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.counter.RemoveAllCountersPermanentTargetEffect; import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.MenaceAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.WatcherScope; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.DamagedEvent; @@ -52,13 +55,9 @@ public final class MarchesaResoluteMonarch extends CardImpl { this.addAbility(ability); // At the beginning of your upkeep, if you haven't been dealt combat damage since your last turn, you draw a card and you lose 1 life. - ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - new DrawCardSourceControllerEffect(1), false - ), MarchesaResoluteMonarchWatcher::checkPlayer, "At the beginning of your upkeep, " + - "if you haven't been dealt combat damage since your last turn, you draw a card and you lose 1 life." - ); - ability.addEffect(new LoseLifeSourceControllerEffect(1)); + ability = new BeginningOfUpkeepTriggeredAbility(new DrawCardSourceControllerEffect(1, true)) + .withInterveningIf(MarchesaResoluteMonarchCondition.instance); + ability.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and")); this.addAbility(ability); } @@ -76,6 +75,20 @@ public final class MarchesaResoluteMonarch extends CardImpl { } } +enum MarchesaResoluteMonarchCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return MarchesaResoluteMonarchWatcher.checkPlayer(game, source); + } + + @Override + public String toString() { + return "you haven't been dealt combat damage since your last turn"; + } +} + class MarchesaResoluteMonarchWatcher extends Watcher { private final Set players = new HashSet<>(); diff --git a/Mage.Sets/src/mage/cards/m/MarduHeartPiercer.java b/Mage.Sets/src/mage/cards/m/MarduHeartPiercer.java index 17a3bf31124..0b585235d2b 100644 --- a/Mage.Sets/src/mage/cards/m/MarduHeartPiercer.java +++ b/Mage.Sets/src/mage/cards/m/MarduHeartPiercer.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.hint.common.RaidHint; import mage.cards.CardImpl; @@ -31,12 +30,9 @@ public final class MarduHeartPiercer extends CardImpl { this.toughness = new MageInt(3); // Raid - When Mardu Heart-Piercer enters the battlefield, if you attacked this turn, Mardu Heart-Piercer deals 2 damage to any target. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2)), RaidCondition.instance, - "When {this} enters, if you attacked this turn, {this} deals 2 damage to any target."); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2)).withInterveningIf(RaidCondition.instance); ability.addTarget(new TargetAnyTarget()); - ability.setAbilityWord(AbilityWord.RAID); - ability.addHint(RaidHint.instance); - this.addAbility(ability, new PlayerAttackedWatcher()); + this.addAbility(ability.setAbilityWord(AbilityWord.RAID).addHint(RaidHint.instance), new PlayerAttackedWatcher()); } private MarduHeartPiercer(final MarduHeartPiercer card) { diff --git a/Mage.Sets/src/mage/cards/m/MarduHordechief.java b/Mage.Sets/src/mage/cards/m/MarduHordechief.java index 27430d4ce84..b26bc66cf98 100644 --- a/Mage.Sets/src/mage/cards/m/MarduHordechief.java +++ b/Mage.Sets/src/mage/cards/m/MarduHordechief.java @@ -3,7 +3,6 @@ package mage.cards.m; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.common.RaidHint; import mage.cards.CardImpl; @@ -30,13 +29,8 @@ public final class MarduHordechief extends CardImpl { this.toughness = new MageInt(3); // Raid — When Mardu Hordechief enters the battlefield, if you attacked this turn, create a 1/1 white Warrior creature token - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( - new CreateTokenEffect(new WarriorToken())), - RaidCondition.instance, - "When {this} enters, if you attacked this turn, create a 1/1 white Warrior creature token.") - .setAbilityWord(AbilityWord.RAID) - .addHint(RaidHint.instance), - new PlayerAttackedWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new WarriorToken())) + .withInterveningIf(RaidCondition.instance).setAbilityWord(AbilityWord.RAID).addHint(RaidHint.instance), new PlayerAttackedWatcher()); } private MarduHordechief(final MarduHordechief card) { diff --git a/Mage.Sets/src/mage/cards/m/MarduSkullhunter.java b/Mage.Sets/src/mage/cards/m/MarduSkullhunter.java index ec59f21eb59..4153d13a8ea 100644 --- a/Mage.Sets/src/mage/cards/m/MarduSkullhunter.java +++ b/Mage.Sets/src/mage/cards/m/MarduSkullhunter.java @@ -5,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.hint.common.RaidHint; import mage.cards.CardImpl; @@ -35,12 +34,9 @@ public final class MarduSkullhunter extends CardImpl { this.addAbility(new EntersBattlefieldTappedAbility()); // Raid - When Mardu Skullhunter enters the battlefield, if you attacked this turn, target opponent discards a card. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(1)), RaidCondition.instance, - "When {this} enters, if you attacked this turn, target opponent discards a card."); + Ability ability = new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(1)).withInterveningIf(RaidCondition.instance); ability.addTarget(new TargetOpponent()); - ability.setAbilityWord(AbilityWord.RAID); - ability.addHint(RaidHint.instance); - this.addAbility(ability, new PlayerAttackedWatcher()); + this.addAbility(ability.setAbilityWord(AbilityWord.RAID).addHint(RaidHint.instance), new PlayerAttackedWatcher()); } private MarduSkullhunter(final MarduSkullhunter card) { diff --git a/Mage.Sets/src/mage/cards/m/MarduWarshrieker.java b/Mage.Sets/src/mage/cards/m/MarduWarshrieker.java index 0acb5bbbb2d..745db07abc7 100644 --- a/Mage.Sets/src/mage/cards/m/MarduWarshrieker.java +++ b/Mage.Sets/src/mage/cards/m/MarduWarshrieker.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.Mana; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.mana.AddManaToManaPoolSourceControllerEffect; import mage.abilities.hint.common.RaidHint; import mage.cards.CardImpl; @@ -30,13 +29,9 @@ public final class MarduWarshrieker extends CardImpl { this.toughness = new MageInt(3); // Raid - When Mardu Warshrieker enters the battlefield, if you attacked this turn, add {R}{W}{B}. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( - new AddManaToManaPoolSourceControllerEffect(new Mana(1, 0, 1, 1, 0, 0, 0, 0))), - RaidCondition.instance, - "When {this} enters, if you attacked this turn, add {R}{W}{B}.") - .setAbilityWord(AbilityWord.RAID) - .addHint(RaidHint.instance), - new PlayerAttackedWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility(new AddManaToManaPoolSourceControllerEffect( + new Mana(1, 0, 1, 1, 0, 0, 0, 0) + ).setText("add {R}{W}{B}")).withInterveningIf(RaidCondition.instance).setAbilityWord(AbilityWord.RAID).addHint(RaidHint.instance), new PlayerAttackedWatcher()); } private MarduWarshrieker(final MarduWarshrieker card) { diff --git a/Mage.Sets/src/mage/cards/m/MarinaVendrellsGrimoire.java b/Mage.Sets/src/mage/cards/m/MarinaVendrellsGrimoire.java index 82a54e1e140..f8618b1edff 100644 --- a/Mage.Sets/src/mage/cards/m/MarinaVendrellsGrimoire.java +++ b/Mage.Sets/src/mage/cards/m/MarinaVendrellsGrimoire.java @@ -7,7 +7,6 @@ import mage.abilities.common.LoseLifeTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; import mage.abilities.condition.common.HellbentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.dynamicvalue.common.SavedGainedLifeValue; import mage.abilities.dynamicvalue.common.SavedLifeLossValue; @@ -35,10 +34,8 @@ public final class MarinaVendrellsGrimoire extends CardImpl { this.supertype.add(SuperType.LEGENDARY); // When Marina Vendrell's Grimoire enters, if you cast it, draw five cards. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(5)), - CastFromEverywhereSourceCondition.instance, "When {this} enters, if you cast it, draw five cards." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(5)) + .withInterveningIf(CastFromEverywhereSourceCondition.instance)); // You have no maximum hand size and don't lose the game for having 0 or less life. Ability ability = new SimpleStaticAbility(new MaximumHandSizeControllerEffect( diff --git a/Mage.Sets/src/mage/cards/m/MaritLagesSlumber.java b/Mage.Sets/src/mage/cards/m/MaritLagesSlumber.java index 5753d166982..d5694ada06b 100644 --- a/Mage.Sets/src/mage/cards/m/MaritLagesSlumber.java +++ b/Mage.Sets/src/mage/cards/m/MaritLagesSlumber.java @@ -1,15 +1,14 @@ package mage.cards.m; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.SacrificeSourceCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.keyword.ScryEffect; import mage.abilities.hint.ConditionHint; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -28,14 +27,17 @@ public final class MaritLagesSlumber extends CardImpl { private static final FilterPermanent filter = new FilterControlledPermanent("snow permanent"); + private static final FilterPermanent filter2 + = new FilterControlledPermanent("you control ten or more snow permanents"); static { filter.add(SuperType.SNOW.getPredicate()); + filter2.add(SuperType.SNOW.getPredicate()); } private static final Condition condition - = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 9); - private static final ConditionHint hint = new ConditionHint(condition, "You control ten or more snow permanents"); + = new PermanentsOnTheBattlefieldCondition(filter2, ComparisonType.MORE_THAN, 9); + private static final ConditionHint hint = new ConditionHint(condition); public MaritLagesSlumber(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); @@ -49,14 +51,10 @@ public final class MaritLagesSlumber extends CardImpl { )); // At the beginning of your upkeep, if you control ten or more snow permanents, sacrifice Marit Lage's Slumber. If you do, create Marit Lage, a legendary 20/20 black Avatar creature token with flying and indestructible. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new DoIfCostPaid( - new CreateTokenEffect(new MaritLageToken()), - new SacrificeSourceCost(), "", false - )), condition, "At the beginning of your upkeep, " + - "if you control ten or more snow permanents, sacrifice {this}. If you do, create Marit Lage, " + - "a legendary 20/20 black Avatar creature token with flying and indestructible." - ).addHint(hint)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DoIfCostPaid( + new CreateTokenEffect(new MaritLageToken()), + new SacrificeSourceCost(), "", false + )).withInterveningIf(condition).addHint(hint)); } private MaritLagesSlumber(final MaritLagesSlumber card) { diff --git a/Mage.Sets/src/mage/cards/m/Marjhan.java b/Mage.Sets/src/mage/cards/m/Marjhan.java index 647523eca49..9795dee8330 100644 --- a/Mage.Sets/src/mage/cards/m/Marjhan.java +++ b/Mage.Sets/src/mage/cards/m/Marjhan.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ControlsPermanentsControllerTriggeredAbility; @@ -10,8 +8,7 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; -import mage.abilities.effects.Effect; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect; import mage.abilities.effects.common.SacrificeSourceEffect; @@ -21,17 +18,21 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; import mage.filter.common.FilterAttackingCreature; import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class Marjhan extends CardImpl { @@ -52,8 +53,9 @@ public final class Marjhan extends CardImpl { this.addAbility(new SimpleStaticAbility(new DontUntapInControllersUntapStepSourceEffect())); // {U}{U}, Sacrifice a creature: Untap Marjhan. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new UntapSourceEffect(), new ManaCostsImpl<>("{U}{U}"), new IsStepCondition(PhaseStep.UPKEEP), null); + Ability ability = new ActivateIfConditionActivatedAbility( + new UntapSourceEffect(), new ManaCostsImpl<>("{U}{U}"), IsStepCondition.getMyUpkeep() + ); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE)); this.addAbility(ability); @@ -63,7 +65,7 @@ public final class Marjhan extends CardImpl { // {U}{U}: Marjhan gets -1/-0 until end of turn and deals 1 damage to target attacking creature without flying. ability = new SimpleActivatedAbility(new BoostSourceEffect(-1, 0, Duration.EndOfTurn), new ManaCostsImpl<>("{U}{U}")); ability.addEffect(new DamageTargetEffect(1, "and")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // When you control no Islands, sacrifice Marjhan. diff --git a/Mage.Sets/src/mage/cards/m/MarkForDeath.java b/Mage.Sets/src/mage/cards/m/MarkForDeath.java index b533b5b8f0f..56fcc4e39c0 100644 --- a/Mage.Sets/src/mage/cards/m/MarkForDeath.java +++ b/Mage.Sets/src/mage/cards/m/MarkForDeath.java @@ -18,9 +18,12 @@ import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author jeffwadsworth @@ -32,7 +35,7 @@ public final class MarkForDeath extends CardImpl { // Target creature an opponent controls blocks this turn if able. Untap that creature. Other creatures that player controls can't block this turn. this.getSpellAbility().addEffect(new MarkForDeathEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); } private MarkForDeath(final MarkForDeath card) { diff --git a/Mage.Sets/src/mage/cards/m/MarketwatchPhantom.java b/Mage.Sets/src/mage/cards/m/MarketwatchPhantom.java index f1ae73f2d5a..40f7b4a14b2 100644 --- a/Mage.Sets/src/mage/cards/m/MarketwatchPhantom.java +++ b/Mage.Sets/src/mage/cards/m/MarketwatchPhantom.java @@ -1,7 +1,7 @@ package mage.cards.m; import mage.MageInt; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -23,7 +23,7 @@ import java.util.UUID; public final class MarketwatchPhantom extends CardImpl { private static final FilterPermanent filter - = new FilterControlledCreaturePermanent("another creature with power 2 or less"); + = new FilterControlledCreaturePermanent("another creature you control with power 2 or less"); static { filter.add(AnotherPredicate.instance); @@ -39,7 +39,7 @@ public final class MarketwatchPhantom extends CardImpl { this.toughness = new MageInt(2); // Whenever another creature with power 2 or less you control enters, Marketwatch Phantom gains flying until end of turn. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + this.addAbility(new EntersBattlefieldAllTriggeredAbility( new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), filter )); } diff --git a/Mage.Sets/src/mage/cards/m/MarthaJones.java b/Mage.Sets/src/mage/cards/m/MarthaJones.java index 08363a2f3ee..cf8d6b3a06f 100644 --- a/Mage.Sets/src/mage/cards/m/MarthaJones.java +++ b/Mage.Sets/src/mage/cards/m/MarthaJones.java @@ -17,7 +17,7 @@ import mage.constants.SuperType; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -52,7 +52,7 @@ public final class MarthaJones extends CardImpl { ); ability.addEffect(new CantBeBlockedTargetEffect() .setText("and up to one other target creature can't be blocked this turn")); - ability.addTarget(new TargetCreaturePermanent(0, 1, filterOther, false)); + ability.addTarget(new TargetPermanent(0, 1, filterOther)); this.addAbility(ability); // Doctor's companion diff --git a/Mage.Sets/src/mage/cards/m/MartialLaw.java b/Mage.Sets/src/mage/cards/m/MartialLaw.java index dffa0610bff..fa40616f24b 100644 --- a/Mage.Sets/src/mage/cards/m/MartialLaw.java +++ b/Mage.Sets/src/mage/cards/m/MartialLaw.java @@ -1,15 +1,14 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.common.DetainTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.StaticFilters; -import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; /** * @author LevelX2 @@ -17,14 +16,12 @@ import mage.target.common.TargetCreaturePermanent; public final class MartialLaw extends CardImpl { public MartialLaw(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}{W}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); // At the beginning of your upkeep, detain target creature an opponent controls. // (Until your next turn, that creature can't attack or block and its activated abilities can't be activated.) Ability ability = new BeginningOfUpkeepTriggeredAbility(new DetainTargetEffect()); - TargetCreaturePermanent target = new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE); - ability.addTarget(target); + ability.addTarget(new TargetOpponentsCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MartyrOfAshes.java b/Mage.Sets/src/mage/cards/m/MartyrOfAshes.java index e62bbc29d17..ed45c5c7c95 100644 --- a/Mage.Sets/src/mage/cards/m/MartyrOfAshes.java +++ b/Mage.Sets/src/mage/cards/m/MartyrOfAshes.java @@ -1,7 +1,6 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -17,7 +16,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; @@ -25,6 +23,8 @@ import mage.filter.predicate.mageobject.AbilityPredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetCardInHand; +import java.util.UUID; + /** * * @author emerald000 @@ -49,7 +49,7 @@ public final class MartyrOfAshes extends CardImpl { // {2}, Reveal X red cards from your hand, Sacrifice Martyr of Ashes: Martyr of Ashes deals X damage to each creature without flying. Effect effect = new DamageAllEffect(RevealTargetFromHandCostCount.instance, filterCreature); - effect.setText("Martyr of Ashes deals X damage to each creature without flying."); + effect.setText("{this} deals X damage to each creature without flying."); Ability ability = new SimpleActivatedAbility(effect, new GenericManaCost(2)); ability.addCost(new RevealTargetFromHandCost(new TargetCardInHand(0, Integer.MAX_VALUE, filterHand))); ability.addCost(new SacrificeSourceCost()); diff --git a/Mage.Sets/src/mage/cards/m/MartyrsSoul.java b/Mage.Sets/src/mage/cards/m/MartyrsSoul.java index f7190ff1b81..e19e16f32c4 100644 --- a/Mage.Sets/src/mage/cards/m/MartyrsSoul.java +++ b/Mage.Sets/src/mage/cards/m/MartyrsSoul.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.ConvokeAbility; import mage.cards.CardImpl; @@ -24,7 +23,7 @@ import java.util.UUID; */ public final class MartyrsSoul extends CardImpl { - private static final FilterPermanent filter = new FilterControlledLandPermanent(); + private static final FilterPermanent filter = new FilterControlledLandPermanent("you control no tapped lands"); static { filter.add(TappedPredicate.TAPPED); @@ -45,12 +44,10 @@ public final class MartyrsSoul extends CardImpl { this.addAbility(new ConvokeAbility()); // When Martyr's Soul enters the battlefield, if you control no tapped lands, put two +1/+1 counters on it. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new AddCountersSourceEffect( - CounterType.P1P1.createInstance(2) - )), condition, "When {this} enters, " + - "if you control no tapped lands, put two +1/+1 counters on it." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)) + .setText("put two +1/+1 counters on it") + ).withInterveningIf(condition)); } private MartyrsSoul(final MartyrsSoul card) { diff --git a/Mage.Sets/src/mage/cards/m/Marut.java b/Mage.Sets/src/mage/cards/m/Marut.java index 8a168a0d724..83a166f8d65 100644 --- a/Mage.Sets/src/mage/cards/m/Marut.java +++ b/Mage.Sets/src/mage/cards/m/Marut.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.TreasureSpentToCastCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; @@ -35,11 +34,9 @@ public final class Marut extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // When Marut enters the battlefield, if mana from a Treasure was spent to cast it, create a Treasure token for each mana from a Treasure spent to cast it. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new TreasureToken(), MarutValue.instance)), - TreasureSpentToCastCondition.instance, "When {this} enters, if mana from a " + - "Treasure was spent to cast it, create a Treasure token for each mana from a Treasure spent to cast it." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new CreateTokenEffect(new TreasureToken(), MarutValue.instance) + ).withInterveningIf(TreasureSpentToCastCondition.instance)); } private Marut(final Marut card) { @@ -67,6 +64,11 @@ enum MarutValue implements DynamicValue { @Override public String getMessage() { - return ""; + return "mana from a Treasure spent to cast it"; + } + + @Override + public String toString() { + return "1"; } } diff --git a/Mage.Sets/src/mage/cards/m/MaskOfIntolerance.java b/Mage.Sets/src/mage/cards/m/MaskOfIntolerance.java index a88e165c016..b4d4df12080 100644 --- a/Mage.Sets/src/mage/cards/m/MaskOfIntolerance.java +++ b/Mage.Sets/src/mage/cards/m/MaskOfIntolerance.java @@ -1,17 +1,14 @@ package mage.cards.m; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.condition.IntCompareCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.DomainValue; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.hint.common.DomainHint; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ComparisonType; import mage.constants.TargetController; import mage.game.Game; @@ -22,16 +19,13 @@ import java.util.UUID; */ public final class MaskOfIntolerance extends CardImpl { - private static final Condition condition = new MaskOfIntoleranceCondition(); - public MaskOfIntolerance(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // At the beginning of each player's upkeep, if there are four or more basic land types among lands that player controls, Mask of Intolerance deals 3 damage to that player. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new BeginningOfUpkeepTriggeredAbility( - TargetController.ANY, new DamageTargetEffect(3), false - ), condition, "At the beginning of each player's upkeep, if there are four or more basic land types " + - "among lands that player controls, {this} deals 3 damage to that player.").addHint(DomainHint.instance)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.EACH_PLAYER, new DamageTargetEffect(3, true, "that player"), false + ).withInterveningIf(MaskOfIntoleranceCondition.instance).addHint(DomainHint.instance)); } private MaskOfIntolerance(final MaskOfIntolerance card) { @@ -44,14 +38,16 @@ public final class MaskOfIntolerance extends CardImpl { } } -class MaskOfIntoleranceCondition extends IntCompareCondition { +enum MaskOfIntoleranceCondition implements Condition { + instance; - public MaskOfIntoleranceCondition() { - super(ComparisonType.MORE_THAN, 3); + @Override + public boolean apply(Game game, Ability source) { + return DomainValue.ACTIVE.calculate(game, source, null) >= 4; } @Override - protected int getInputValue(Game game, Ability source) { - return DomainValue.ACTIVE.calculate(game, source, null); + public String toString() { + return "there are four or more basic land types among lands that player controls"; } } diff --git a/Mage.Sets/src/mage/cards/m/MaskOfTheMimic.java b/Mage.Sets/src/mage/cards/m/MaskOfTheMimic.java index 438b6efae01..5e38afcef06 100644 --- a/Mage.Sets/src/mage/cards/m/MaskOfTheMimic.java +++ b/Mage.Sets/src/mage/cards/m/MaskOfTheMimic.java @@ -17,6 +17,7 @@ import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; @@ -41,7 +42,7 @@ public final class MaskOfTheMimic extends CardImpl { // Search your library for a card with the same name as target nontoken creature and put that card onto the battlefield. Then shuffle your library. this.getSpellAbility().addEffect(new MaskOfTheMimicEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private MaskOfTheMimic(final MaskOfTheMimic card) { diff --git a/Mage.Sets/src/mage/cards/m/MasterOfDiversion.java b/Mage.Sets/src/mage/cards/m/MasterOfDiversion.java index eca0f1d9ded..aed3b066464 100644 --- a/Mage.Sets/src/mage/cards/m/MasterOfDiversion.java +++ b/Mage.Sets/src/mage/cards/m/MasterOfDiversion.java @@ -12,6 +12,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -35,7 +36,7 @@ public final class MasterOfDiversion extends CardImpl { // Whenever Master of Diversion attacks, tap target creature defending player controls. Ability ability = new AttacksTriggeredAbility(new TapTargetEffect(), false); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MasterOfTheVeil.java b/Mage.Sets/src/mage/cards/m/MasterOfTheVeil.java index 583aef98668..cee6f88e03b 100644 --- a/Mage.Sets/src/mage/cards/m/MasterOfTheVeil.java +++ b/Mage.Sets/src/mage/cards/m/MasterOfTheVeil.java @@ -1,11 +1,9 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.TurnedFaceUpSourceTriggeredAbility; -import mage.constants.SubType; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureAllEffect; @@ -14,6 +12,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicates; @@ -21,10 +20,11 @@ import mage.filter.predicate.mageobject.AbilityPredicate; import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class MasterOfTheVeil extends CardImpl { @@ -48,7 +48,7 @@ public final class MasterOfTheVeil extends CardImpl { // When Master of the Veil is turned face up, you may turn target creature with a morph ability face down. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new MasterOfTheVeilEffect(), false, true); - ability.addTarget(new TargetCreaturePermanent(1, 1, filter, false)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MasterOfTheWildHunt.java b/Mage.Sets/src/mage/cards/m/MasterOfTheWildHunt.java index 63e08d01d3c..f784e102b7e 100644 --- a/Mage.Sets/src/mage/cards/m/MasterOfTheWildHunt.java +++ b/Mage.Sets/src/mage/cards/m/MasterOfTheWildHunt.java @@ -2,20 +2,22 @@ package mage.cards.m; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.ValueHint; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.MultiAmountType; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.game.permanent.token.WolfToken; import mage.players.Player; @@ -39,8 +41,7 @@ public final class MasterOfTheWildHunt extends CardImpl { this.toughness = new MageInt(3); // At the beginning of your upkeep, create a 2/2 green Wolf creature token. - this.addAbility(new OnEventTriggeredAbility(EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", - new CreateTokenEffect(new WolfToken()))); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new WolfToken()))); // {T}: Tap all untapped Wolf creatures you control. Each Wolf tapped this way deals damage equal to its power to target creature. That creature deals damage equal to its power divided as its controller chooses among any number of those Wolves. Ability ability = new SimpleActivatedAbility(new MasterOfTheWildHuntEffect(), new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/m/MasterWarcraft.java b/Mage.Sets/src/mage/cards/m/MasterWarcraft.java index 303eb9ed934..8a0c2335fb9 100644 --- a/Mage.Sets/src/mage/cards/m/MasterWarcraft.java +++ b/Mage.Sets/src/mage/cards/m/MasterWarcraft.java @@ -21,7 +21,7 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.targetpointer.FixedTarget; import mage.watchers.common.ControlCombatRedundancyWatcher; @@ -107,7 +107,7 @@ class MasterWarcraftChooseAttackersEffect extends ContinuousRuleModifyingEffectI if (controller == null || attackingPlayer == null || attackingPlayer.getAvailableAttackers(game).isEmpty()) { return false; // the attack declaration resumes for the active player as normal } - Target target = new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, true); + Target target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); if (!controller.chooseTarget(Outcome.Benefit, target, source, game)) { return false; // the attack declaration resumes for the active player as normal } diff --git a/Mage.Sets/src/mage/cards/m/MastermindPlum.java b/Mage.Sets/src/mage/cards/m/MastermindPlum.java index b9fc6d5e3a2..56dd1c61c84 100644 --- a/Mage.Sets/src/mage/cards/m/MastermindPlum.java +++ b/Mage.Sets/src/mage/cards/m/MastermindPlum.java @@ -1,25 +1,18 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; -import mage.cards.Cards; -import mage.cards.CardsImpl; -import mage.constants.Outcome; -import mage.constants.SetTargetPointer; -import mage.constants.SubType; -import mage.constants.SuperType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Zone; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.*; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.token.Token; @@ -29,6 +22,8 @@ import mage.players.Player; import mage.target.common.TargetCardInGraveyard; import mage.watchers.common.ManaPaidSourceWatcher; +import java.util.UUID; + /** * Mastermind Plum {2}{B} * Legendary Creature - Human Wizard 2/2 @@ -54,15 +49,11 @@ public final class MastermindPlum extends CardImpl { this.addAbility(ability); // Whenever you cast a spell, if mana from a Treasure was spent to cast it, you draw a card and you lose 1 life. - ability = new ConditionalInterveningIfTriggeredAbility( - new SpellCastControllerTriggeredAbility( - new DrawCardSourceControllerEffect(1), StaticFilters.FILTER_SPELL, - false, SetTargetPointer.SPELL), - MastermindPlumCondition.instance, - "Whenever you cast a spell, if mana from a Treasure was spent to cast it, " + - "you draw a card and you lose 1 life." - ); - ability.addEffect(new LoseLifeSourceControllerEffect(1)); + ability = new SpellCastControllerTriggeredAbility( + new DrawCardSourceControllerEffect(1, true), + StaticFilters.FILTER_SPELL_A, false, SetTargetPointer.SPELL + ).withInterveningIf(MastermindPlumCondition.instance); + ability.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and")); this.addAbility(ability); } @@ -120,4 +111,9 @@ enum MastermindPlumCondition implements Condition { Spell spell = (Spell) source.getEffects().get(0).getValue("spellCast"); return spell != null && ManaPaidSourceWatcher.getTreasurePaid(spell.getSourceId(), game) > 0; } + + @Override + public String toString() { + return "mana from a Treasure was spent to cast it"; + } } diff --git a/Mage.Sets/src/mage/cards/m/MastersManufactory.java b/Mage.Sets/src/mage/cards/m/MastersManufactory.java index fbd796afbc6..ed3f49799fa 100644 --- a/Mage.Sets/src/mage/cards/m/MastersManufactory.java +++ b/Mage.Sets/src/mage/cards/m/MastersManufactory.java @@ -12,7 +12,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.WatcherScope; -import mage.constants.Zone; import mage.game.Game; import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; @@ -27,11 +26,6 @@ import java.util.*; */ public final class MastersManufactory extends CardImpl { - private static final Hint hint = new ConditionHint( - MastersManufactoryCondition.instance, - "{this} or another artifact entered under your control this turn" - ); - public MastersManufactory(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); this.nightCard = true; @@ -40,11 +34,9 @@ public final class MastersManufactory extends CardImpl { // {T}: Create a 4/4 white and blue Golem artifact creature token. Activate only if Master's Manufactory or another artifact entered the battlefield under your control this turn. this.addAbility(new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new CreateTokenEffect(new GolemWhiteBlueToken()), - new TapSourceCost(), - MastersManufactoryCondition.instance - ).addHint(hint), new MastersManufactoryWatcher()); + new TapSourceCost(), MastersManufactoryCondition.instance + ).addHint(MastersManufactoryCondition.getHint()), new MastersManufactoryWatcher()); } private MastersManufactory(final MastersManufactory card) { @@ -59,19 +51,23 @@ public final class MastersManufactory extends CardImpl { enum MastersManufactoryCondition implements Condition { instance; + private static final Hint hint = new ConditionHint(instance); + + public static Hint getHint() { + return hint; + } @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getSourceId()); MastersManufactoryWatcher watcher = game.getState().getWatcher(MastersManufactoryWatcher.class); - return watcher != null - && permanent != null + return watcher != null && permanent != null && watcher.check(source.getControllerId(), new MageObjectReference(permanent, game)); } @Override public String toString() { - return "if {this} or another artifact entered the battlefield under your control this turn"; + return "{this} or another artifact entered the battlefield under your control this turn"; } } diff --git a/Mage.Sets/src/mage/cards/m/MathasFiendSeeker.java b/Mage.Sets/src/mage/cards/m/MathasFiendSeeker.java index bf12a53d574..3ff467d78a0 100644 --- a/Mage.Sets/src/mage/cards/m/MathasFiendSeeker.java +++ b/Mage.Sets/src/mage/cards/m/MathasFiendSeeker.java @@ -1,40 +1,29 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.DiesSourceTriggeredAbility; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.DrawCardAllEffect; -import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.GainLifeAllEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.MenaceAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SuperType; -import mage.constants.TargetController; +import mage.constants.*; import mage.counters.CounterType; -import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class MathasFiendSeeker extends CardImpl { - private static final String rule = "For as long as that creature has a bounty counter on it, it has \"When this creature dies, each opponent draws a card and gains 2 life.\""; - public MathasFiendSeeker(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{W}{B}"); @@ -47,12 +36,11 @@ public final class MathasFiendSeeker extends CardImpl { this.addAbility(new MenaceAbility(false)); // At the beginning of your end step, put a bounty counter on target creature an opponent controls. For as long as that creature has a bounty counter on it, it has "When this creature dies, each opponent draws a card and gains 2 life." - Ability ability = new BeginningOfEndStepTriggeredAbility(new AddCountersTargetEffect(CounterType.BOUNTY.createInstance())); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); - Ability ability2 = new DiesSourceTriggeredAbility(new DrawCardAllEffect(1, TargetController.OPPONENT)); - ability2.addEffect(new OpponentsGainLifeEffect()); - Effect effect = new MathasFiendSeekerGainAbilityEffect(ability2, Duration.Custom, rule); - ability.addEffect(effect); + Ability ability = new BeginningOfEndStepTriggeredAbility( + new AddCountersTargetEffect(CounterType.BOUNTY.createInstance()) + ); + ability.addEffect(new MathasFiendSeekerEffect()); + ability.addTarget(new TargetOpponentsCreaturePermanent()); this.addAbility(ability); } @@ -66,56 +54,36 @@ public final class MathasFiendSeeker extends CardImpl { } } -class MathasFiendSeekerGainAbilityEffect extends GainAbilityTargetEffect { +class MathasFiendSeekerEffect extends ContinuousEffectImpl { - MathasFiendSeekerGainAbilityEffect(Ability ability, Duration duration, String rule) { - super(ability, duration, rule); + private final Ability ability; + + MathasFiendSeekerEffect() { + super(Duration.Custom, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = "For as long as that creature has a bounty counter on it, " + + "it has \"When this creature dies, each opponent draws a card and gains 2 life.\""; + this.ability = new DiesSourceTriggeredAbility(new DrawCardAllEffect(1, TargetController.OPPONENT)); + this.ability.addEffect(new GainLifeAllEffect(2, TargetController.OPPONENT).setText("and gains 2 life")); } - private MathasFiendSeekerGainAbilityEffect(final MathasFiendSeekerGainAbilityEffect effect) { + private MathasFiendSeekerEffect(final MathasFiendSeekerEffect effect) { super(effect); + this.ability = effect.ability.copy(); } @Override - public boolean isInactive(Ability source, Game game) { - Permanent creature = game.getPermanent(this.getTargetPointer().getFirst(game, source)); - if (creature != null && creature.getCounters(game).getCount(CounterType.BOUNTY) < 1) { - return true; - } - return false; - } - - @Override - public MathasFiendSeekerGainAbilityEffect copy() { - return new MathasFiendSeekerGainAbilityEffect(this); - } -} - -class OpponentsGainLifeEffect extends OneShotEffect { - - OpponentsGainLifeEffect() { - super(Outcome.GainLife); - staticText = "and gains 2 life."; - } - - private OpponentsGainLifeEffect(final OpponentsGainLifeEffect effect) { - super(effect); - } - - @Override - public OpponentsGainLifeEffect copy() { - return new OpponentsGainLifeEffect(this); + public MathasFiendSeekerEffect copy() { + return new MathasFiendSeekerEffect(this); } @Override public boolean apply(Game game, Ability source) { - for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null && game.isOpponent(player, source.getControllerId())) { - player.gainLife(2, game, source); - } + Permanent creature = game.getPermanent(this.getTargetPointer().getFirst(game, source)); + if (creature == null || !creature.getCounters(game).containsKey(CounterType.BOUNTY)) { + discard(); + return false; } + creature.addAbility(ability, source.getSourceId(), game); return true; } - } diff --git a/Mage.Sets/src/mage/cards/m/MatsuTribeSniper.java b/Mage.Sets/src/mage/cards/m/MatsuTribeSniper.java index eee0f6b76cb..e6347dc4070 100644 --- a/Mage.Sets/src/mage/cards/m/MatsuTribeSniper.java +++ b/Mage.Sets/src/mage/cards/m/MatsuTribeSniper.java @@ -18,6 +18,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -43,7 +44,7 @@ public final class MatsuTribeSniper extends CardImpl { // {t}: Matsu-Tribe Sniper deals 1 damage to target creature with flying. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Whenever Matsu-Tribe Sniper deals damage to a creature, tap that creature and it doesn't untap during its controller's next untap step. diff --git a/Mage.Sets/src/mage/cards/m/MatzalantliTheGreatDoor.java b/Mage.Sets/src/mage/cards/m/MatzalantliTheGreatDoor.java index 3152e2d0860..04f0ff0b214 100644 --- a/Mage.Sets/src/mage/cards/m/MatzalantliTheGreatDoor.java +++ b/Mage.Sets/src/mage/cards/m/MatzalantliTheGreatDoor.java @@ -5,7 +5,7 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.IntCompareCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawDiscardControllerEffect; @@ -43,7 +43,7 @@ public final class MatzalantliTheGreatDoor extends CardImpl { // {4}, {T}: Transform Matzalantli, the Great Door. Activate only if there are four or more permanent types among cards in your graveyard. this.addAbility(new TransformAbility()); - Ability ability = new ConditionalActivatedAbility( + Ability ability = new ActivateIfConditionActivatedAbility( new TransformSourceEffect(), new GenericManaCost(4), new MatzalantliTheGreatDoorCondition() @@ -118,4 +118,4 @@ enum MatzalantliTheGreatDoorValue implements DynamicValue { public String toString() { return "X"; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/m/MausoleumHarpy.java b/Mage.Sets/src/mage/cards/m/MausoleumHarpy.java index 0c1deab303f..f666a9469af 100644 --- a/Mage.Sets/src/mage/cards/m/MausoleumHarpy.java +++ b/Mage.Sets/src/mage/cards/m/MausoleumHarpy.java @@ -3,7 +3,6 @@ package mage.cards.m; import mage.MageInt; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.condition.common.CitysBlessingCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; @@ -36,12 +35,10 @@ public final class MausoleumHarpy extends CardImpl { this.addAbility(new AscendAbility()); // Whenever another creature you control dies, if you have the city's blessing, put a +1/+1 counter on Mausoleum Harpy. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new DiesCreatureTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL), - CitysBlessingCondition.instance, - "Whenever another creature you control dies, if you have the city's blessing, put a +1/+1 counter on {this}.") - .addHint(CitysBlessingHint.instance)); - + this.addAbility(new DiesCreatureTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, + StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL + ).withInterveningIf(CitysBlessingCondition.instance).addHint(CitysBlessingHint.instance)); } private MausoleumHarpy(final MausoleumHarpy card) { diff --git a/Mage.Sets/src/mage/cards/m/MausoleumTurnkey.java b/Mage.Sets/src/mage/cards/m/MausoleumTurnkey.java index 5e95ea8d9c5..a5427501f26 100644 --- a/Mage.Sets/src/mage/cards/m/MausoleumTurnkey.java +++ b/Mage.Sets/src/mage/cards/m/MausoleumTurnkey.java @@ -1,32 +1,31 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.SubType; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.card.OwnerIdPredicate; import mage.game.Game; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetOpponent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class MausoleumTurnkey extends CardImpl { + private static final FilterCreatureCard filter = new FilterCreatureCard("creature card of an opponent's choice"); + public MausoleumTurnkey(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); @@ -36,8 +35,10 @@ public final class MausoleumTurnkey extends CardImpl { this.toughness = new MageInt(2); // When Mausoleum Turnkey enters the battlefield, return target creature card of an opponent's choice from your graveyard to your hand. - this.addAbility(new EntersBattlefieldTriggeredAbility(new MausoleumTurnkeyEffect(), false)); - + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + ability.setTargetAdjuster(MausoleumTurnkeyAdjuster.instance); + this.addAbility(ability); } private MausoleumTurnkey(final MausoleumTurnkey card) { @@ -50,50 +51,27 @@ public final class MausoleumTurnkey extends CardImpl { } } -class MausoleumTurnkeyEffect extends OneShotEffect { - - MausoleumTurnkeyEffect() { - super(Outcome.Benefit); - this.staticText = "return target creature card of an opponent's choice from your graveyard to your hand"; - } - - private MausoleumTurnkeyEffect(final MausoleumTurnkeyEffect effect) { - super(effect); - } +// Exact copy of KarplusanMinotaurAdjuster +enum MausoleumTurnkeyAdjuster implements TargetAdjuster { + instance; @Override - public MausoleumTurnkeyEffect copy() { - return new MausoleumTurnkeyEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - UUID opponentId = null; - if (game.getOpponents(controller.getId()).size() > 1) { - Target target = new TargetOpponent(true); - if (controller.chooseTarget(outcome, target, source, game)) { - opponentId = target.getFirstTarget(); - } - } else { - opponentId = game.getOpponents(controller.getId()).iterator().next(); - } - if (opponentId != null) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null) { - FilterCreatureCard filter = new FilterCreatureCard("creature card from " + controller.getLogName() + " graveyard"); - filter.add(new OwnerIdPredicate(controller.getId())); - Target target = new TargetCardInGraveyard(filter); - opponent.chooseTarget(outcome, target, source, game); - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - controller.moveCards(card, Zone.HAND, source, game); - } - } - } - return true; + public void adjustTargets(Ability ability, Game game) { + Player controller = game.getPlayer(ability.getControllerId()); + if (controller == null) { + return; + } + UUID opponentId = null; + if (game.getOpponents(controller.getId()).size() > 1) { + Target target = new TargetOpponent(true); + if (controller.chooseTarget(Outcome.Neutral, target, ability, game)) { + opponentId = target.getFirstTarget(); + } + } else { + opponentId = game.getOpponents(controller.getId()).iterator().next(); + } + if (opponentId != null) { + ability.getTargets().get(0).setTargetController(opponentId); } - return false; } } diff --git a/Mage.Sets/src/mage/cards/m/MazesMantle.java b/Mage.Sets/src/mage/cards/m/MazesMantle.java index 3970420af8c..df561e997a7 100644 --- a/Mage.Sets/src/mage/cards/m/MazesMantle.java +++ b/Mage.Sets/src/mage/cards/m/MazesMantle.java @@ -3,9 +3,8 @@ package mage.cards.m; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.AttachedToMatchesFilterCondition; -import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; @@ -24,6 +23,15 @@ import mage.target.common.TargetCreaturePermanent; import java.util.UUID; public class MazesMantle extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("enchanted creature has toxic"); + + static { + filter.add(new AbilityPredicate(ToxicAbility.class)); + } + + private static final Condition condition = new AttachedToMatchesFilterCondition(filter); + public MazesMantle(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); this.addSubType(SubType.AURA); @@ -39,13 +47,9 @@ public class MazesMantle extends CardImpl { this.addAbility(ability); //When Maze’s Mantle enters the battlefield, if enchanted creature has toxic, that creature gains hexproof until end of turn. - FilterPermanent filter = new FilterPermanent("if enchanted creature has toxic"); - filter.add(new AbilityPredicate(ToxicAbility.class)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( - new GainAbilityAttachedEffect(HexproofAbility.getInstance(), AttachmentType.AURA, Duration.EndOfTurn)), - new AttachedToMatchesFilterCondition(filter), "When {this} enters, " + - "if enchanted creature has toxic, that creature gains hexproof until end of turn." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainAbilityAttachedEffect( + HexproofAbility.getInstance(), AttachmentType.AURA, Duration.EndOfTurn + ).setText("that creature gains hexproof until end of turn")).withInterveningIf(condition)); //Enchanted creature gets +2/+2. this.addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(2, 2, Duration.WhileOnBattlefield))); diff --git a/Mage.Sets/src/mage/cards/m/Mechanozoa.java b/Mage.Sets/src/mage/cards/m/Mechanozoa.java new file mode 100644 index 00000000000..cab8091e648 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/Mechanozoa.java @@ -0,0 +1,50 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.WarpAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Mechanozoa extends CardImpl { + + public Mechanozoa(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}{U}{U}"); + + this.subtype.add(SubType.ROBOT); + this.subtype.add(SubType.JELLYFISH); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // When this creature enters, tap target artifact or creature an opponent controls and put a stun counter on it. + Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); + ability.addEffect(new AddCountersTargetEffect(CounterType.STUN.createInstance()).setText("and put a stun counter on it")); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_ARTIFACT_OR_CREATURE)); + this.addAbility(ability); + + // Warp {2}{U} + this.addAbility(new WarpAbility(this, "{2}{U}")); + } + + private Mechanozoa(final Mechanozoa card) { + super(card); + } + + @Override + public Mechanozoa copy() { + return new Mechanozoa(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MemoriesReturning.java b/Mage.Sets/src/mage/cards/m/MemoriesReturning.java index a5b7c0e15b0..9e5c58141f6 100644 --- a/Mage.Sets/src/mage/cards/m/MemoriesReturning.java +++ b/Mage.Sets/src/mage/cards/m/MemoriesReturning.java @@ -74,6 +74,7 @@ class MemoriesReturningEffect extends OneShotEffect { } TargetPlayer target = new TargetOpponent(); target.withNotTarget(true); + controller.choose(Outcome.Neutral, target, source, game); Player opponent = game.getPlayer(target.getFirstTarget()); if (putCardOnBottom(controller, opponent, cards, source, game)) { return true; diff --git a/Mage.Sets/src/mage/cards/m/MerfolkAssassin.java b/Mage.Sets/src/mage/cards/m/MerfolkAssassin.java index 98873f31acd..19d2af39adf 100644 --- a/Mage.Sets/src/mage/cards/m/MerfolkAssassin.java +++ b/Mage.Sets/src/mage/cards/m/MerfolkAssassin.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class MerfolkAssassin extends CardImpl { // {tap}: Destroy target creature with islandwalk. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MerfolkSeastalkers.java b/Mage.Sets/src/mage/cards/m/MerfolkSeastalkers.java index 2d4d25f7e49..ca389f8ba5d 100644 --- a/Mage.Sets/src/mage/cards/m/MerfolkSeastalkers.java +++ b/Mage.Sets/src/mage/cards/m/MerfolkSeastalkers.java @@ -16,6 +16,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class MerfolkSeastalkers extends CardImpl { this.addAbility(new IslandwalkAbility()); SimpleActivatedAbility ability = new SimpleActivatedAbility(new TapTargetEffect(), new ManaCostsImpl<>("{2}{U}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MerfolkSovereign.java b/Mage.Sets/src/mage/cards/m/MerfolkSovereign.java index ca499fa5ac7..08dd298229a 100644 --- a/Mage.Sets/src/mage/cards/m/MerfolkSovereign.java +++ b/Mage.Sets/src/mage/cards/m/MerfolkSovereign.java @@ -14,6 +14,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -43,7 +44,7 @@ public final class MerfolkSovereign extends CardImpl { // {tap}: Target Merfolk creature can't be blocked this turn. Ability ability = new SimpleActivatedAbility(new CantBeBlockedTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter2)); + ability.addTarget(new TargetPermanent(filter2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MerfolkWindrobber.java b/Mage.Sets/src/mage/cards/m/MerfolkWindrobber.java index f5e341bca31..3d5a9c30432 100644 --- a/Mage.Sets/src/mage/cards/m/MerfolkWindrobber.java +++ b/Mage.Sets/src/mage/cards/m/MerfolkWindrobber.java @@ -1,25 +1,19 @@ package mage.cards.m; -import java.util.UUID; - import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.condition.common.CardsInOpponentGraveyardCondition; import mage.abilities.costs.common.SacrificeSourceCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.MillCardsTargetEffect; -import mage.constants.SubType; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; -import mage.game.events.GameEvent; -import mage.target.targetpointer.FixedTarget; +import mage.constants.SubType; + +import java.util.UUID; /** * @author TheElk801 @@ -38,11 +32,13 @@ public final class MerfolkWindrobber extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever Merfolk Windrobber deals combat damage to a player, that player mills a card. - this.addAbility(new MerfolkWindrobberTriggeredAbility()); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new MillCardsTargetEffect(1), false, true + )); // Sacrifice Merfolk Windrobber: Draw a card. Activate this ability only if an opponent has eight or more cards in their graveyard. this.addAbility(new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), + new DrawCardSourceControllerEffect(1), new SacrificeSourceCost(), CardsInOpponentGraveyardCondition.EIGHT ).addHint(CardsInOpponentGraveyardCondition.EIGHT.getHint())); } @@ -56,41 +52,3 @@ public final class MerfolkWindrobber extends CardImpl { return new MerfolkWindrobber(this); } } - -class MerfolkWindrobberTriggeredAbility extends TriggeredAbilityImpl { - - public MerfolkWindrobberTriggeredAbility() { - super(Zone.BATTLEFIELD, new MillCardsTargetEffect(1)); - } - - private MerfolkWindrobberTriggeredAbility(final MerfolkWindrobberTriggeredAbility ability) { - super(ability); - } - - @Override - public MerfolkWindrobberTriggeredAbility copy() { - return new MerfolkWindrobberTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; - if (damageEvent.isCombatDamage() && event.getSourceId().equals(this.getSourceId())) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getPlayerId())); - } - return true; - } - return false; - } - - @Override - public String getRule() { - return "Whenever {this} deals combat damage to a player, that player mills a card."; - } -} diff --git a/Mage.Sets/src/mage/cards/m/MeriadocBrandybuck.java b/Mage.Sets/src/mage/cards/m/MeriadocBrandybuck.java index cde68efd66b..09c7d3c85cc 100644 --- a/Mage.Sets/src/mage/cards/m/MeriadocBrandybuck.java +++ b/Mage.Sets/src/mage/cards/m/MeriadocBrandybuck.java @@ -1,17 +1,16 @@ package mage.cards.m; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.AttacksPlayerWithCreaturesTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SetTargetPointer; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.DefenderAttackedEvent; -import mage.game.events.GameEvent; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.game.permanent.token.FoodToken; import java.util.UUID; @@ -20,6 +19,7 @@ import java.util.UUID; * @author TheElk801 */ public final class MeriadocBrandybuck extends CardImpl { + FilterPermanent filter = new FilterControlledPermanent(SubType.HALFLING,"Halflings you control"); public MeriadocBrandybuck(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); @@ -31,7 +31,7 @@ public final class MeriadocBrandybuck extends CardImpl { this.toughness = new MageInt(2); // Whenever one or more Halflings you control attack a player, create a Food token. - this.addAbility(new MeriadocBrandybuckTriggeredAbility()); + this.addAbility(new AttacksPlayerWithCreaturesTriggeredAbility(new CreateTokenEffect(new FoodToken()), filter, SetTargetPointer.NONE)); } private MeriadocBrandybuck(final MeriadocBrandybuck card) { @@ -43,35 +43,3 @@ public final class MeriadocBrandybuck extends CardImpl { return new MeriadocBrandybuck(this); } } - -class MeriadocBrandybuckTriggeredAbility extends TriggeredAbilityImpl { - - MeriadocBrandybuckTriggeredAbility() { - super(Zone.BATTLEFIELD, new CreateTokenEffect(new FoodToken())); - setTriggerPhrase("Whenever one or more Halflings you control attack a player, "); - } - - private MeriadocBrandybuckTriggeredAbility(final MeriadocBrandybuckTriggeredAbility ability) { - super(ability); - } - - @Override - public MeriadocBrandybuckTriggeredAbility copy() { - return new MeriadocBrandybuckTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DEFENDER_ATTACKED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - return isControlledBy(event.getPlayerId()) - && game.getPlayer(event.getTargetId()) != null - && ((DefenderAttackedEvent) event) - .getAttackers(game) - .stream() - .anyMatch(permanent -> permanent.hasSubtype(SubType.HALFLING, game)); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MetallurgicSummonings.java b/Mage.Sets/src/mage/cards/m/MetallurgicSummonings.java index deb5729a571..42261b5ec34 100644 --- a/Mage.Sets/src/mage/cards/m/MetallurgicSummonings.java +++ b/Mage.Sets/src/mage/cards/m/MetallurgicSummonings.java @@ -1,26 +1,27 @@ - package mage.cards.m; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.ExileSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterSpell; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledArtifactPermanent; -import mage.filter.common.FilterInstantOrSorceryCard; -import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.permanent.token.MetallurgicSummoningsConstructToken; import mage.game.stack.Spell; import mage.players.Player; +import java.util.Optional; import java.util.UUID; /** @@ -28,26 +29,23 @@ import java.util.UUID; */ public final class MetallurgicSummonings extends CardImpl { - private static final FilterSpell filter = new FilterSpell("an instant or sorcery spell"); - - static { - filter.add(Predicates.or( - CardType.INSTANT.getPredicate(), - CardType.SORCERY.getPredicate())); - } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledArtifactPermanent("you control six or more artifacts"), + ComparisonType.MORE_THAN, 5 + ); public MetallurgicSummonings(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}"); // Whenever you cast an instant or sorcery spell, create an X/X colorless Construct artifact creature token, where X is that spell's converted mana cost. - this.addAbility(new SpellCastControllerTriggeredAbility(new MetallurgicSummoningsTokenEffect(), filter, false, SetTargetPointer.SPELL)); + this.addAbility(new SpellCastControllerTriggeredAbility( + new MetallurgicSummoningsTokenEffect(), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false + )); // {3}{U}{U}, Exile Metallurgic Summons: Return all instant and sorcery cards from your graveyard to your hand. Activate this ability only if you control six or more artifacts. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new MetallurgicSummoningsReturnEffect(), new ManaCostsImpl<>("{3}{U}{U}"), - new PermanentsOnTheBattlefieldCondition(new FilterControlledArtifactPermanent(), ComparisonType.MORE_THAN, 5), - "{3}{U}{U}, Exile {this}: Return all instant and sorcery cards from your graveyard to your hand." - + " Activate only if you control six or more artifacts."); + Ability ability = new ActivateIfConditionActivatedAbility( + new MetallurgicSummoningsReturnEffect(), new ManaCostsImpl<>("{3}{U}{U}"), condition + ); ability.addCost(new ExileSourceCost()); this.addAbility(ability); } @@ -75,15 +73,11 @@ class MetallurgicSummoningsTokenEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getSpellOrLKIStack(this.getTargetPointer().getFirst(game, source)); - if (spell != null) { - int cmc = spell.getManaValue(); - if (cmc > 0) { - return new CreateTokenEffect(new MetallurgicSummoningsConstructToken(cmc)).apply(game, source); - } - return true; - } - return false; + int mv = Optional + .ofNullable((Spell) getValue("spellCast")) + .map(Spell::getManaValue) + .orElse(0); + return new MetallurgicSummoningsConstructToken(mv).putOntoBattlefield(1, game, source); } @Override @@ -96,7 +90,7 @@ class MetallurgicSummoningsReturnEffect extends OneShotEffect { MetallurgicSummoningsReturnEffect() { super(Outcome.PutCardInPlay); - this.staticText = "Return all instant and sorcery cards from your graveyard to your hand. Activate only if you control six or more artifacts"; + this.staticText = "return all instant and sorcery cards from your graveyard to your hand"; } private MetallurgicSummoningsReturnEffect(final MetallurgicSummoningsReturnEffect effect) { @@ -111,10 +105,11 @@ class MetallurgicSummoningsReturnEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - return controller.moveCards(controller.getGraveyard().getCards(new FilterInstantOrSorceryCard(), - source.getControllerId(), source, game), Zone.HAND, source, game); - } - return false; + return controller != null && controller.moveCards( + controller.getGraveyard().getCards( + StaticFilters.FILTER_CARDS_INSTANT_AND_SORCERY, + source.getControllerId(), source, game + ), Zone.HAND, source, game + ); } } diff --git a/Mage.Sets/src/mage/cards/m/MeticulousExcavation.java b/Mage.Sets/src/mage/cards/m/MeticulousExcavation.java index 3847f745780..7b31635c5e4 100644 --- a/Mage.Sets/src/mage/cards/m/MeticulousExcavation.java +++ b/Mage.Sets/src/mage/cards/m/MeticulousExcavation.java @@ -28,8 +28,7 @@ public final class MeticulousExcavation extends CardImpl { // {2}{W}: Return target permanent you control to its owner's hand. If it has unearth, instead exile it, then return that card to its owner's hand. Activate only during your turn. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new MeticulousExcavationEffect(), - new ManaCostsImpl<>("{2}{W}"), MyTurnCondition.instance + new MeticulousExcavationEffect(), new ManaCostsImpl<>("{2}{W}"), MyTurnCondition.instance ); ability.addTarget(new TargetControlledPermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/m/MightMakesRight.java b/Mage.Sets/src/mage/cards/m/MightMakesRight.java index 570b2f2a3af..4d45e70af2e 100644 --- a/Mage.Sets/src/mage/cards/m/MightMakesRight.java +++ b/Mage.Sets/src/mage/cards/m/MightMakesRight.java @@ -1,47 +1,48 @@ - package mage.cards.m; -import java.util.List; -import java.util.UUID; +import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.abilities.keyword.HasteAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; +import mage.game.Controllable; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.List; +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * @author Quercitron */ public final class MightMakesRight extends CardImpl { - private static final String ruleText = "At the beginning of combat on your turn, if you control each creature on the battlefield with the greatest power, " - + "gain control of target creature an opponent controls until end of turn. Untap that creature. It gains haste until end of turn."; - public MightMakesRight(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{5}{R}"); - // At the beginning of combat on your turn, if you control each creature on the battlefield with the greatest power, gain control // of target creature an opponent controls until end of turn. Untap that creature. It gains haste until end of turn. - TriggeredAbility gainControlAbility = new BeginningOfCombatTriggeredAbility(new GainControlTargetEffect(Duration.EndOfTurn)); - gainControlAbility.addEffect(new UntapTargetEffect()); - gainControlAbility.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn)); - gainControlAbility.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); - Ability conditionalAbility = new ConditionalInterveningIfTriggeredAbility(gainControlAbility, ControlsEachCreatureWithGreatestPowerCondition.instance, ruleText); - this.addAbility(conditionalAbility); + Ability ability = new BeginningOfCombatTriggeredAbility(new GainControlTargetEffect(Duration.EndOfTurn)) + .withInterveningIf(ControlsEachCreatureWithGreatestPowerCondition.instance); + ability.addEffect(new UntapTargetEffect("Untap that creature")); + ability.addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("It gains haste until end of turn")); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); + this.addAbility(ability); } private MightMakesRight(final MightMakesRight card) { @@ -55,30 +56,31 @@ public final class MightMakesRight extends CardImpl { } enum ControlsEachCreatureWithGreatestPowerCondition implements Condition { - instance; - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - @Override public boolean apply(Game game, Ability source) { - Integer maxPower = null; - boolean result = false; - List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); - for (Permanent permanent : permanents) { - if (permanent == null) { - continue; - } - int power = permanent.getPower().getValue(); - if (maxPower == null || power > maxPower) { - maxPower = permanent.getPower().getValue(); - result = true; - } - if (power == maxPower) { - result &= permanent.isControlledBy(source.getControllerId()); - } + List permanents = game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game + ); + if (permanents.isEmpty()) { + return false; } - return result; + int max = permanents + .stream() + .map(MageObject::getPower) + .mapToInt(MageInt::getValue) + .max() + .orElse(Integer.MIN_VALUE); + return permanents + .stream() + .filter(permanent -> permanent.getPower().getValue() >= max) + .map(Controllable::getControllerId) + .allMatch(source::isControlledBy); } + @Override + public String toString() { + return "you control each creature on the battlefield with the greatest power"; + } } diff --git a/Mage.Sets/src/mage/cards/m/MightWeaver.java b/Mage.Sets/src/mage/cards/m/MightWeaver.java index 29dc9d2cea2..8d2d8000e17 100644 --- a/Mage.Sets/src/mage/cards/m/MightWeaver.java +++ b/Mage.Sets/src/mage/cards/m/MightWeaver.java @@ -18,6 +18,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -42,7 +43,7 @@ public final class MightWeaver extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(1); Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn), new GenericManaCost(2)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MightyEmergence.java b/Mage.Sets/src/mage/cards/m/MightyEmergence.java index be78171d7f6..f1bbae84c35 100644 --- a/Mage.Sets/src/mage/cards/m/MightyEmergence.java +++ b/Mage.Sets/src/mage/cards/m/MightyEmergence.java @@ -1,8 +1,6 @@ package mage.cards.m; -import java.util.UUID; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; -import mage.abilities.effects.Effect; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -11,28 +9,31 @@ import mage.constants.ComparisonType; import mage.constants.SetTargetPointer; import mage.constants.Zone; import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import java.util.UUID; + /** - * * @author Plopman */ public final class MightyEmergence extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a creature with power 5 or greater"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("a creature you control with power 5 or greater"); static { filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 4)); } public MightyEmergence(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); // Whenever a creature with power 5 or greater you control enters, you may put two +1/+1 counters on it. - Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)); - effect.setText("you may put two +1/+1 counters on it"); - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, effect, filter, true, SetTargetPointer.PERMANENT)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)) + .setText("put two +1/+1 counters on it"), filter, true, SetTargetPointer.PERMANENT + )); } private MightyEmergence(final MightyEmergence card) { diff --git a/Mage.Sets/src/mage/cards/m/MilesTailsPrower.java b/Mage.Sets/src/mage/cards/m/MilesTailsPrower.java new file mode 100644 index 00000000000..0c6d3459eee --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MilesTailsPrower.java @@ -0,0 +1,95 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.game.Controllable; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MilesTailsPrower extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.VEHICLE); + + public MilesTailsPrower(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.FOX); + this.subtype.add(SubType.ARTIFICER); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever a Vehicle you control enters, draw a card if it has flying. Otherwise, put a flying counter on it. + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + Zone.BATTLEFIELD, new MilesTailsProwerEffect(), filter, false, SetTargetPointer.PERMANENT + )); + } + + private MilesTailsPrower(final MilesTailsPrower card) { + super(card); + } + + @Override + public MilesTailsPrower copy() { + return new MilesTailsPrower(this); + } +} + +class MilesTailsProwerEffect extends OneShotEffect { + + MilesTailsProwerEffect() { + super(Outcome.Benefit); + staticText = "draw a card if it has flying. Otherwise, put a flying counter on it"; + } + + private MilesTailsProwerEffect(final MilesTailsProwerEffect effect) { + super(effect); + } + + @Override + public MilesTailsProwerEffect copy() { + return new MilesTailsProwerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = (Permanent) getValue("permanentEnteringBattlefield"); + if (permanent == null) { + return false; + } + if (permanent.hasAbility(FlyingAbility.getInstance(), game)) { + return Optional + .ofNullable(source) + .map(Controllable::getControllerId) + .map(game::getPlayer) + .filter(player -> player.drawCards(1, source, game) > 0) + .isPresent(); + } + return Optional + .ofNullable(getTargetPointer().getFirstTargetPermanentOrLKI(game, source)) + .filter(p -> p.addCounters(CounterType.FLYING.createInstance(), source, game)) + .isPresent(); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MinamoSightbender.java b/Mage.Sets/src/mage/cards/m/MinamoSightbender.java index 5120222bc51..7b4b16a5072 100644 --- a/Mage.Sets/src/mage/cards/m/MinamoSightbender.java +++ b/Mage.Sets/src/mage/cards/m/MinamoSightbender.java @@ -13,6 +13,7 @@ import mage.constants.ComparisonType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.PowerTargetAdjuster; @@ -36,7 +37,7 @@ public final class MinamoSightbender extends CardImpl { // {X}, {T}: Target creature with power X or less can't be blocked this turn. Ability ability = new SimpleActivatedAbility(new CantBeBlockedTargetEffect(), new ManaCostsImpl<>("{X}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); ability.setTargetAdjuster(new PowerTargetAdjuster(ComparisonType.OR_LESS)); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/m/MinasTirith.java b/Mage.Sets/src/mage/cards/m/MinasTirith.java index a7ef0249a44..6e580899c59 100644 --- a/Mage.Sets/src/mage/cards/m/MinasTirith.java +++ b/Mage.Sets/src/mage/cards/m/MinasTirith.java @@ -16,7 +16,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SuperType; import mage.constants.WatcherScope; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; @@ -54,7 +53,7 @@ public final class MinasTirith extends CardImpl { // {1}{W}, {T}: Draw a card. Activate only if you attacked with two or more creatures this turn. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), + new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{1}{W}"), MinasTirithCondition.instance ); ability.addCost(new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/m/MindlinkMech.java b/Mage.Sets/src/mage/cards/m/MindlinkMech.java index 4e7a8387228..c1f283c996c 100644 --- a/Mage.Sets/src/mage/cards/m/MindlinkMech.java +++ b/Mage.Sets/src/mage/cards/m/MindlinkMech.java @@ -12,25 +12,25 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.MageObjectReferencePredicate; import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.filter.predicate.permanent.CrewedSourceThisTurnPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; -import mage.util.CardUtil; import mage.util.functions.CopyApplier; import mage.watchers.Watcher; -import java.util.*; -import java.util.stream.Collectors; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; /** * @author TheElk801 */ public final class MindlinkMech extends CardImpl { - public MindlinkMech(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{U}"); @@ -60,9 +60,18 @@ public final class MindlinkMech extends CardImpl { class MindlinkMechTriggeredAbility extends TriggeredAbilityImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("nonlegendary creature that crewed it this turn"); + + static { + filter.add(CrewedSourceThisTurnPredicate.instance); + filter.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); + } + MindlinkMechTriggeredAbility() { super(Zone.BATTLEFIELD, new MindlinkMechEffect()); this.addWatcher(new MindlinkMechWatcher()); + this.addTarget(new TargetPermanent(filter)); + this.setTriggerPhrase("Whenever {this} becomes crewed for the first time each turn"); } private MindlinkMechTriggeredAbility(final MindlinkMechTriggeredAbility ability) { @@ -81,26 +90,13 @@ class MindlinkMechTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (!event.getSourceId().equals(getSourceId()) || !MindlinkMechWatcher.checkVehicle(this, game)) { - return false; - } - this.getTargets().clear(); - this.addTarget(new TargetPermanent(MindlinkMechWatcher.makeFilter(this, game))); - return true; - } - - @Override - public String getRule() { - return "Whenever {this} becomes crewed for the first time each turn, until end of turn, " + - "{this} becomes a copy of target nonlegendary creature that crewed it this turn, " + - "except it's 4/3, it's a Vehicle artifact in addition to its other types, and it has flying."; + return event.getSourceId().equals(getSourceId()) && MindlinkMechWatcher.checkVehicle(this, game); } } class MindlinkMechWatcher extends Watcher { private final Map crewCount = new HashMap<>(); - private final Map> crewMap = new HashMap<>(); private static final FilterPermanent invalidFilter = new FilterPermanent(); static { @@ -114,34 +110,16 @@ class MindlinkMechWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { Permanent vehicle; - Permanent crewer; - switch (event.getType()) { - case VEHICLE_CREWED: - vehicle = game.getPermanent(event.getTargetId()); - crewer = null; - break; - case CREWED_VEHICLE: - vehicle = game.getPermanent(event.getSourceId()); - crewer = game.getPermanent(event.getTargetId()); - break; - default: - return; - } - if (vehicle == null) { - return; - } - if (crewer == null) { + if (event.getType() == GameEvent.EventType.VEHICLE_CREWED) { + vehicle = game.getPermanent(event.getTargetId()); crewCount.compute(new MageObjectReference(vehicle, game), (m, i) -> i == null ? 1 : Integer.sum(i, 1)); - return; } - crewMap.computeIfAbsent(new MageObjectReference(vehicle, game), x -> new HashSet<>()).add(new MageObjectReference(crewer, game)); } @Override public void reset() { super.reset(); crewCount.clear(); - crewMap.clear(); } public static boolean checkVehicle(Ability source, Game game) { @@ -151,34 +129,14 @@ class MindlinkMechWatcher extends Watcher { .crewCount .getOrDefault(new MageObjectReference(source), 0) < 2; } - - public static FilterPermanent makeFilter(Ability source, Game game) { - Set predicates = game - .getState() - .getWatcher(MindlinkMechWatcher.class) - .crewMap - .computeIfAbsent(new MageObjectReference(game.getPermanent(source.getSourceId()), game), x -> new HashSet<>()) - .stream() - .filter(mor -> { - Permanent permanent = mor.getPermanent(game); - return permanent != null && !permanent.isLegendary(game) && permanent.isCreature(game); - }).map(MageObjectReferencePredicate::new) - .collect(Collectors.toSet()); - if (predicates.isEmpty()) { - return invalidFilter; - } - FilterPermanent filterPermanent = new FilterPermanent( - "nonlegendary creature that crewed " + CardUtil.getSourceName(game, source) + " this turn" - ); - filterPermanent.add(Predicates.or(predicates)); - return filterPermanent; - } } class MindlinkMechEffect extends OneShotEffect { MindlinkMechEffect() { super(Outcome.Benefit); + this.setText("until end of turn, {this} becomes a copy of target nonlegendary creature that crewed it this turn, " + + "except it's 4/3, it's a Vehicle artifact in addition to its other types, and it has flying."); } private MindlinkMechEffect(final MindlinkMechEffect effect) { @@ -212,4 +170,4 @@ class MindlinkMechApplier extends CopyApplier { blueprint.getAbilities().add(FlyingAbility.getInstance()); return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/m/MindwrackDemon.java b/Mage.Sets/src/mage/cards/m/MindwrackDemon.java index c318d5a3d7f..119a9f2bbfd 100644 --- a/Mage.Sets/src/mage/cards/m/MindwrackDemon.java +++ b/Mage.Sets/src/mage/cards/m/MindwrackDemon.java @@ -1,29 +1,32 @@ package mage.cards.m; -import java.util.UUID; - import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.DeliriumCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** * @author fireshoes */ public final class MindwrackDemon extends CardImpl { + private static final Condition condition = new InvertCondition(DeliriumCondition.instance); + public MindwrackDemon(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); this.subtype.add(SubType.DEMON); @@ -40,12 +43,10 @@ public final class MindwrackDemon extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new MillCardsControllerEffect(4))); // At the beginning of your upkeep, if you don't have 4 or more card types in your graveyard, you lose 4 life. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new LoseLifeSourceControllerEffect(4)), - new InvertCondition(DeliriumCondition.instance), - "Delirium — At the beginning of your upkeep, you lose 4 life unless there are four or more card types among cards in your graveyard."); - ability.addHint(CardTypesInGraveyardCount.YOU.getHint()); - this.addAbility(ability); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new ConditionalOneShotEffect( + null, new LoseLifeSourceControllerEffect(4), DeliriumCondition.instance, + "you lose 4 life unless there are four or more card types among cards in your graveyard" + )).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); } private MindwrackDemon(final MindwrackDemon card) { diff --git a/Mage.Sets/src/mage/cards/m/MineRaider.java b/Mage.Sets/src/mage/cards/m/MineRaider.java index 48fbf632edb..d13f6f6cc4c 100644 --- a/Mage.Sets/src/mage/cards/m/MineRaider.java +++ b/Mage.Sets/src/mage/cards/m/MineRaider.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; @@ -26,7 +25,7 @@ import java.util.UUID; */ public final class MineRaider extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent(); + private static final FilterPermanent filter = new FilterControlledPermanent("you control another outlaw"); static { filter.add(AnotherPredicate.instance); @@ -34,7 +33,7 @@ public final class MineRaider extends CardImpl { } private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); - private static final Hint hint = new ConditionHint(condition, "You control another outlaw"); + private static final Hint hint = new ConditionHint(condition); public MineRaider(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); @@ -48,10 +47,8 @@ public final class MineRaider extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // When Mine Raider enters the battlefield, if you control another outlaw, create a Treasure token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new TreasureToken())), condition, - "When {this} enters, if you control another outlaw, create a Treasure token." - ).addHint(hint)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new TreasureToken())) + .withInterveningIf(condition).addHint(hint)); } private MineRaider(final MineRaider card) { diff --git a/Mage.Sets/src/mage/cards/m/MirkwoodTrapper.java b/Mage.Sets/src/mage/cards/m/MirkwoodTrapper.java index 843aa8760e8..c92d3a26ff2 100644 --- a/Mage.Sets/src/mage/cards/m/MirkwoodTrapper.java +++ b/Mage.Sets/src/mage/cards/m/MirkwoodTrapper.java @@ -5,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.PlayerAttacksTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; @@ -40,11 +39,7 @@ public final class MirkwoodTrapper extends CardImpl { this.addAbility(new MirkwoodTrapperTriggerAttackYou()); // Whenever a player attacks, if they aren't attacking you, that player chooses an attacking creature. It gets +2/+0 until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new PlayerAttacksTriggeredAbility(new MirkwoodTrapperEffect(), true), - NotAttackingSourceControllerCondition.instance, - "Whenever a player attacks, if they aren't attacking you, that player chooses an attacking creature. It gets +2/+0 until end of turn." - )); + this.addAbility(new PlayerAttacksTriggeredAbility(new MirkwoodTrapperEffect(), true).withInterveningIf(MirkwoodTrapperCondition.instance)); } private MirkwoodTrapper(final MirkwoodTrapper card) { @@ -85,15 +80,15 @@ class MirkwoodTrapperTriggerAttackYou extends TriggeredAbilityImpl { } } -enum NotAttackingSourceControllerCondition implements Condition { +enum MirkwoodTrapperCondition implements Condition { instance; @Override public boolean apply(Game game, Ability source) { return game.getCombat() - .getPlayerDefenders(game, false) - .stream() - .noneMatch(pId -> pId.equals(source.getControllerId())); + .getPlayerDefenders(game, false) + .stream() + .noneMatch(pId -> pId.equals(source.getControllerId())); } @Override @@ -143,4 +138,4 @@ class MirkwoodTrapperEffect extends OneShotEffect { return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/m/MirrorOfLifeTrapping.java b/Mage.Sets/src/mage/cards/m/MirrorOfLifeTrapping.java index 8e6e36841d4..d4e15becb54 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorOfLifeTrapping.java +++ b/Mage.Sets/src/mage/cards/m/MirrorOfLifeTrapping.java @@ -104,7 +104,7 @@ class MirrorOfLifeTrappingEffect extends OneShotEffect { if (toBattlefield != null) { game.processAction(); controller.moveCards(toBattlefield.getCards(StaticFilters.FILTER_CARD_PERMANENT, game), - Zone.BATTLEFIELD, source, game, false, true, true, null); + Zone.BATTLEFIELD, source, game, false, false, true, null); } return true; diff --git a/Mage.Sets/src/mage/cards/m/MirrorSigilSergeant.java b/Mage.Sets/src/mage/cards/m/MirrorSigilSergeant.java index a57dd03d453..2731f6476a7 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorSigilSergeant.java +++ b/Mage.Sets/src/mage/cards/m/MirrorSigilSergeant.java @@ -1,16 +1,12 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.CreateTokenCopySourceEffect; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -18,19 +14,20 @@ import mage.constants.SubType; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class MirrorSigilSergeant extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("blue permanent"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("you control a blue permanent"); static { filter.add(new ColorPredicate(ObjectColor.BLUE)); } - private static final String rule = "At the beginning of your upkeep, if you control a blue permanent, you may create a token that's a copy of {this}."; + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); public MirrorSigilSergeant(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}"); @@ -44,11 +41,9 @@ public final class MirrorSigilSergeant extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // At the beginning of your upkeep, if you control a blue permanent, you may create a token that's a copy of Mirror-Sigil Sergeant. - Effect effect = new CreateTokenCopySourceEffect(); - effect.setText("you may create a token that's a copy of {this}"); - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(effect, true); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new PermanentsOnTheBattlefieldCondition(filter), rule)); - + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new CreateTokenCopySourceEffect(), true + ).withInterveningIf(condition)); } private MirrorSigilSergeant(final MirrorSigilSergeant card) { diff --git a/Mage.Sets/src/mage/cards/m/MirrorStrike.java b/Mage.Sets/src/mage/cards/m/MirrorStrike.java index 71b5fc782a6..f0c984ccebb 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorStrike.java +++ b/Mage.Sets/src/mage/cards/m/MirrorStrike.java @@ -17,6 +17,7 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.UnblockedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -36,7 +37,7 @@ public final class MirrorStrike extends CardImpl { // All combat damage that would be dealt to you this turn by target unblocked creature is dealt to its controller instead. this.getSpellAbility().addEffect(new MirrorStrikeEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private MirrorStrike(final MirrorStrike card) { diff --git a/Mage.Sets/src/mage/cards/m/MirrorUniverse.java b/Mage.Sets/src/mage/cards/m/MirrorUniverse.java index 4f16b7e18ea..6137a7f16e3 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorUniverse.java +++ b/Mage.Sets/src/mage/cards/m/MirrorUniverse.java @@ -1,22 +1,19 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.ExchangeLifeControllerTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.PhaseStep; -import mage.constants.Zone; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author Styxo */ public final class MirrorUniverse extends CardImpl { @@ -25,11 +22,9 @@ public final class MirrorUniverse extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}"); // {tap}, Sacrifice Mirror Universe: Exchange life totals with target opponent. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, + Ability ability = new ActivateIfConditionActivatedAbility( new ExchangeLifeControllerTargetEffect(), - new TapSourceCost(), - new IsStepCondition(PhaseStep.UPKEEP) + new TapSourceCost(), IsStepCondition.getMyUpkeep() ); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetOpponent()); diff --git a/Mage.Sets/src/mage/cards/m/MischiefAndMayhem.java b/Mage.Sets/src/mage/cards/m/MischiefAndMayhem.java index 3b2c2c39d2e..cf420f4d3f4 100644 --- a/Mage.Sets/src/mage/cards/m/MischiefAndMayhem.java +++ b/Mage.Sets/src/mage/cards/m/MischiefAndMayhem.java @@ -1,16 +1,15 @@ package mage.cards.m; -import java.util.UUID; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class MischiefAndMayhem extends CardImpl { @@ -20,7 +19,7 @@ public final class MischiefAndMayhem extends CardImpl { // Up to two target creatures each get +4/+4 until end of turn. this.getSpellAbility().addEffect(new BoostTargetEffect(4, 4, Duration.EndOfTurn)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2, StaticFilters.FILTER_PERMANENT_CREATURES, false)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2)); } private MischiefAndMayhem(final MischiefAndMayhem card) { diff --git a/Mage.Sets/src/mage/cards/m/MishrasFactory.java b/Mage.Sets/src/mage/cards/m/MishrasFactory.java index 28abadfa49c..8a2217455ca 100644 --- a/Mage.Sets/src/mage/cards/m/MishrasFactory.java +++ b/Mage.Sets/src/mage/cards/m/MishrasFactory.java @@ -13,6 +13,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.game.permanent.token.custom.CreatureToken; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -46,7 +47,7 @@ public final class MishrasFactory extends CardImpl { SimpleActivatedAbility ability = new SimpleActivatedAbility( new BoostTargetEffect(1, 1, Duration.EndOfTurn), new TapSourceCost() ); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MishrasWarMachine.java b/Mage.Sets/src/mage/cards/m/MishrasWarMachine.java index 38814d489e2..63ecd3d24ee 100644 --- a/Mage.Sets/src/mage/cards/m/MishrasWarMachine.java +++ b/Mage.Sets/src/mage/cards/m/MishrasWarMachine.java @@ -2,10 +2,10 @@ package mage.cards.m; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.BandingAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -51,7 +51,7 @@ class MishrasWarMachineEffect extends OneShotEffect { MishrasWarMachineEffect() { super(Outcome.Sacrifice); - staticText = "{this} deals 3 damage to you unless you discard a card. If Mishra's War Machine deals damage to you this way, tap it"; + staticText = "{this} deals 3 damage to you unless you discard a card. If {this} deals damage to you this way, tap it"; } private MishrasWarMachineEffect(final MishrasWarMachineEffect effect) { diff --git a/Mage.Sets/src/mage/cards/m/MistbladeShinobi.java b/Mage.Sets/src/mage/cards/m/MistbladeShinobi.java index 9959e14301a..08d0839ba63 100644 --- a/Mage.Sets/src/mage/cards/m/MistbladeShinobi.java +++ b/Mage.Sets/src/mage/cards/m/MistbladeShinobi.java @@ -11,6 +11,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; @@ -37,7 +38,7 @@ public final class MistbladeShinobi extends CardImpl { // Whenever Mistblade Shinobi deals combat damage to a player, you may return target creature that player controls to its owner's hand. Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new ReturnToHandTargetEffect(), true, true); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MistveilPlains.java b/Mage.Sets/src/mage/cards/m/MistveilPlains.java index 09cb3dea2eb..b6616d7597c 100644 --- a/Mage.Sets/src/mage/cards/m/MistveilPlains.java +++ b/Mage.Sets/src/mage/cards/m/MistveilPlains.java @@ -1,10 +1,10 @@ package mage.cards.m; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -20,6 +20,8 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** * @author LevelX2 */ @@ -31,6 +33,8 @@ public final class MistveilPlains extends CardImpl { filter.add(new ColorPredicate(ObjectColor.WHITE)); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); + public MistveilPlains(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); this.subtype.add(SubType.PLAINS); @@ -43,15 +47,11 @@ public final class MistveilPlains extends CardImpl { // {W}, {tap}: Put target card from your graveyard on the bottom of your library. Activate this ability only if you control two or more white permanents. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new MistveilPlainsGraveyardToLibraryEffect(), - new ManaCostsImpl<>("{W}"), - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1) + new MistveilPlainsGraveyardToLibraryEffect(), new ManaCostsImpl<>("{W}"), condition ); ability.addTarget(new TargetCardInYourGraveyard()); ability.addCost(new TapSourceCost()); this.addAbility(ability); - } private MistveilPlains(final MistveilPlains card) { diff --git a/Mage.Sets/src/mage/cards/m/MizziumMortars.java b/Mage.Sets/src/mage/cards/m/MizziumMortars.java index af8e09f6bfc..e04f5b04a4b 100644 --- a/Mage.Sets/src/mage/cards/m/MizziumMortars.java +++ b/Mage.Sets/src/mage/cards/m/MizziumMortars.java @@ -8,10 +8,13 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author LevelX2 */ @@ -21,7 +24,7 @@ public final class MizziumMortars extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); // MizziumMortars deals 4 damage to target creature you don't control. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.getSpellAbility().addEffect(new DamageTargetEffect(4)); // Overload {3}{R}{R}{R} (You may cast this spell for its overload cost. If you do, change its text by replacing all instances of "target" with "each.") diff --git a/Mage.Sets/src/mage/cards/m/MizziumSkin.java b/Mage.Sets/src/mage/cards/m/MizziumSkin.java index 4e64224f007..1d70c946bec 100644 --- a/Mage.Sets/src/mage/cards/m/MizziumSkin.java +++ b/Mage.Sets/src/mage/cards/m/MizziumSkin.java @@ -14,8 +14,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED; + /** * @@ -29,7 +32,7 @@ public final class MizziumSkin extends CardImpl { // Target creature you control gets +0/+1 and gains hexproof until end of turn. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_CONTROLLED)); this.getSpellAbility().addEffect(new BoostTargetEffect(0,1, Duration.EndOfTurn).setText("target creature you control gets +0/+1")); this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HexproofAbility.getInstance(), Duration.EndOfTurn).setText("and gains hexproof until end of turn")); @@ -47,4 +50,4 @@ public final class MizziumSkin extends CardImpl { public MizziumSkin copy() { return new MizziumSkin(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/m/ModifyMemory.java b/Mage.Sets/src/mage/cards/m/ModifyMemory.java index aaa41a8fb68..b41118ba499 100644 --- a/Mage.Sets/src/mage/cards/m/ModifyMemory.java +++ b/Mage.Sets/src/mage/cards/m/ModifyMemory.java @@ -14,7 +14,7 @@ import mage.game.Controllable; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.targetpointer.EachTargetPointer; import java.util.Collection; @@ -67,7 +67,7 @@ enum ModifyMemoryCondition implements Condition { } } -class ModifyMemoryTarget extends TargetCreaturePermanent { +class ModifyMemoryTarget extends TargetPermanent { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures controlled by different players"); diff --git a/Mage.Sets/src/mage/cards/m/MoggJailer.java b/Mage.Sets/src/mage/cards/m/MoggJailer.java index 455abd71cb0..f8a720ed30e 100644 --- a/Mage.Sets/src/mage/cards/m/MoggJailer.java +++ b/Mage.Sets/src/mage/cards/m/MoggJailer.java @@ -1,7 +1,6 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.Effect; @@ -9,14 +8,15 @@ import mage.abilities.effects.common.combat.CantAttackIfDefenderControlsPermanen import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; -import mage.constants.Zone; +import mage.constants.SubType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.PowerPredicate; import mage.filter.predicate.permanent.TappedPredicate; +import java.util.UUID; + /** * @author BursegSardaukar */ @@ -36,7 +36,7 @@ public final class MoggJailer extends CardImpl { // Mogg Jailer can't attack if defending player controls an untapped creature with power 2 or less. Effect effect = new CantAttackIfDefenderControlsPermanent(filter); - effect.setText("Mogg Jailer can't attack if defending player controls an untapped creature with power 2 or less."); + effect.setText("{this} can't attack if defending player controls an untapped creature with power 2 or less."); this.addAbility(new SimpleStaticAbility(effect)); } diff --git a/Mage.Sets/src/mage/cards/m/MoltenEchoes.java b/Mage.Sets/src/mage/cards/m/MoltenEchoes.java index 6157be1cfd1..5b6493315b5 100644 --- a/Mage.Sets/src/mage/cards/m/MoltenEchoes.java +++ b/Mage.Sets/src/mage/cards/m/MoltenEchoes.java @@ -3,7 +3,7 @@ package mage.cards.m; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.AsEntersBattlefieldAbility; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseCreatureTypeEffect; @@ -15,6 +15,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SetTargetPointer; import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.ChosenSubtypePredicate; import mage.filter.predicate.permanent.TokenPredicate; @@ -25,11 +26,17 @@ import mage.target.targetpointer.FixedTarget; import java.util.UUID; /** - * * @author ciaccona007 */ public final class MoltenEchoes extends CardImpl { + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("nontoken creature you control of the chosen type"); + + static { + filter.add(TokenPredicate.FALSE); + filter.add(ChosenSubtypePredicate.TRUE); + } + public MoltenEchoes(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}{R}"); @@ -37,14 +44,9 @@ public final class MoltenEchoes extends CardImpl { this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.Copy))); // Whenever a nontoken creature of the chosen type you control enters, create a token that's a copy of that creature. That token gains haste. Exile it at the beginning of the next end step. - FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("nontoken creature of the chosen type"); - filter.add(TokenPredicate.FALSE); - filter.add(ChosenSubtypePredicate.TRUE); - - Ability ability = new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, new MoltenEchoesEffect(), - filter, false, SetTargetPointer.PERMANENT - ); - this.addAbility(ability); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + Zone.BATTLEFIELD, new MoltenEchoesEffect(), filter, false, SetTargetPointer.PERMANENT + )); } private MoltenEchoes(final MoltenEchoes card) { diff --git a/Mage.Sets/src/mage/cards/m/MoltenFrame.java b/Mage.Sets/src/mage/cards/m/MoltenFrame.java index f36e9804ec9..2a889f2eeaa 100644 --- a/Mage.Sets/src/mage/cards/m/MoltenFrame.java +++ b/Mage.Sets/src/mage/cards/m/MoltenFrame.java @@ -10,6 +10,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -28,7 +29,7 @@ public final class MoltenFrame extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{R}"); this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{2}"))); } diff --git a/Mage.Sets/src/mage/cards/m/MoltenPsyche.java b/Mage.Sets/src/mage/cards/m/MoltenPsyche.java index f65d6f902a3..69011bd09ce 100644 --- a/Mage.Sets/src/mage/cards/m/MoltenPsyche.java +++ b/Mage.Sets/src/mage/cards/m/MoltenPsyche.java @@ -47,7 +47,7 @@ class MoltenPsycheEffect extends OneShotEffect { MoltenPsycheEffect() { super(Outcome.Neutral); - staticText = "Each player shuffles the cards from their hand into their library, then draws that many cards.\n" + staticText = "Each player shuffles the cards from their hand into their library, then draws that many cards.
" + "Metalcraft — If you control three or more artifacts, {this} deals damage to each opponent equal to the number of cards that player has drawn this turn."; } diff --git a/Mage.Sets/src/mage/cards/m/MoltenRain.java b/Mage.Sets/src/mage/cards/m/MoltenRain.java index 39b8e3b5a29..bcf60e55094 100644 --- a/Mage.Sets/src/mage/cards/m/MoltenRain.java +++ b/Mage.Sets/src/mage/cards/m/MoltenRain.java @@ -45,7 +45,7 @@ class MoltenRainEffect extends OneShotEffect { MoltenRainEffect() { super(Outcome.Damage); - this.staticText = "If that land was nonbasic, Molten Rain deals 2 damage to the land's controller"; + this.staticText = "If that land was nonbasic, {this} deals 2 damage to the land's controller"; } private MoltenRainEffect(final MoltenRainEffect effect) { diff --git a/Mage.Sets/src/mage/cards/m/MomentOfValor.java b/Mage.Sets/src/mage/cards/m/MomentOfValor.java index dda0fef5ac3..400b9420ae6 100644 --- a/Mage.Sets/src/mage/cards/m/MomentOfValor.java +++ b/Mage.Sets/src/mage/cards/m/MomentOfValor.java @@ -12,6 +12,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -39,7 +40,7 @@ public final class MomentOfValor extends CardImpl { // * Destroy target creature with power 4 or greater. Mode mode = new Mode(new DestroyTargetEffect()); - mode.addTarget(new TargetCreaturePermanent(filter)); + mode.addTarget(new TargetPermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/m/MomentumRumbler.java b/Mage.Sets/src/mage/cards/m/MomentumRumbler.java index b6875666aa8..debaaf01f2c 100644 --- a/Mage.Sets/src/mage/cards/m/MomentumRumbler.java +++ b/Mage.Sets/src/mage/cards/m/MomentumRumbler.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.DoubleStrikeAbility; @@ -33,20 +32,15 @@ public final class MomentumRumbler extends CardImpl { this.toughness = new MageInt(3); // Whenever Momentum Rumbler attacks, if it doesn't have first strike, put a first strike counter on it. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new AddCountersSourceEffect( - CounterType.FIRST_STRIKE.createInstance() - ), false), MomentumRumblerCondition.FALSE, "Whenever {this} attacks, " + - "if it doesn't have first strike, put a first strike counter on it." - )); + this.addAbility(new AttacksTriggeredAbility( + new AddCountersSourceEffect(CounterType.FIRST_STRIKE.createInstance()) + .setText("put a first strike counter on it"), false + ).withInterveningIf(MomentumRumblerCondition.FALSE)); // Whenever Momentum Rumbler attacks, if it has first strike, it gains double strike until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new GainAbilitySourceEffect( - DoubleStrikeAbility.getInstance(), Duration.EndOfTurn - ), false), MomentumRumblerCondition.TRUE, "Whenever {this} attacks, " + - "if it has first strike, it gains double strike until end of turn." - )); + this.addAbility(new AttacksTriggeredAbility(new GainAbilitySourceEffect( + DoubleStrikeAbility.getInstance(), Duration.EndOfTurn + ).setText("it gains double strike until end of turn")).withInterveningIf(MomentumRumblerCondition.TRUE)); } private MomentumRumbler(final MomentumRumbler card) { @@ -77,4 +71,9 @@ enum MomentumRumblerCondition implements Condition { } return hasAbility == permanent.hasAbility(FirstStrikeAbility.getInstance(), game); } -} \ No newline at end of file + + @Override + public String toString() { + return "it " + (hasAbility ? "has" : "doesn't have") + " first strike"; + } +} diff --git a/Mage.Sets/src/mage/cards/m/Monsoon.java b/Mage.Sets/src/mage/cards/m/Monsoon.java index 809f56f15f3..d13893597fd 100644 --- a/Mage.Sets/src/mage/cards/m/Monsoon.java +++ b/Mage.Sets/src/mage/cards/m/Monsoon.java @@ -1,19 +1,17 @@ package mage.cards.m; import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; -import mage.abilities.common.OnEventTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; +import mage.constants.TargetController; import mage.filter.FilterPermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; @@ -28,8 +26,9 @@ public final class Monsoon extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}{G}"); // At the beginning of each player's end step, tap all untapped Islands that player controls and Monsoon deals X damage to the player, where X is the number of Islands tapped this way. - TriggeredAbility ability = new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of each player's end step", true, new MonsoonEffect()); - this.addAbility(ability); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.EACH_PLAYER, new MonsoonEffect(), false + )); } private Monsoon(final Monsoon card) { diff --git a/Mage.Sets/src/mage/cards/m/MonsterManual.java b/Mage.Sets/src/mage/cards/m/MonsterManual.java index a1a17bff4b1..783ccd5af5f 100644 --- a/Mage.Sets/src/mage/cards/m/MonsterManual.java +++ b/Mage.Sets/src/mage/cards/m/MonsterManual.java @@ -84,7 +84,7 @@ class ZoologicalStudyEffect extends OneShotEffect { break; default: TargetCard target = new TargetCard(Zone.ALL, StaticFilters.FILTER_CARD_CREATURE); - player.choose(outcome, cards, target, source, game); + player.choose(Outcome.PutCardInPlay, cards, target, source, game); card = cards.get(target.getFirstTarget(), game); } player.moveCards(card, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/m/MonumentToPerfection.java b/Mage.Sets/src/mage/cards/m/MonumentToPerfection.java index 45371e91954..deddca2a48d 100644 --- a/Mage.Sets/src/mage/cards/m/MonumentToPerfection.java +++ b/Mage.Sets/src/mage/cards/m/MonumentToPerfection.java @@ -56,7 +56,6 @@ public final class MonumentToPerfection extends CardImpl { // {3}: Monument to Perfection becomes a 9/9 Phyrexian Construct artifact creature, loses all abilities, and gains indestructible and toxic 9. Activate only if there are nine or more lands with different names among the basic, Sphere, and Locus lands you control. this.addAbility(new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new CreatureToken( 9, 9, "9/9 Phyrexian Construct artifact creature, " + "loses all abilities, and gains indestructible and toxic 9", SubType.PHYREXIAN, SubType.CONSTRUCT diff --git a/Mage.Sets/src/mage/cards/m/MoonlightHunt.java b/Mage.Sets/src/mage/cards/m/MoonlightHunt.java index 43afb96001b..941a51b1a72 100644 --- a/Mage.Sets/src/mage/cards/m/MoonlightHunt.java +++ b/Mage.Sets/src/mage/cards/m/MoonlightHunt.java @@ -13,10 +13,13 @@ import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author LevelX2 */ @@ -27,7 +30,7 @@ public final class MoonlightHunt extends CardImpl { // Choose target creature you don't control. Each creature you control that's a Wolf or Werewolf deals damage equal to its power to that creature. this.getSpellAbility().addEffect(new MoonlightHuntEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); } private MoonlightHunt(final MoonlightHunt card) { diff --git a/Mage.Sets/src/mage/cards/m/MoonlitScavengers.java b/Mage.Sets/src/mage/cards/m/MoonlitScavengers.java index 1fe3f432ba7..d7419a1fa3b 100644 --- a/Mage.Sets/src/mage/cards/m/MoonlitScavengers.java +++ b/Mage.Sets/src/mage/cards/m/MoonlitScavengers.java @@ -5,14 +5,11 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.TargetController; -import mage.filter.FilterPermanent; import mage.filter.common.FilterArtifactOrEnchantmentPermanent; import mage.target.common.TargetOpponentsCreaturePermanent; @@ -23,13 +20,9 @@ import java.util.UUID; */ public final class MoonlitScavengers extends CardImpl { - private static final FilterPermanent filter = new FilterArtifactOrEnchantmentPermanent(); - - static { - filter.add(TargetController.YOU.getControllerPredicate()); - } - - private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterArtifactOrEnchantmentPermanent("you control an artifact or enchantment"), true + ); public MoonlitScavengers(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}"); @@ -40,11 +33,7 @@ public final class MoonlitScavengers extends CardImpl { this.toughness = new MageInt(5); // When Moonlit Scavengers enters the battlefield, if you control an artifact or enchantment, return target creature an opponent controls to its owner's hand. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()), condition, - "When {this} enters, if you control an artifact or enchantment, " + - "return target creature an opponent controls to its owner's hand." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()).withInterveningIf(condition); ability.addTarget(new TargetOpponentsCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MoonringIsland.java b/Mage.Sets/src/mage/cards/m/MoonringIsland.java index 2af09f8d935..f3f8e983da0 100644 --- a/Mage.Sets/src/mage/cards/m/MoonringIsland.java +++ b/Mage.Sets/src/mage/cards/m/MoonringIsland.java @@ -1,28 +1,27 @@ - package mage.cards.m; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.LookLibraryTopCardTargetPlayerEffect; import mage.abilities.mana.BlueManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; -import mage.constants.Zone; +import mage.constants.SubType; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class MoonringIsland extends CardImpl { @@ -33,8 +32,10 @@ public final class MoonringIsland extends CardImpl { filter.add(new ColorPredicate(ObjectColor.BLUE)); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); + public MoonringIsland(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); this.subtype.add(SubType.ISLAND); // ({tap}: Add {U}.) @@ -44,14 +45,12 @@ public final class MoonringIsland extends CardImpl { this.addAbility(new EntersBattlefieldTappedAbility()); // {U}, {tap}: Look at the top card of target player's library. Activate this ability only if you control two or more blue permanents. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new LookLibraryTopCardTargetPlayerEffect(), - new ManaCostsImpl<>("{U}"), - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1)); + Ability ability = new ActivateIfConditionActivatedAbility( + new LookLibraryTopCardTargetPlayerEffect(), new ManaCostsImpl<>("{U}"), condition + ); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetPlayer()); this.addAbility(ability); - } private MoonringIsland(final MoonringIsland card) { diff --git a/Mage.Sets/src/mage/cards/m/MoorlandDrifter.java b/Mage.Sets/src/mage/cards/m/MoorlandDrifter.java index 6210d3e77cb..90a8de5c777 100644 --- a/Mage.Sets/src/mage/cards/m/MoorlandDrifter.java +++ b/Mage.Sets/src/mage/cards/m/MoorlandDrifter.java @@ -11,6 +11,7 @@ import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; @@ -26,8 +27,8 @@ public final class MoorlandDrifter extends CardImpl { this.toughness = new MageInt(2); // Delirium — Moorland Drifter has flying as long as there are four or more card types among cards in your graveyard. - ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance()), DeliriumCondition.instance, "Delirium — Moorland Drifter has flying as long as there are four or more card types among cards in your graveyard."); - this.addAbility(new SimpleStaticAbility(effect).addHint(CardTypesInGraveyardCount.YOU.getHint())); + ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance()), DeliriumCondition.instance, "{this} has flying as long as there are four or more card types among cards in your graveyard."); + this.addAbility(new SimpleStaticAbility(effect).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); } private MoorlandDrifter(final MoorlandDrifter card) { diff --git a/Mage.Sets/src/mage/cards/m/MoraugFuryOfAkoum.java b/Mage.Sets/src/mage/cards/m/MoraugFuryOfAkoum.java index 3843f45540f..addd453c276 100644 --- a/Mage.Sets/src/mage/cards/m/MoraugFuryOfAkoum.java +++ b/Mage.Sets/src/mage/cards/m/MoraugFuryOfAkoum.java @@ -1,13 +1,11 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.LandfallAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.IsMainPhaseCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.UntapAllControllerEffect; @@ -22,6 +20,8 @@ import mage.game.turn.TurnMod; import mage.watchers.Watcher; import mage.watchers.common.AttackedThisTurnWatcher; +import java.util.UUID; + /** * @author TheElk801 */ @@ -40,12 +40,7 @@ public final class MoraugFuryOfAkoum extends CardImpl { this.addAbility(new SimpleStaticAbility(new MoraugFuryOfAkoumBoostEffect())); // Landfall — Whenever a land you control enters, if it's your main phase, there's an additional combat phase after this phase. At the beginning of that combat, untap all creatures you control. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new LandfallAbility(new MoraugFuryOfAkoumCombatEffect()), IsMainPhaseCondition.YOUR, - "Landfall — Whenever a land you control enters, " + - "if it's your main phase, there's an additional combat phase after this phase. " + - "At the beginning of that combat, untap all creatures you control." - ), new MoraugFuryOfAkoumWatcher()); + this.addAbility(new LandfallAbility(new MoraugFuryOfAkoumCombatEffect()).withInterveningIf(IsMainPhaseCondition.YOUR), new MoraugFuryOfAkoumWatcher()); } private MoraugFuryOfAkoum(final MoraugFuryOfAkoum card) { @@ -91,6 +86,7 @@ class MoraugFuryOfAkoumCombatEffect extends OneShotEffect { MoraugFuryOfAkoumCombatEffect() { super(Outcome.Benefit); + staticText = "there's an additional combat phase after this phase. At the beginning of that combat, untap all creatures you control"; } private MoraugFuryOfAkoumCombatEffect(final MoraugFuryOfAkoumCombatEffect effect) { @@ -189,4 +185,4 @@ class MoraugFuryOfAkoumWatcher extends Watcher { } } } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/m/MorgueBurst.java b/Mage.Sets/src/mage/cards/m/MorgueBurst.java index 4a0d9e2870e..cfac441a154 100644 --- a/Mage.Sets/src/mage/cards/m/MorgueBurst.java +++ b/Mage.Sets/src/mage/cards/m/MorgueBurst.java @@ -45,7 +45,7 @@ class MorgueBurstEffect extends OneShotEffect { MorgueBurstEffect() { super(Outcome.ReturnToHand); - this.staticText = "Return target creature card from your graveyard to your hand. Morgue Burst deals damage to any target equal to the power of the card returned this way"; + this.staticText = "Return target creature card from your graveyard to your hand. {this} deals damage to any target equal to the power of the card returned this way"; } private MorgueBurstEffect(final MorgueBurstEffect effect) { diff --git a/Mage.Sets/src/mage/cards/m/MorkrutBanshee.java b/Mage.Sets/src/mage/cards/m/MorkrutBanshee.java index 2256df34c35..68a34548722 100644 --- a/Mage.Sets/src/mage/cards/m/MorkrutBanshee.java +++ b/Mage.Sets/src/mage/cards/m/MorkrutBanshee.java @@ -1,30 +1,27 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.MorbidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.hint.common.MorbidHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * @author nantuko */ public final class MorkrutBanshee extends CardImpl { - private static final String staticText = "Morbid — When {this} enters, if a creature died this turn, target creature gets -4/-4 until end of turn."; - public MorkrutBanshee(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); this.subtype.add(SubType.SPIRIT); this.color.setBlack(true); @@ -32,10 +29,10 @@ public final class MorkrutBanshee extends CardImpl { this.toughness = new MageInt(4); // Morbid — When Morkut Banshee enters the battlefield, if a creature died this turn, target creature gets -4/-4 until end of turn. - TriggeredAbility triggeredAbility = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-4, -4, Duration.EndOfTurn)); - TriggeredAbility ability = new ConditionalInterveningIfTriggeredAbility(triggeredAbility, MorbidCondition.instance, staticText); + Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-4, -4)) + .withInterveningIf(MorbidCondition.instance); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability.addHint(MorbidHint.instance)); + this.addAbility(ability.setAbilityWord(AbilityWord.MORBID).addHint(MorbidHint.instance)); } private MorkrutBanshee(final MorkrutBanshee card) { diff --git a/Mage.Sets/src/mage/cards/m/MortalCombat.java b/Mage.Sets/src/mage/cards/m/MortalCombat.java index cb72ca3dfe1..be419afcc78 100644 --- a/Mage.Sets/src/mage/cards/m/MortalCombat.java +++ b/Mage.Sets/src/mage/cards/m/MortalCombat.java @@ -1,32 +1,28 @@ package mage.cards.m; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.CardsInControllerGraveyardCondition; import mage.abilities.effects.common.WinGameSourceControllerEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; + +import java.util.UUID; /** - * * @author daagar */ public final class MortalCombat extends CardImpl { + private static final Condition condition = new CardsInControllerGraveyardCondition(20, StaticFilters.FILTER_CARD_CREATURES); + public MortalCombat(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); // At the beginning of your upkeep, if twenty or more creature cards are in your graveyard, you win the game. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect()), - new TwentyGraveyardCreatureCondition(), - "At the beginning of your upkeep, if twenty or more creature cards are in your graveyard, you win the game.")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect()).withInterveningIf(condition)); } private MortalCombat(final MortalCombat card) { @@ -38,12 +34,3 @@ public final class MortalCombat extends CardImpl { return new MortalCombat(this); } } - -class TwentyGraveyardCreatureCondition implements Condition { - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - return player != null && player.getGraveyard().count(StaticFilters.FILTER_CARD_CREATURE, game) >= 20; - } -} diff --git a/Mage.Sets/src/mage/cards/m/MossPitSkeleton.java b/Mage.Sets/src/mage/cards/m/MossPitSkeleton.java index c839f412218..089ee27b195 100644 --- a/Mage.Sets/src/mage/cards/m/MossPitSkeleton.java +++ b/Mage.Sets/src/mage/cards/m/MossPitSkeleton.java @@ -59,7 +59,7 @@ public final class MossPitSkeleton extends CardImpl { class MossPitSkeletonTriggeredAbility extends TriggeredAbilityImpl { MossPitSkeletonTriggeredAbility() { - super(Zone.GRAVEYARD, new PutOnLibrarySourceEffect(true).setText("put {this} on top of your library"), true); + super(Zone.GRAVEYARD, new PutOnLibrarySourceEffect(true).setText("put this card on top of your library"), true); this.withInterveningIf(SourceInGraveyardCondition.instance); setTriggerPhrase("Whenever one or more +1/+1 counters are put on a creature you control, "); } diff --git a/Mage.Sets/src/mage/cards/m/MossbridgeTroll.java b/Mage.Sets/src/mage/cards/m/MossbridgeTroll.java index cd63deca655..ac1e44e7b7a 100644 --- a/Mage.Sets/src/mage/cards/m/MossbridgeTroll.java +++ b/Mage.Sets/src/mage/cards/m/MossbridgeTroll.java @@ -18,7 +18,7 @@ import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; import java.util.UUID; @@ -108,7 +108,7 @@ class MossbridgeTrollCost extends CostImpl { } public MossbridgeTrollCost() { - this.addTarget(new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true)); + this.addTarget(new TargetControlledPermanent(0, Integer.MAX_VALUE, filter, true)); this.text = "tap any number of untapped creatures you control other than {this} with total power 10 or greater"; } diff --git a/Mage.Sets/src/mage/cards/m/Mosstodon.java b/Mage.Sets/src/mage/cards/m/Mosstodon.java index 96b104ab4e8..f2f8295d7a9 100644 --- a/Mage.Sets/src/mage/cards/m/Mosstodon.java +++ b/Mage.Sets/src/mage/cards/m/Mosstodon.java @@ -16,6 +16,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -41,7 +42,7 @@ public final class Mosstodon extends CardImpl { SimpleActivatedAbility ability = new SimpleActivatedAbility( new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{1}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/Mournwillow.java b/Mage.Sets/src/mage/cards/m/Mournwillow.java index 993ede54731..e6bdde9bae8 100644 --- a/Mage.Sets/src/mage/cards/m/Mournwillow.java +++ b/Mage.Sets/src/mage/cards/m/Mournwillow.java @@ -4,12 +4,12 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.RestrictionEffect; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; @@ -35,13 +35,10 @@ public final class Mournwillow extends CardImpl { // Delirium — When Mournwillow enters the battlefield, if there are four or more card types among cards in your graveyard, // creatures with power 2 or less can't block this turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new MournwillowEffect(), false), - DeliriumCondition.instance, - "Delirium — When {this} enters, if there are four or more card types among cards in your graveyard, " - + "creatures with power 2 or less can't block this turn."); - ability.addHint(CardTypesInGraveyardCount.YOU.getHint()); - this.addAbility(ability); + this.addAbility(new EntersBattlefieldTriggeredAbility(new MournwillowEffect()) + .withInterveningIf(DeliriumCondition.instance) + .setAbilityWord(AbilityWord.DELIRIUM) + .addHint(CardTypesInGraveyardCount.YOU.getHint())); } private Mournwillow(final Mournwillow card) { diff --git a/Mage.Sets/src/mage/cards/m/MrHousePresidentAndCEO.java b/Mage.Sets/src/mage/cards/m/MrHousePresidentAndCEO.java index 5b537b0c5c8..f7840701dcd 100644 --- a/Mage.Sets/src/mage/cards/m/MrHousePresidentAndCEO.java +++ b/Mage.Sets/src/mage/cards/m/MrHousePresidentAndCEO.java @@ -14,7 +14,7 @@ import mage.cards.CardSetInfo; import mage.game.Game; import mage.game.events.DieRolledEvent; import mage.game.events.GameEvent; -import mage.game.permanent.token.RobotToken; +import mage.game.permanent.token.Robot33Token; import mage.game.permanent.token.Token; import mage.game.permanent.token.TreasureToken; import mage.players.Player; @@ -116,7 +116,7 @@ class MrHousePresidentAndCEOTokenEffect extends OneShotEffect { int amount = (Integer) getValue("rolled"); if (amount >= 4) { - Token robotToken = new RobotToken(); + Token robotToken = new Robot33Token(); robotToken.putOntoBattlefield(1, game, source); } if (amount >= 6) { diff --git a/Mage.Sets/src/mage/cards/m/MsBumbleflower.java b/Mage.Sets/src/mage/cards/m/MsBumbleflower.java index ecf246926ce..59bcd8bb050 100644 --- a/Mage.Sets/src/mage/cards/m/MsBumbleflower.java +++ b/Mage.Sets/src/mage/cards/m/MsBumbleflower.java @@ -1,36 +1,37 @@ package mage.cards.m; -import java.util.*; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.DrawCardTargetEffect; import mage.abilities.effects.common.IfAbilityHasResolvedXTimesEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.VigilanceAbility; -import mage.constants.*; -import mage.counters.CounterType; -import mage.filter.StaticFilters; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponent; import mage.target.targetpointer.FirstTargetPointer; import mage.target.targetpointer.SecondTargetPointer; import mage.watchers.common.AbilityResolvedWatcher; +import java.util.UUID; + /** - * * @author DreamWaker */ public final class MsBumbleflower extends CardImpl { public MsBumbleflower(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[] { CardType.CREATURE }, "{1}{G}{W}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{W}{U}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.RABBIT); @@ -43,18 +44,18 @@ public final class MsBumbleflower extends CardImpl { // Whenever you cast a spell, target opponent draws a card. Put a +1/+1 counter on target creature. It gains // flying until end of turn. If this is the second time this ability has resolved this turn, you draw two cards. - Effect draw = new DrawCardTargetEffect(1); - draw.setTargetPointer(new FirstTargetPointer()); - Effect counters = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); - counters.setTargetPointer(new SecondTargetPointer()); - Effect flying = new GainAbilityTargetEffect(FlyingAbility.getInstance()).setText("It gains flying until end of turn."); - flying.setTargetPointer(new SecondTargetPointer()); - Ability ability = new SpellCastControllerTriggeredAbility(draw,StaticFilters.FILTER_SPELL_A, false); + Ability ability = new SpellCastControllerTriggeredAbility( + new DrawCardTargetEffect(1), StaticFilters.FILTER_SPELL_A, false + ); ability.addTarget(new TargetOpponent()); - ability.addEffect(counters); - ability.addEffect(flying); - ability.addTarget(new TargetCreaturePermanent(1)); - ability.addEffect(new IfAbilityHasResolvedXTimesEffect(2, new DrawCardSourceControllerEffect(2, true))); + ability.addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance()) + .setTargetPointer(new SecondTargetPointer())); + ability.addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance()) + .setText("It gains flying until end of turn.").setTargetPointer(new SecondTargetPointer())); + ability.addTarget(new TargetCreaturePermanent()); + ability.addEffect(new IfAbilityHasResolvedXTimesEffect( + 2, new DrawCardSourceControllerEffect(2, true + ))); this.addAbility(ability, new AbilityResolvedWatcher()); } diff --git a/Mage.Sets/src/mage/cards/m/MtendaGriffin.java b/Mage.Sets/src/mage/cards/m/MtendaGriffin.java index d79901ea18b..1813bd7cea5 100644 --- a/Mage.Sets/src/mage/cards/m/MtendaGriffin.java +++ b/Mage.Sets/src/mage/cards/m/MtendaGriffin.java @@ -1,59 +1,51 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.effects.common.ReturnToHandSourceEffect; -import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.PhaseStep; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterCard; -import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author fireshoes */ public final class MtendaGriffin extends CardImpl { - + private static final FilterCard filter = new FilterCard("Griffin card from your graveyard"); static { filter.add(SubType.GRIFFIN.getPredicate()); -} + } public MtendaGriffin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.subtype.add(SubType.GRIFFIN); this.power = new MageInt(2); this.toughness = new MageInt(2); // Flying this.addAbility(FlyingAbility.getInstance()); - + // {W}, {tap}: Return Mtenda Griffin to its owner's hand and return target Griffin card from your graveyard to your hand. Activate this ability only during your upkeep. - Effect effect = new ReturnToHandSourceEffect(true); - effect.setText("Return Mtenda Griffin to its owner's hand"); - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - effect, new ManaCostsImpl<>("{W}"), new IsStepCondition(PhaseStep.UPKEEP)); - effect = new ReturnToHandTargetEffect(); + Ability ability = new ActivateIfConditionActivatedAbility( + new ReturnToHandSourceEffect(true), + new ManaCostsImpl<>("{W}"), IsStepCondition.getMyUpkeep() + ); ability.addCost(new TapSourceCost()); - effect.setText("and return target Griffin card from your graveyard to your hand"); - ability.addEffect(effect); - Target target = new TargetCardInYourGraveyard(filter); - ability.addTarget(target); + ability.addEffect(new ReturnFromGraveyardToHandTargetEffect().concatBy("and")); + ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/Mudslide.java b/Mage.Sets/src/mage/cards/m/Mudslide.java index 90e7097ea6d..6429d26d481 100644 --- a/Mage.Sets/src/mage/cards/m/Mudslide.java +++ b/Mage.Sets/src/mage/cards/m/Mudslide.java @@ -1,15 +1,18 @@ package mage.cards.m; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.Cost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DontUntapInControllersUntapStepAllEffect; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; @@ -19,7 +22,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; import mage.util.ManaUtil; import java.util.UUID; @@ -86,7 +89,8 @@ class MudslideEffect extends OneShotEffect { if (player != null && sourcePermanent != null) { int countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).size(); while (player.canRespond() && countBattlefield > 0 && player.chooseUse(Outcome.Benefit, "Pay {2} and untap a tapped creature without flying under your control?", source, game)) { - Target tappedCreatureTarget = new TargetControlledCreaturePermanent(1, 1, filter, true); + Target tappedCreatureTarget = new TargetControlledPermanent(filter); + tappedCreatureTarget.withNotTarget(true); if (player.choose(Outcome.Untap, tappedCreatureTarget, source, game)) { Cost cost = ManaUtil.createManaCost(2, false); Permanent tappedCreature = game.getPermanent(tappedCreatureTarget.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/m/MulDayaChannelers.java b/Mage.Sets/src/mage/cards/m/MulDayaChannelers.java index 2ad815a2701..ae8ee997ce0 100644 --- a/Mage.Sets/src/mage/cards/m/MulDayaChannelers.java +++ b/Mage.Sets/src/mage/cards/m/MulDayaChannelers.java @@ -1,24 +1,25 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.TopLibraryCardTypeCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.effects.mana.AddManaOfAnyColorEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.continuous.PlayWithTheTopCardRevealedEffect; +import mage.abilities.effects.mana.AddManaOfAnyColorEffect; import mage.abilities.mana.SimpleManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; +import java.util.UUID; + /** * * @author jeffwadsworth @@ -48,7 +49,7 @@ public final class MulDayaChannelers extends CardImpl { SimpleManaAbility manaAbility = new SimpleManaAbility(Zone.BATTLEFIELD, new AddManaOfAnyColorEffect(2), new TapSourceCost()); effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(manaAbility, Duration.WhileOnBattlefield), new TopLibraryCardTypeCondition(CardType.LAND), - "As long as the top card of your library is a land card, Mul Daya Channelers has \"{T}: Add two mana of any one color.\""); + "As long as the top card of your library is a land card, {this} has \"{T}: Add two mana of any one color.\""); this.addAbility(new SimpleStaticAbility(effect)); } diff --git a/Mage.Sets/src/mage/cards/m/MurasaSproutling.java b/Mage.Sets/src/mage/cards/m/MurasaSproutling.java index 09beac04b30..cbad132fbe6 100644 --- a/Mage.Sets/src/mage/cards/m/MurasaSproutling.java +++ b/Mage.Sets/src/mage/cards/m/MurasaSproutling.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; @@ -40,11 +39,7 @@ public final class MurasaSproutling extends CardImpl { this.addAbility(new KickerAbility("{1}{G}")); // When Murasa Sproutling enters the battlefield, if it was kicked, return target card with a kicker ability from your graveyard to your hand. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()), - KickedCondition.ONCE, "When {this} enters, if it was kicked, " + - "return target card with a kicker ability from your graveyard to your hand." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()).withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MurderousBetrayal.java b/Mage.Sets/src/mage/cards/m/MurderousBetrayal.java index 4c6f66c45a0..21d3bacf9e3 100644 --- a/Mage.Sets/src/mage/cards/m/MurderousBetrayal.java +++ b/Mage.Sets/src/mage/cards/m/MurderousBetrayal.java @@ -15,9 +15,12 @@ import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.util.CardUtil; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author choiseul11 @@ -31,7 +34,7 @@ public final class MurderousBetrayal extends CardImpl { Effect effect = new DestroyTargetEffect(true); Ability ability = new SimpleActivatedAbility(effect, new MurderousBetrayalCost()); ability.addCost(new ManaCostsImpl<>("{B}{B}")); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + ability.addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MurderousCompulsion.java b/Mage.Sets/src/mage/cards/m/MurderousCompulsion.java index 0ceae7d2435..e410c72f58c 100644 --- a/Mage.Sets/src/mage/cards/m/MurderousCompulsion.java +++ b/Mage.Sets/src/mage/cards/m/MurderousCompulsion.java @@ -10,6 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class MurderousCompulsion extends CardImpl { // Destroy target tapped creature. getSpellAbility().addEffect(new DestroyTargetEffect()); - getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + getSpellAbility().addTarget(new TargetPermanent(filter)); // Madness {1}{B} (If you discard card, discard it into exile. When you do, cast it for its madness cost or put it into your graveyard.) this.addAbility(new MadnessAbility(new ManaCostsImpl<>("{1}{B}"))); diff --git a/Mage.Sets/src/mage/cards/m/MurderousSpoils.java b/Mage.Sets/src/mage/cards/m/MurderousSpoils.java index e400860f079..50255a1a2a0 100644 --- a/Mage.Sets/src/mage/cards/m/MurderousSpoils.java +++ b/Mage.Sets/src/mage/cards/m/MurderousSpoils.java @@ -16,9 +16,12 @@ import mage.constants.Outcome; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author wetterlicht @@ -29,7 +32,7 @@ public final class MurderousSpoils extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{5}{B}"); // Destroy target nonblack creature. It can't be regenerated. You gain control of all Equipment that was attached to it. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.getSpellAbility().addEffect(new MurderousSpoilsEffect()); } diff --git a/Mage.Sets/src/mage/cards/m/MuseVessel.java b/Mage.Sets/src/mage/cards/m/MuseVessel.java index 04a1518e5e6..2d7be46fbbd 100644 --- a/Mage.Sets/src/mage/cards/m/MuseVessel.java +++ b/Mage.Sets/src/mage/cards/m/MuseVessel.java @@ -6,24 +6,26 @@ import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.OneShotNonTargetEffect; +import mage.abilities.effects.common.AddContinuousEffectToGame; +import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.CardsImpl; -import mage.constants.*; -import mage.filter.FilterCard; -import mage.game.ExileZone; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetCardInExile; import mage.target.common.TargetCardInHand; +import mage.target.targetadjustment.TargetAdjuster; import mage.util.CardUtil; -import java.util.HashSet; -import java.util.Set; import java.util.UUID; /** @@ -40,10 +42,12 @@ public final class MuseVessel extends CardImpl { tapAbility.addCost(new ManaCostsImpl<>("{3}")); tapAbility.addTarget(new TargetPlayer()); this.addAbility(tapAbility); - // {1}: Choose a card exiled with Muse Vessel. You may play that card this turn. - SimpleActivatedAbility playAbility = new SimpleActivatedAbility(new MuseVesselMayPlayExiledEffect(), new ManaCostsImpl<>("{1}")); - playAbility.addTarget(new TargetCardInMuseVesselExile()); + SimpleActivatedAbility playAbility = new SimpleActivatedAbility(new OneShotNonTargetEffect( + new AddContinuousEffectToGame(new PlayFromNotOwnHandZoneTargetEffect(Zone.EXILED, Duration.EndOfTurn)) + .setText("Choose a card exiled with {this}. You may play that card this turn."), + new TargetCardInExile(StaticFilters.FILTER_CARD), MuseVesselAdjuster.instance + ), new ManaCostsImpl<>("{1}")); this.addAbility(playAbility); } @@ -80,8 +84,8 @@ class MuseVesselExileEffect extends OneShotEffect { } TargetCardInHand target = new TargetCardInHand(); if (target.canChoose(player.getId(), source, game) - && target.chooseTarget(Outcome.Exile, player.getId(), source, game)) { - UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); + && target.choose(Outcome.Exile, player.getId(), source, game)) { + UUID exileId = CardUtil.getExileZoneId(game, source); return player.moveCardsToExile(new CardsImpl(target.getTargets()).getCards(game), source, game, true, exileId, sourceObject.getIdName()); } return false; @@ -94,90 +98,14 @@ class MuseVesselExileEffect extends OneShotEffect { } -class MuseVesselMayPlayExiledEffect extends AsThoughEffectImpl { - - MuseVesselMayPlayExiledEffect() { - super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); - this.staticText = "Choose a card exiled with {this}. You may play that card this turn"; - } - - private MuseVesselMayPlayExiledEffect(final MuseVesselMayPlayExiledEffect effect) { - super(effect); - } +enum MuseVesselAdjuster implements TargetAdjuster { + instance; @Override - public MuseVesselMayPlayExiledEffect copy() { - return new MuseVesselMayPlayExiledEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - return affectedControllerId.equals(source.getControllerId()) - && getTargetPointer().getTargets(game, source).contains(objectId); - } - -} - -// TODO: cleanup. there should be no need for custom Target there. -class TargetCardInMuseVesselExile extends TargetCardInExile { - - public TargetCardInMuseVesselExile() { - super(new FilterCard("card exiled with Muse Vessel")); - } - - private TargetCardInMuseVesselExile(final TargetCardInMuseVesselExile target) { - super(target); - } - - @Override - public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { - Set possibleTargets = new HashSet<>(); - Card sourceCard = game.getCard(source.getSourceId()); - if (sourceCard != null) { - UUID exileId = CardUtil.getCardExileZoneId(game, source.getSourceId()); - ExileZone exile = game.getExile().getExileZone(exileId); - if (exile != null && !exile.isEmpty()) { - possibleTargets.addAll(exile); - } - } - return possibleTargets; - } - - @Override - public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { - Card sourceCard = game.getCard(source.getSourceId()); - if (sourceCard != null) { - UUID exileId = CardUtil.getCardExileZoneId(game, source.getSourceId()); - ExileZone exile = game.getExile().getExileZone(exileId); - return exile != null && !exile.isEmpty(); - } - return false; - } - - @Override - public boolean canTarget(UUID id, Ability source, Game game) { - Card card = game.getCard(id); - if (card != null && game.getState().getZone(card.getId()) == Zone.EXILED) { - ExileZone exile = null; - Card sourceCard = game.getCard(source.getSourceId()); - if (sourceCard != null) { - UUID exileId = CardUtil.getCardExileZoneId(game, source); - exile = game.getExile().getExileZone(exileId); - } - if (exile != null && exile.contains(id)) { - return filter.match(card, source.getControllerId(), source, game); - } - } - return false; - } - - @Override - public TargetCardInMuseVesselExile copy() { - return new TargetCardInMuseVesselExile(this); + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget( + new TargetCardInExile(StaticFilters.FILTER_CARD, CardUtil.getCardExileZoneId(game, ability.getSourceId())) + .withNotTarget(true)); } } diff --git a/Mage.Sets/src/mage/cards/m/MutantsPrey.java b/Mage.Sets/src/mage/cards/m/MutantsPrey.java index bad72bb85fa..a05b6763b25 100644 --- a/Mage.Sets/src/mage/cards/m/MutantsPrey.java +++ b/Mage.Sets/src/mage/cards/m/MutantsPrey.java @@ -1,15 +1,13 @@ - - package mage.cards.m; -import java.util.UUID; import mage.abilities.effects.common.FightTargetsEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** * @author LevelX2 @@ -17,12 +15,12 @@ import mage.target.common.TargetCreaturePermanent; public final class MutantsPrey extends CardImpl { public MutantsPrey(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}"); // Target creature you control with a +1/+1 counter on it fights target creature an opponent controls. this.getSpellAbility().addEffect(new FightTargetsEffect()); - this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_CONTROLLED_CREATURE_P1P1)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_CREATURE_P1P1)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); } private MutantsPrey(final MutantsPrey card) { diff --git a/Mage.Sets/src/mage/cards/m/Mutiny.java b/Mage.Sets/src/mage/cards/m/Mutiny.java index 23ab622d0ed..40caae27b00 100644 --- a/Mage.Sets/src/mage/cards/m/Mutiny.java +++ b/Mage.Sets/src/mage/cards/m/Mutiny.java @@ -15,6 +15,7 @@ import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -30,8 +31,7 @@ public final class Mutiny extends CardImpl { // Target creature an opponent controls deals damage equal to its power to another target creature that player controls. this.getSpellAbility().addEffect(new MutinyEffect()); this.getSpellAbility().addTarget(new MutinyFirstTarget(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("another target creature that player controls"))); - + this.getSpellAbility().addTarget(new TargetPermanent(new FilterCreaturePermanent("another target creature that player controls"))); } private Mutiny(final Mutiny card) { @@ -75,7 +75,7 @@ class MutinyEffect extends OneShotEffect { } -class MutinyFirstTarget extends TargetCreaturePermanent { +class MutinyFirstTarget extends TargetPermanent { public MutinyFirstTarget(FilterCreaturePermanent filter) { super(1, 1, filter, false); diff --git a/Mage.Sets/src/mage/cards/m/MycoidShepherd.java b/Mage.Sets/src/mage/cards/m/MycoidShepherd.java index 51f3d1f815b..b996d460869 100644 --- a/Mage.Sets/src/mage/cards/m/MycoidShepherd.java +++ b/Mage.Sets/src/mage/cards/m/MycoidShepherd.java @@ -1,40 +1,42 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; -import mage.MageObject; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.DiesThisOrAnotherTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.events.ZoneChangeEvent; -import mage.game.permanent.Permanent; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.PowerPredicate; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class MycoidShepherd extends CardImpl { + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("another creature you control with power 5 or greater"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 4)); + } public MycoidShepherd(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{G}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{G}{W}"); this.subtype.add(SubType.FUNGUS); - - this.power = new MageInt(5); this.toughness = new MageInt(4); // Whenever Mycoid Shepherd or another creature you control with power 5 or greater dies, you may gain 5 life. - this.addAbility(new MycoidShepherdTriggeredAbility()); - + this.addAbility(new DiesThisOrAnotherTriggeredAbility(new GainLifeEffect(5), true, filter)); + } private MycoidShepherd(final MycoidShepherd card) { @@ -46,55 +48,3 @@ public final class MycoidShepherd extends CardImpl { return new MycoidShepherd(this); } } - -class MycoidShepherdTriggeredAbility extends TriggeredAbilityImpl { - - public MycoidShepherdTriggeredAbility() { - super(Zone.BATTLEFIELD, new GainLifeEffect(5), true); - setLeavesTheBattlefieldTrigger(true); - } - - private MycoidShepherdTriggeredAbility(final MycoidShepherdTriggeredAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ZONE_CHANGE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - MageObject lastKnown = game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); - if (lastKnown == null) { - return false; - } - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - Permanent permanent = zEvent.getTarget(); - if (permanent == null) { - return false; - } - if (super.getSourceId().equals(event.getTargetId()) - || permanent.getPower().getValue() > 4 - && permanent.isControlledBy(controllerId)) { - Zone after = game.getState().getZone(event.getTargetId()); - return after != null && Zone.GRAVEYARD.match(after); - } - return false; - } - - @Override - public String getRule() { - return "Whenever Mycoid Shepherd or another creature you control with power 5 or greater dies, you may gain 5 life."; - } - - @Override - public MycoidShepherdTriggeredAbility copy() { - return new MycoidShepherdTriggeredAbility(this); - } - - @Override - public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) { - return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game); - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/MyrServitor.java b/Mage.Sets/src/mage/cards/m/MyrServitor.java index a2024a5a332..bbd9cb03402 100644 --- a/Mage.Sets/src/mage/cards/m/MyrServitor.java +++ b/Mage.Sets/src/mage/cards/m/MyrServitor.java @@ -1,44 +1,38 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.common.SourceOnBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.NamePredicate; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class MyrServitor extends CardImpl { public MyrServitor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{1}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}"); this.subtype.add(SubType.MYR); this.power = new MageInt(1); this.toughness = new MageInt(1); // At the beginning of your upkeep, if Myr Servitor is on the battlefield, each player returns all cards named Myr Servitor from their graveyard to the battlefield. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new MyrServitorReturnEffect()), - SourceOnBattlefieldCondition.instance, - "At the beginning of your upkeep, if {this} is on the battlefield, each player returns all cards named Myr Servitor from their graveyard to the battlefield" - )); - + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new MyrServitorReturnEffect()) + .withInterveningIf(SourceOnBattlefieldCondition.instance)); } private MyrServitor(final MyrServitor card) { @@ -61,7 +55,7 @@ class MyrServitorReturnEffect extends OneShotEffect { public MyrServitorReturnEffect() { super(Outcome.PutCardInPlay); - this.staticText = "if {this} is on the battlefield, each player returns all cards named Myr Servitor from their graveyard to the battlefield"; + this.staticText = "each player returns all cards named Myr Servitor from their graveyard to the battlefield"; } private MyrServitorReturnEffect(final MyrServitorReturnEffect effect) { @@ -75,16 +69,12 @@ class MyrServitorReturnEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - controller.moveCards(player.getGraveyard().getCards(filter, game), Zone.BATTLEFIELD, source, game); - } + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + player.moveCards(player.getGraveyard().getCards(filter, game), Zone.BATTLEFIELD, source, game); } - return true; } - return false; + return true; } } diff --git a/Mage.Sets/src/mage/cards/m/MysteriousStranger.java b/Mage.Sets/src/mage/cards/m/MysteriousStranger.java new file mode 100644 index 00000000000..21c1f5eaab8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MysteriousStranger.java @@ -0,0 +1,126 @@ +package mage.cards.m; + +import mage.ApprovingObject; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlashAbility; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterInstantOrSorceryCard; +import mage.filter.predicate.card.OwnerIdPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; +import mage.target.targetadjustment.TargetAdjuster; +import mage.target.targetpointer.EachTargetPointer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MysteriousStranger extends CardImpl { + + public MysteriousStranger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // When Mysterious Stranger enters the battlefield, for each graveyard with an instant or sorcery card in it, exile target instant or sorcery card from that graveyard. If two or more cards are exiled this way, choose one of them at random and copy it. You may cast the copy without paying its mana cost. + this.addAbility(new EntersBattlefieldTriggeredAbility(new MysteriousStrangerEffect()) + .setTargetAdjuster(MysteriousStrangerAdjuster.instance)); + } + + private MysteriousStranger(final MysteriousStranger card) { + super(card); + } + + @Override + public MysteriousStranger copy() { + return new MysteriousStranger(this); + } +} + +enum MysteriousStrangerAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + for (UUID playerId : game.getState().getPlayersInRange(ability.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player == null || player.getGraveyard().count(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, game) < 1) { + continue; + } + FilterCard filter = new FilterInstantOrSorceryCard("instant or sorcery card (owned by " + + (ability.isControlledBy(playerId) ? "you" : player.getLogName()) + ')'); + filter.add(new OwnerIdPredicate(playerId)); + ability.addTarget(new TargetCardInGraveyard(filter)); + } + } +} + +class MysteriousStrangerEffect extends OneShotEffect { + + MysteriousStrangerEffect() { + super(Outcome.Benefit); + staticText = "for each graveyard with an instant or sorcery card in it, " + + "exile target instant or sorcery card from that graveyard. " + + "If two or more cards are exiled this way, choose one of them at random and copy it. " + + "You may cast the copy without paying its mana cost"; + this.setTargetPointer(new EachTargetPointer()); + } + + private MysteriousStrangerEffect(final MysteriousStrangerEffect effect) { + super(effect); + } + + @Override + public MysteriousStrangerEffect copy() { + return new MysteriousStrangerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Cards cards = new CardsImpl(getTargetPointer().getTargets(game, source)); + cards.retainZone(Zone.GRAVEYARD, game); + if (player == null || cards.isEmpty()) { + return false; + } + player.moveCards(cards, Zone.EXILED, source, game); + cards.retainZone(Zone.EXILED, game); + if (cards.size() < 2) { + return true; + } + Card card = cards.getRandom(game); + if (card == null) { + return true; + } + Card copiedCard = game.copyCard(card, source, source.getControllerId()); + if (!player.chooseUse(Outcome.PlayForFree, "Cast a copy of " + + card.getLogName() + " without paying its mana cost?", source, game)) { + return true; + } + game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), Boolean.TRUE); + player.cast( + player.chooseAbilityForCast(copiedCard, game, true), + game, true, new ApprovingObject(source, game) + ); + game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), null); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MystifyingMaze.java b/Mage.Sets/src/mage/cards/m/MystifyingMaze.java index 6ff0835d94f..cb9104a1ba4 100644 --- a/Mage.Sets/src/mage/cards/m/MystifyingMaze.java +++ b/Mage.Sets/src/mage/cards/m/MystifyingMaze.java @@ -19,6 +19,7 @@ import mage.constants.Zone; import mage.filter.common.FilterAttackingCreature; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -44,7 +45,7 @@ public final class MystifyingMaze extends CardImpl { // {4}, {T}: Exile target attacking creature an opponent controls. At the beginning of the next end step, return it to the battlefield tapped under its owner's control. Ability ability = new SimpleActivatedAbility(new MystifyingMazeEffect(), new ManaCostsImpl<>("{4}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MythosOfIlluna.java b/Mage.Sets/src/mage/cards/m/MythosOfIlluna.java index 606f0b9ee2a..7a1c03f658f 100644 --- a/Mage.Sets/src/mage/cards/m/MythosOfIlluna.java +++ b/Mage.Sets/src/mage/cards/m/MythosOfIlluna.java @@ -5,16 +5,16 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.CompoundCondition; import mage.abilities.condition.Condition; import mage.abilities.condition.common.ManaWasSpentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.SourceMatchesFilterCondition; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.abilities.effects.common.FightTargetSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ColoredManaSymbol; import mage.constants.Outcome; import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; @@ -50,12 +50,13 @@ class MythosOfIllunaEffect extends OneShotEffect { ManaWasSpentCondition.RED, ManaWasSpentCondition.GREEN ); + private static final Condition condition2 = new SourceMatchesFilterCondition(new FilterCreaturePermanent("it's a creature")); MythosOfIllunaEffect() { super(Outcome.Benefit); staticText = "Create a token that's a copy of target permanent. " + "If {R}{G} was spent to cast this spell, instead create a token that's a copy of that permanent, " + - "except the token has \"When this permanent enters the battlefield, if it's a creature, " + + "except the token has \"When this token enters, if it's a creature, " + "it fights up to one target creature you don't control.\""; } @@ -75,15 +76,15 @@ class MythosOfIllunaEffect extends OneShotEffect { return false; } CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(source.getControllerId()); - if (condition.apply(game, source)) { - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new FightTargetSourceEffect()), - MythosOfIllunaCondition.instance, "When this permanent enters, " + - "if it's a creature, it fights up to one target creature you don't control." - ); - ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL, false)); - effect.addAdditionalAbilities(ability); + if (!condition.apply(game, source)) { + return effect.apply(game, source); } + Ability ability = new EntersBattlefieldTriggeredAbility(new FightTargetSourceEffect() + .setText("it fights up to one target creature you don't control")) + .setTriggerPhrase("When this token enters, ") + .withInterveningIf(condition2); + ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + effect.addAdditionalAbilities(ability); return effect.apply(game, source); } diff --git a/Mage.Sets/src/mage/cards/n/N1Starfighter.java b/Mage.Sets/src/mage/cards/n/N1Starfighter.java index 2d7997412ad..807950858b7 100644 --- a/Mage.Sets/src/mage/cards/n/N1Starfighter.java +++ b/Mage.Sets/src/mage/cards/n/N1Starfighter.java @@ -13,6 +13,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; @@ -37,7 +38,7 @@ public final class N1Starfighter extends CardImpl { doIfCostPaid.addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false).concatBy(", then")); Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(doIfCostPaid, false); - ability.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NahiriHeirOfTheAncients.java b/Mage.Sets/src/mage/cards/n/NahiriHeirOfTheAncients.java index a3971466c9f..e1776c59374 100644 --- a/Mage.Sets/src/mage/cards/n/NahiriHeirOfTheAncients.java +++ b/Mage.Sets/src/mage/cards/n/NahiriHeirOfTheAncients.java @@ -1,6 +1,5 @@ package mage.cards.n; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.dynamicvalue.DynamicValue; @@ -15,7 +14,7 @@ import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.KorWarriorToken; @@ -119,12 +118,7 @@ class NahiriHeirOfTheAncientsEffect extends OneShotEffect { Permanent tokenCreature = tokens.get(0); if (tokens.size() > 1) { FilterPermanent tokenFilter = new FilterPermanent("token"); - tokenFilter.add(Predicates.or( - tokens.stream() - .map(MageObject::getId) - .map(PermanentIdPredicate::new) - .collect(Collectors.toSet()) - )); + tokenFilter.add(new PermanentReferenceInCollectionPredicate(tokens, game)); TargetPermanent target = new TargetPermanent(tokenFilter); target.withNotTarget(true); player.choose(outcome, target, source, game); diff --git a/Mage.Sets/src/mage/cards/n/NahirisMachinations.java b/Mage.Sets/src/mage/cards/n/NahirisMachinations.java index a37a28dda48..284d29c2d7f 100644 --- a/Mage.Sets/src/mage/cards/n/NahirisMachinations.java +++ b/Mage.Sets/src/mage/cards/n/NahirisMachinations.java @@ -15,6 +15,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterBlockingCreature; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; @@ -34,7 +35,7 @@ public final class NahirisMachinations extends CardImpl { // {1}{R}: Nahiri's Machinations deals 1 damage to target blocking creature. ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new ManaCostsImpl<>("{1}{R}")); - ability.addTarget(new TargetCreaturePermanent(new FilterBlockingCreature("blocking creature"))); + ability.addTarget(new TargetPermanent(new FilterBlockingCreature("blocking creature"))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NajeelaTheBladeBlossom.java b/Mage.Sets/src/mage/cards/n/NajeelaTheBladeBlossom.java index 95d30ba9b08..c335bce3ad6 100644 --- a/Mage.Sets/src/mage/cards/n/NajeelaTheBladeBlossom.java +++ b/Mage.Sets/src/mage/cards/n/NajeelaTheBladeBlossom.java @@ -1,13 +1,13 @@ package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksAllTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.IsPhaseCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.AdditionalCombatPhaseEffect; import mage.abilities.effects.common.CreateTokenTargetEffect; @@ -18,24 +18,20 @@ import mage.abilities.keyword.LifelinkAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SetTargetPointer; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.TurnPhase; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.game.permanent.token.WarriorToken; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class NajeelaTheBladeBlossom extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.WARRIOR, "Warrior"); + private static final Condition condition = new IsPhaseCondition(TurnPhase.COMBAT); public NajeelaTheBladeBlossom(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); @@ -54,25 +50,20 @@ public final class NajeelaTheBladeBlossom extends CardImpl { )); // {W}{U}{B}{R}{G}: Untap all attacking creatures. They gain trample, lifelink, and haste until end of turn. After this phase, there is an additional combat phase. Activate this ability only during combat. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, + Ability ability = new ActivateIfConditionActivatedAbility( new UntapAllEffect(StaticFilters.FILTER_ATTACKING_CREATURES), - new ManaCostsImpl<>("{W}{U}{B}{R}{G}"), - new IsPhaseCondition(TurnPhase.COMBAT) + new ManaCostsImpl<>("{W}{U}{B}{R}{G}"), condition ); ability.addEffect(new GainAbilityAllEffect( - TrampleAbility.getInstance(), - Duration.EndOfTurn, + TrampleAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_ATTACKING_CREATURES ).setText("They gain trample")); ability.addEffect(new GainAbilityAllEffect( - LifelinkAbility.getInstance(), - Duration.EndOfTurn, + LifelinkAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_ATTACKING_CREATURES ).setText(", lifelink")); ability.addEffect(new GainAbilityAllEffect( - HasteAbility.getInstance(), - Duration.EndOfTurn, + HasteAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_ATTACKING_CREATURES ).setText(", and haste until end of turn")); ability.addEffect(new AdditionalCombatPhaseEffect()); diff --git a/Mage.Sets/src/mage/cards/n/NaliaDeArnise.java b/Mage.Sets/src/mage/cards/n/NaliaDeArnise.java index 3101cd723a5..f1a1a484728 100644 --- a/Mage.Sets/src/mage/cards/n/NaliaDeArnise.java +++ b/Mage.Sets/src/mage/cards/n/NaliaDeArnise.java @@ -2,19 +2,21 @@ package mage.cards.n; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.FullPartyCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.effects.common.continuous.LookAtTopCardOfLibraryAnyTimeEffect; import mage.abilities.effects.common.continuous.PlayFromTopOfLibraryEffect; import mage.abilities.effects.common.counter.AddCountersAllEffect; import mage.abilities.hint.common.PartyCountHint; import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.StaticFilters; @@ -54,17 +56,13 @@ public final class NaliaDeArnise extends CardImpl { this.addAbility(new SimpleStaticAbility(new PlayFromTopOfLibraryEffect(filter))); // At the beginning of combat on your turn, if you have a full party, put a +1/+1 counter on each creature you control and those creatures gain deathtouch until end of turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility(new AddCountersAllEffect( - CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE - )), FullPartyCondition.instance, "At the beginning " + - "of combat on your turn, if you have a full party, put a +1/+1 counter on each creature " + - "you control and those creatures gain deathtouch until end of turn." - ); + Ability ability = new BeginningOfCombatTriggeredAbility(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE + )).withInterveningIf(FullPartyCondition.instance); ability.addEffect(new GainAbilityAllEffect( DeathtouchAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURE - )); + ).setText("and those creatures gain deathtouch until end of turn")); this.addAbility(ability.addHint(PartyCountHint.instance)); } diff --git a/Mage.Sets/src/mage/cards/n/NantukoMonastery.java b/Mage.Sets/src/mage/cards/n/NantukoMonastery.java index 2d5d06dff11..167a029fb6d 100644 --- a/Mage.Sets/src/mage/cards/n/NantukoMonastery.java +++ b/Mage.Sets/src/mage/cards/n/NantukoMonastery.java @@ -3,7 +3,7 @@ package mage.cards.n; import mage.MageInt; import mage.abilities.condition.common.ThresholdCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.mana.ColorlessManaAbility; @@ -29,7 +29,7 @@ public final class NantukoMonastery extends CardImpl { this.addAbility(new ColorlessManaAbility()); // Threshold - {G}{W}: Nantuko Monastery becomes a 4/4 green and white Insect Monk creature with first strike until end of turn. It's still a land. Activate this ability only if seven or more cards are in your graveyard. - this.addAbility(new ConditionalActivatedAbility(new BecomesCreatureSourceEffect( + this.addAbility(new ActivateIfConditionActivatedAbility(new BecomesCreatureSourceEffect( new NantukoMonasteryToken(), CardType.LAND, Duration.EndOfTurn), new ManaCostsImpl<>("{G}{W}"), ThresholdCondition.instance ).setAbilityWord(AbilityWord.THRESHOLD)); diff --git a/Mage.Sets/src/mage/cards/n/NantukoShaman.java b/Mage.Sets/src/mage/cards/n/NantukoShaman.java index fb71f184ff2..7c5c9b60473 100644 --- a/Mage.Sets/src/mage/cards/n/NantukoShaman.java +++ b/Mage.Sets/src/mage/cards/n/NantukoShaman.java @@ -1,36 +1,37 @@ - package mage.cards.n; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.SuspendAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; +import mage.constants.SubType; import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.permanent.TappedPredicate; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class NantukoShaman extends CardImpl { - private static final FilterLandPermanent filter = new FilterLandPermanent(); + private static final FilterLandPermanent filter = new FilterLandPermanent("you control no tapped lands"); + static { filter.add(TappedPredicate.TAPPED); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0); + public NantukoShaman(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.subtype.add(SubType.INSECT); this.subtype.add(SubType.SHAMAN); @@ -38,11 +39,7 @@ public final class NantukoShaman extends CardImpl { this.toughness = new MageInt(2); // When Nantuko Shaman enters the battlefield, if you control no tapped lands, draw a card. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)), - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0), - "When {this} enters, if you control no tapped lands, draw a card."); - this.addAbility(ability); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)).withInterveningIf(condition)); // Suspend 1-{2}{G}{G} this.addAbility(new SuspendAbility(1, new ManaCostsImpl<>("{2}{G}{G}"), this)); diff --git a/Mage.Sets/src/mage/cards/n/NaomiPillarOfOrder.java b/Mage.Sets/src/mage/cards/n/NaomiPillarOfOrder.java index 411846fd272..78f56a14c48 100644 --- a/Mage.Sets/src/mage/cards/n/NaomiPillarOfOrder.java +++ b/Mage.Sets/src/mage/cards/n/NaomiPillarOfOrder.java @@ -3,7 +3,6 @@ package mage.cards.n; import mage.MageInt; import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; import mage.abilities.condition.common.ControlArtifactAndEnchantmentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.common.ControlArtifactAndEnchantmentHint; import mage.cards.CardImpl; @@ -30,11 +29,8 @@ public final class NaomiPillarOfOrder extends CardImpl { this.toughness = new MageInt(4); // Whenever Naomi, Pillar of Order enters the battlefield or attacks, if you control an artifact and an enchantment, create a 2/2 white Samurai creature token with vigilance. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldOrAttacksSourceTriggeredAbility(new CreateTokenEffect(new SamuraiToken())), - ControlArtifactAndEnchantmentCondition.instance, "Whenever {this} enters or " + - "attacks, if you control an artifact and an enchantment, create a 2/2 white Samurai creature token with vigilance." - ).addHint(ControlArtifactAndEnchantmentHint.instance)); + this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new CreateTokenEffect(new SamuraiToken())) + .withInterveningIf(ControlArtifactAndEnchantmentCondition.instance).addHint(ControlArtifactAndEnchantmentHint.instance)); } private NaomiPillarOfOrder(final NaomiPillarOfOrder card) { diff --git a/Mage.Sets/src/mage/cards/n/NaturesWay.java b/Mage.Sets/src/mage/cards/n/NaturesWay.java index 451ade62eef..aa31e9ba1ac 100644 --- a/Mage.Sets/src/mage/cards/n/NaturesWay.java +++ b/Mage.Sets/src/mage/cards/n/NaturesWay.java @@ -9,11 +9,14 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author LevelX2 */ @@ -31,7 +34,7 @@ public final class NaturesWay extends CardImpl { // It deals damage equal to its power to target creature you don't control. this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect("It")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); // second target + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); // second target } private NaturesWay(final NaturesWay card) { diff --git a/Mage.Sets/src/mage/cards/n/NavigatorsRuin.java b/Mage.Sets/src/mage/cards/n/NavigatorsRuin.java index 846b7b84c20..0b6f0995e22 100644 --- a/Mage.Sets/src/mage/cards/n/NavigatorsRuin.java +++ b/Mage.Sets/src/mage/cards/n/NavigatorsRuin.java @@ -1,11 +1,10 @@ package mage.cards.n; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.MillCardsTargetEffect; import mage.abilities.hint.common.RaidHint; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; @@ -24,16 +23,10 @@ public final class NavigatorsRuin extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); // Raid - At the beginning of your end step, if you attacked with a creature this turm, target opponent puts the top four cards of their library into their graveyard. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new BeginningOfEndStepTriggeredAbility( - new MillCardsTargetEffect(4)), - RaidCondition.instance, - "At the beginning of your end step, " + - "if you attacked this turn, target opponent mills four cards." - ); + Ability ability = new BeginningOfEndStepTriggeredAbility(new MillCardsTargetEffect(4)) + .withInterveningIf(RaidCondition.instance); ability.addTarget(new TargetOpponent()); - ability.setAbilityWord(AbilityWord.RAID); - ability.addHint(RaidHint.instance); - this.addAbility(ability, new PlayerAttackedWatcher()); + this.addAbility(ability.setAbilityWord(AbilityWord.RAID).addHint(RaidHint.instance), new PlayerAttackedWatcher()); } private NavigatorsRuin(final NavigatorsRuin card) { diff --git a/Mage.Sets/src/mage/cards/n/NayaHushblade.java b/Mage.Sets/src/mage/cards/n/NayaHushblade.java index e42a0764a67..1e16ae4e125 100644 --- a/Mage.Sets/src/mage/cards/n/NayaHushblade.java +++ b/Mage.Sets/src/mage/cards/n/NayaHushblade.java @@ -1,7 +1,6 @@ package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -13,12 +12,13 @@ import mage.abilities.keyword.ShroudAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.mageobject.MulticoloredPredicate; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.MulticoloredPredicate; + +import java.util.UUID; /** * @@ -46,9 +46,9 @@ public final class NayaHushblade extends CardImpl { // As long as you control another multicolored permanent, Naya Hushblade gets +1/+1 and has shroud. Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( - new BoostSourceEffect(1,1, Duration.WhileOnBattlefield), + new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), new PermanentsOnTheBattlefieldCondition(filter), - "As long as you control another multicolored permanent, Naya Hushblade gets +1/+1")); + "As long as you control another multicolored permanent, {this} gets +1/+1")); ability.addEffect(new ConditionalContinuousEffect( new GainAbilitySourceEffect(ShroudAbility.getInstance()), new PermanentsOnTheBattlefieldCondition(filter), diff --git a/Mage.Sets/src/mage/cards/n/NazahnReveredBladesmith.java b/Mage.Sets/src/mage/cards/n/NazahnReveredBladesmith.java index 190e36257b9..8abdfc14b67 100644 --- a/Mage.Sets/src/mage/cards/n/NazahnReveredBladesmith.java +++ b/Mage.Sets/src/mage/cards/n/NazahnReveredBladesmith.java @@ -21,8 +21,8 @@ import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.filter.predicate.permanent.EquippedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInLibrary; -import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.TargetAdjuster; import java.util.UUID; @@ -61,7 +61,7 @@ public final class NazahnReveredBladesmith extends CardImpl { // Whenever an equipped creature you control attacks, you may tap target creature defending player controls. Ability ability = new AttacksCreatureYouControlTriggeredAbility(new NazahnTapEffect(), true, equippedFilter, true); - ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature defending player controls"))); + ability.addTarget(new TargetPermanent(new FilterCreaturePermanent("creature defending player controls"))); ability.setTargetAdjuster(NazahnReveredBladesmithAdjuster.instance); this.addAbility(ability); } @@ -89,8 +89,7 @@ enum NazahnReveredBladesmithAdjuster implements TargetAdjuster { } } ability.getTargets().clear(); - TargetCreaturePermanent target = new TargetCreaturePermanent(filterDefender); - ability.addTarget(target); + ability.addTarget(new TargetPermanent(filterDefender)); } } diff --git a/Mage.Sets/src/mage/cards/n/Nebuchadnezzar.java b/Mage.Sets/src/mage/cards/n/Nebuchadnezzar.java index 20048051a12..39eeffa252b 100644 --- a/Mage.Sets/src/mage/cards/n/Nebuchadnezzar.java +++ b/Mage.Sets/src/mage/cards/n/Nebuchadnezzar.java @@ -9,9 +9,11 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseACardNameEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.cards.*; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetOpponent; @@ -33,11 +35,13 @@ public final class Nebuchadnezzar extends CardImpl { this.toughness = new MageInt(3); // {X}, {T}: Choose a card name. Target opponent reveals X cards at random from their hand. Then that player discards all cards with that name revealed this way. Activate this ability only during your turn. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new ChooseACardNameEffect(ChooseACardNameEffect.TypeOfName.ALL), new ManaCostsImpl<>("{X}"), MyTurnCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new ChooseACardNameEffect(ChooseACardNameEffect.TypeOfName.ALL), + new ManaCostsImpl<>("{X}"), MyTurnCondition.instance + ); ability.addCost(new TapSourceCost()); ability.addEffect(new NebuchadnezzarEffect()); ability.addTarget(new TargetOpponent()); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NecraSanctuary.java b/Mage.Sets/src/mage/cards/n/NecraSanctuary.java index 4696cd265c8..c998f69081c 100644 --- a/Mage.Sets/src/mage/cards/n/NecraSanctuary.java +++ b/Mage.Sets/src/mage/cards/n/NecraSanctuary.java @@ -1,18 +1,17 @@ - package mage.cards.n; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.common.SanctuaryInterveningIfTriggeredAbility; +import mage.abilities.common.SanctuaryTriggeredAbility; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class NecraSanctuary extends CardImpl { @@ -21,10 +20,9 @@ public final class NecraSanctuary extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}"); // At the beginning of your upkeep, if you control a green or white permanent, target player loses 1 life. If you control a green permanent and a white permanent, that player loses 3 life instead. - Ability ability = new SanctuaryInterveningIfTriggeredAbility( + Ability ability = new SanctuaryTriggeredAbility( new LoseLifeTargetEffect(1), new LoseLifeTargetEffect(3), ObjectColor.GREEN, ObjectColor.WHITE, - "At the beginning of your upkeep, if you control a green or white permanent, " - + "target player loses 1 life. If you control a green permanent and a white permanent, that player loses 3 life instead." + "target player loses 1 life. If you control a green permanent and a white permanent, that player loses 3 life instead." ); ability.addTarget(new TargetPlayer()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/n/Necrite.java b/Mage.Sets/src/mage/cards/n/Necrite.java index bc0b994b982..0ce99f7ef0e 100644 --- a/Mage.Sets/src/mage/cards/n/Necrite.java +++ b/Mage.Sets/src/mage/cards/n/Necrite.java @@ -1,44 +1,42 @@ - package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility; import mage.abilities.costs.common.SacrificeSourceCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.DoIfCostPaid; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SetTargetPointer; import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.target.Target; import mage.target.TargetPermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; + +import java.util.UUID; /** - * * @author MarcoMarin */ public final class Necrite extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("creature defending player controls"); + public Necrite(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); this.subtype.add(SubType.THRULL); this.power = new MageInt(2); this.toughness = new MageInt(2); // Whenever Necrite attacks and isn't blocked, you may sacrifice it. If you do, destroy target creature defending player controls. It can't be regenerated. DoIfCostPaid effect = new DoIfCostPaid(new DestroyTargetEffect(true), new SacrificeSourceCost(), "Sacrifice {this} to destroy target creature defending player controls?"); - effect.setText("you may sacrifice it. If you do, destroy target creature defending player controls. It can't be regenerated."); - Ability ability = new NecriteTriggeredAbility(effect); + Ability ability = new AttacksAndIsNotBlockedTriggeredAbility(effect, false, SetTargetPointer.PLAYER); + ability.addTarget(new TargetPermanent(filter)); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); this.addAbility(ability); - } private Necrite(final Necrite card) { @@ -50,33 +48,3 @@ public final class Necrite extends CardImpl { return new Necrite(this); } } - -class NecriteTriggeredAbility extends AttacksAndIsNotBlockedTriggeredAbility{ - - public NecriteTriggeredAbility(Effect effect) { - super(effect); - } - - private NecriteTriggeredAbility(final NecriteTriggeredAbility ability) { - super(ability); - } - - @Override - public NecriteTriggeredAbility copy() { - return new NecriteTriggeredAbility(this); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (super.checkTrigger(event, game)){ - UUID defendingPlayerId = game.getCombat().getDefendingPlayerId(getSourceId(), game); - FilterPermanent filter = new FilterCreaturePermanent(); - filter.add(new ControllerIdPredicate(defendingPlayerId)); - Target target = new TargetPermanent(filter); - this.getTargets().clear(); - this.addTarget(target); - return true; - } - return false; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/n/Necrosavant.java b/Mage.Sets/src/mage/cards/n/Necrosavant.java index 44c5d86dc5e..65e33666d87 100644 --- a/Mage.Sets/src/mage/cards/n/Necrosavant.java +++ b/Mage.Sets/src/mage/cards/n/Necrosavant.java @@ -1,25 +1,22 @@ - package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.PhaseStep; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author Quercitron */ public final class Necrosavant extends CardImpl { @@ -33,11 +30,10 @@ public final class Necrosavant extends CardImpl { this.toughness = new MageInt(5); // {3}{B}{B}, Sacrifice a creature: Return Necrosavant from your graveyard to the battlefield. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility(Zone.GRAVEYARD, - new ReturnSourceFromGraveyardToBattlefieldEffect(false,false), - new ManaCostsImpl<>("{3}{B}{B}"), - new IsStepCondition(PhaseStep.UPKEEP), - null + Ability ability = new ActivateIfConditionActivatedAbility( + Zone.GRAVEYARD, + new ReturnSourceFromGraveyardToBattlefieldEffect(false, false), + new ManaCostsImpl<>("{3}{B}{B}"), IsStepCondition.getMyUpkeep() ); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/n/NecroticPlague.java b/Mage.Sets/src/mage/cards/n/NecroticPlague.java index 3827b308fc9..91bfa44657b 100644 --- a/Mage.Sets/src/mage/cards/n/NecroticPlague.java +++ b/Mage.Sets/src/mage/cards/n/NecroticPlague.java @@ -85,6 +85,7 @@ enum NecroticPlagueAdjuster implements TargetAdjuster { ability.setControllerId(creatureController.getId()); ability.getTargets().clear(); TargetPermanent target = new TargetOpponentsCreaturePermanent(); + target.setAbilityController(ability.getControllerId()); target.setTargetController(creatureController.getId()); ability.getTargets().add(target); } diff --git a/Mage.Sets/src/mage/cards/n/NeedletoothRaptor.java b/Mage.Sets/src/mage/cards/n/NeedletoothRaptor.java index d69ab55059b..17a6e1e8ebb 100644 --- a/Mage.Sets/src/mage/cards/n/NeedletoothRaptor.java +++ b/Mage.Sets/src/mage/cards/n/NeedletoothRaptor.java @@ -11,8 +11,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author L_J @@ -27,7 +30,7 @@ public final class NeedletoothRaptor extends CardImpl { // Enrage — Whenever Needletooth Raptor is dealt damage, it deals 5 damage to target creature an opponent controls. Ability ability = new DealtDamageToSourceTriggeredAbility(new DamageTargetEffect(5).setText("it deals 5 damage to target creature an opponent controls"), false, true); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NeighborhoodGuardian.java b/Mage.Sets/src/mage/cards/n/NeighborhoodGuardian.java index 9e6d8fd9a4a..64f85fb2446 100644 --- a/Mage.Sets/src/mage/cards/n/NeighborhoodGuardian.java +++ b/Mage.Sets/src/mage/cards/n/NeighborhoodGuardian.java @@ -2,7 +2,7 @@ package mage.cards.n; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -10,7 +10,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.PowerPredicate; import mage.target.common.TargetControlledCreaturePermanent; @@ -22,7 +22,7 @@ import java.util.UUID; */ public final class NeighborhoodGuardian extends CardImpl { - private static final FilterPermanent filter = new FilterCreaturePermanent("another creature with power 2 or less"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("another creature you control with power 2 or less"); static { filter.add(AnotherPredicate.instance); @@ -37,7 +37,7 @@ public final class NeighborhoodGuardian extends CardImpl { this.toughness = new MageInt(2); // Whenever another creature with power 2 or less you control enters, target creature you control gets +1/+1 until end of turn. - Ability ability = new EntersBattlefieldControlledTriggeredAbility(new BoostTargetEffect(1, 1), filter); + Ability ability = new EntersBattlefieldAllTriggeredAbility(new BoostTargetEffect(1, 1), filter); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/Nekrataal.java b/Mage.Sets/src/mage/cards/n/Nekrataal.java index 4b257515b8c..3de53b4175a 100644 --- a/Mage.Sets/src/mage/cards/n/Nekrataal.java +++ b/Mage.Sets/src/mage/cards/n/Nekrataal.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -44,7 +45,7 @@ public final class Nekrataal extends CardImpl { // When Nekrataal enters the battlefield, destroy target nonartifact, nonblack creature. That creature can't be regenerated. Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(true)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NemesisPhoenix.java b/Mage.Sets/src/mage/cards/n/NemesisPhoenix.java index d58da3b3b3e..9bf9a9f8466 100644 --- a/Mage.Sets/src/mage/cards/n/NemesisPhoenix.java +++ b/Mage.Sets/src/mage/cards/n/NemesisPhoenix.java @@ -39,7 +39,7 @@ public final class NemesisPhoenix extends CardImpl { this.addAbility(new ActivateIfConditionActivatedAbility( Zone.GRAVEYARD, new ReturnToBattlefieldUnderOwnerControlSourceEffect(true, true, -1) - .setText("return {this} from your graveyard to the battlefield tapped and attacking"), + .setText("return this card from your graveyard to the battlefield tapped and attacking"), new ManaCostsImpl<>("{2}{R}"), NemesisPhoenixCondition.instance )); } diff --git a/Mage.Sets/src/mage/cards/n/NephaliaSmuggler.java b/Mage.Sets/src/mage/cards/n/NephaliaSmuggler.java index 42bb23a4cad..02aa626caeb 100644 --- a/Mage.Sets/src/mage/cards/n/NephaliaSmuggler.java +++ b/Mage.Sets/src/mage/cards/n/NephaliaSmuggler.java @@ -10,9 +10,8 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -32,7 +31,7 @@ public final class NephaliaSmuggler extends CardImpl { // {3}{U}, {tap}: Exile another target creature you control, then return that card to the battlefield under your control. Ability ability = new SimpleActivatedAbility(new ExileThenReturnTargetEffect(true, true), new ManaCostsImpl<>("{3}{U}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NerdRage.java b/Mage.Sets/src/mage/cards/n/NerdRage.java index e1a8568bd12..2f45373c802 100644 --- a/Mage.Sets/src/mage/cards/n/NerdRage.java +++ b/Mage.Sets/src/mage/cards/n/NerdRage.java @@ -1,31 +1,32 @@ package mage.cards.n; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInHandCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; -import mage.constants.*; -import mage.target.common.TargetCreaturePermanent; -import mage.abilities.effects.common.AttachEffect; -import mage.target.TargetPermanent; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; /** * @author Cguy7777 */ public final class NerdRage extends CardImpl { + private static final Condition condition = new CardsInHandCondition(ComparisonType.MORE_THAN, 9); + public NerdRage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); @@ -42,22 +43,17 @@ public final class NerdRage extends CardImpl { // Enchanted creature has "You have no maximum hand size" and "Whenever this creature attacks, // if you have ten or more cards in hand, it gets +10/+10 until end of turn." - SimpleStaticAbility noMaxHandSizeAbility = new SimpleStaticAbility(new MaximumHandSizeControllerEffect( - Integer.MAX_VALUE, - Duration.WhileOnBattlefield, - MaximumHandSizeControllerEffect.HandSizeModification.SET)); - ConditionalInterveningIfTriggeredAbility attacksBoostAbility = new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new BoostSourceEffect(10, 10, Duration.EndOfTurn)), - new CardsInHandCondition(ComparisonType.MORE_THAN, 9), - "Whenever {this} attacks, if you have ten or more cards in hand, it gets +10/+10 until end of turn."); - - Effect gainNoMaxHandSizeEffect = new GainAbilityAttachedEffect(noMaxHandSizeAbility, AttachmentType.AURA) - .setText("Enchanted creature has \"You have no maximum hand size\""); - Effect gainAttacksBoostEffect = new GainAbilityAttachedEffect(attacksBoostAbility, AttachmentType.AURA) - .setText("\"Whenever this creature attacks, if you have ten or more cards in hand, it gets +10/+10 until end of turn.\""); - - Ability ability = new SimpleStaticAbility(gainNoMaxHandSizeEffect); - ability.addEffect(gainAttacksBoostEffect.concatBy("and")); + Ability ability = new SimpleStaticAbility(new GainAbilityAttachedEffect( + new SimpleStaticAbility(new MaximumHandSizeControllerEffect( + Integer.MAX_VALUE, Duration.WhileOnBattlefield, + MaximumHandSizeControllerEffect.HandSizeModification.SET + )), AttachmentType.AURA + ).setText("Enchanted creature has \"You have no maximum hand size\"")); + ability.addEffect(new GainAbilityAttachedEffect( + new AttacksTriggeredAbility(new BoostSourceEffect( + 10, 10, Duration.EndOfTurn, "it" + )).withInterveningIf(condition), AttachmentType.AURA + ).setText("and \"Whenever this creature attacks, if you have ten or more cards in hand, it gets +10/+10 until end of turn.\"")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NessianDemolok.java b/Mage.Sets/src/mage/cards/n/NessianDemolok.java index 2091b1ddbde..aa6f76928ff 100644 --- a/Mage.Sets/src/mage/cards/n/NessianDemolok.java +++ b/Mage.Sets/src/mage/cards/n/NessianDemolok.java @@ -1,12 +1,9 @@ - package mage.cards.n; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.TributeNotPaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.TributeAbility; import mage.cards.CardImpl; @@ -17,8 +14,9 @@ import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class NessianDemolok extends CardImpl { @@ -30,19 +28,20 @@ public final class NessianDemolok extends CardImpl { } public NessianDemolok(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); this.subtype.add(SubType.BEAST); this.power = new MageInt(3); this.toughness = new MageInt(3); - // Tribute 3 + // Tribute 3 this.addAbility(new TributeAbility(3)); + // When Nessian Demolok enters the battlefield, if tribute wasn't paid, destroy target noncreature permanent. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), false); + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()) + .withInterveningIf(TributeNotPaidCondition.instance); ability.addTarget(new TargetPermanent(filter)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, TributeNotPaidCondition.instance, - "When {this} enters, if tribute wasn't paid, destroy target noncreature permanent.")); + this.addAbility(ability); } private NessianDemolok(final NessianDemolok card) { diff --git a/Mage.Sets/src/mage/cards/n/NessianHornbeetle.java b/Mage.Sets/src/mage/cards/n/NessianHornbeetle.java index bf85dd5896a..2d4799e8af9 100644 --- a/Mage.Sets/src/mage/cards/n/NessianHornbeetle.java +++ b/Mage.Sets/src/mage/cards/n/NessianHornbeetle.java @@ -1,11 +1,10 @@ package mage.cards.n; import mage.MageInt; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -14,8 +13,8 @@ import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.mageobject.PowerPredicate; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.PowerPredicate; import java.util.UUID; @@ -24,7 +23,8 @@ import java.util.UUID; */ public final class NessianHornbeetle extends CardImpl { - private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("you control another creature with power 4 or greater"); static { filter.add(AnotherPredicate.instance); @@ -41,12 +41,9 @@ public final class NessianHornbeetle extends CardImpl { this.toughness = new MageInt(2); // At the beginning of combat on your turn, if you control another creature with power 4 or greater, put a +1/+1 counter on Nessian Hornbeetle. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance()) - ), condition, "At the beginning of combat on your turn, if you control " + - "another creature with power 4 or greater, put a +1/+1 counter on {this}." - )); + this.addAbility(new BeginningOfCombatTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()) + ).withInterveningIf(condition)); } private NessianHornbeetle(final NessianHornbeetle card) { diff --git a/Mage.Sets/src/mage/cards/n/NessianWildsRavager.java b/Mage.Sets/src/mage/cards/n/NessianWildsRavager.java index 71ada8edfe5..4079623e1a7 100644 --- a/Mage.Sets/src/mage/cards/n/NessianWildsRavager.java +++ b/Mage.Sets/src/mage/cards/n/NessianWildsRavager.java @@ -1,35 +1,27 @@ - package mage.cards.n; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.TributeNotPaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.FightTargetSourceEffect; import mage.abilities.keyword.TributeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class NessianWildsRavager extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); - static { - filter.add(AnotherPredicate.instance); - } - public NessianWildsRavager(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); this.subtype.add(SubType.HYDRA); this.power = new MageInt(6); @@ -37,15 +29,13 @@ public final class NessianWildsRavager extends CardImpl { // Tribute 6 this.addAbility(new TributeAbility(6)); + // When Nessian Wilds Ravager enters the battlefield, if tribute wasn't paid, you may have Nessian Wilds Ravager fight another target creature. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new FightTargetSourceEffect(), true); - ability.addTarget(new TargetCreaturePermanent(filter)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - ability, - TributeNotPaidCondition.instance, - "When {this} enters, if tribute wasn't paid, " + - "you may have {this} fight another target creature. " + - "(Each deals damage equal to its power to the other.)")); + Ability ability = new EntersBattlefieldTriggeredAbility( + new FightTargetSourceEffect().setText("have {this} fight another target creature"), true + ).withInterveningIf(TributeNotPaidCondition.instance); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + this.addAbility(ability); } private NessianWildsRavager(final NessianWildsRavager card) { diff --git a/Mage.Sets/src/mage/cards/n/NestOfScarabs.java b/Mage.Sets/src/mage/cards/n/NestOfScarabs.java index 66c39c6f280..d4545e85df7 100644 --- a/Mage.Sets/src/mage/cards/n/NestOfScarabs.java +++ b/Mage.Sets/src/mage/cards/n/NestOfScarabs.java @@ -20,8 +20,10 @@ public final class NestOfScarabs extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}"); // Whenever you put one or more -1/-1 counters on a creature, create that many 1/1 black Insect creature tokens. - this.addAbility(new PutCounterOnCreatureTriggeredAbility(new CreateTokenEffect(new NestOfScarabsBlackInsectToken(), new EffectKeyValue("countersAdded")) - .setText("create that many 1/1 black Insect creature tokens"), CounterType.M1M1.createInstance())); + this.addAbility(new PutCounterOnCreatureTriggeredAbility( + new CreateTokenEffect(new NestOfScarabsBlackInsectToken(), + new EffectKeyValue("countersAdded", "that many")), + CounterType.M1M1.createInstance())); } private NestOfScarabs(final NestOfScarabs card) { diff --git a/Mage.Sets/src/mage/cards/n/NetherSpirit.java b/Mage.Sets/src/mage/cards/n/NetherSpirit.java index 4dcc774254c..77c06aec98b 100644 --- a/Mage.Sets/src/mage/cards/n/NetherSpirit.java +++ b/Mage.Sets/src/mage/cards/n/NetherSpirit.java @@ -33,7 +33,7 @@ public final class NetherSpirit extends CardImpl { // At the beginning of your upkeep, if Nether Spirit is the only creature card in your graveyard, you may return Nether Spirit to the battlefield. this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.GRAVEYARD, - TargetController.YOU, new ReturnSourceFromGraveyardToBattlefieldEffect().setText("return {this} to the battlefield"), + TargetController.YOU, new ReturnSourceFromGraveyardToBattlefieldEffect().setText("return this card to the battlefield"), true).withInterveningIf(NetherSpiritCondition.instance)); } @@ -60,6 +60,6 @@ enum NetherSpiritCondition implements Condition { @Override public String toString() { - return "{this} is the only creature card in your graveyard"; + return "this card is the only creature card in your graveyard"; } } diff --git a/Mage.Sets/src/mage/cards/n/NettlingImp.java b/Mage.Sets/src/mage/cards/n/NettlingImp.java index 4f7898080c5..2726cec45c9 100644 --- a/Mage.Sets/src/mage/cards/n/NettlingImp.java +++ b/Mage.Sets/src/mage/cards/n/NettlingImp.java @@ -1,14 +1,14 @@ package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.OpponentsTurnCondition; import mage.abilities.condition.common.TargetAttackedThisTurnCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.combat.AttacksIfAbleTargetEffect; @@ -19,24 +19,23 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.ControlledFromStartOfControllerTurnPredicate; import mage.game.Game; -import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; -import mage.watchers.common.AttackedThisTurnWatcher; + +import java.util.UUID; /** - * * @author MTGfan */ public final class NettlingImp extends CardImpl { - static final FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Wall"); + static final FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Wall creature the active player has controlled continuously since the beginning of the turn"); static { filter.add(Predicates.not(SubType.WALL.getPredicate())); filter.add(new ControlledFromStartOfControllerTurnPredicate()); filter.add(TargetController.ACTIVE.getControllerPredicate()); - filter.setMessage("non-Wall creature the active player has controlled continuously since the beginning of the turn."); } public NettlingImp(UUID ownerId, CardSetInfo setInfo) { @@ -47,13 +46,14 @@ public final class NettlingImp extends CardImpl { this.toughness = new MageInt(1); // {T}: Choose target non-Wall creature the active player has controlled continuously since the beginning of the turn. That creature attacks this turn if able. If it doesn't, destroy it at the beginning of the next end step. Activate this ability only during an opponent's turn, before attackers are declared. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new AttacksIfAbleTargetEffect(Duration.EndOfTurn), - new TapSourceCost(), new NettlingImpTurnCondition(), - "{T}: Choose target non-Wall creature the active player has controlled continuously since the beginning of the turn. " - + "That creature attacks this turn if able. If it doesn't, destroy it at the beginning of the next end step. " - + "Activate only during an opponent's turn, before attackers are declared."); + Ability ability = new ActivateIfConditionActivatedAbility( + new AttacksIfAbleTargetEffect(Duration.EndOfTurn) + .setText("choose target non-Wall creature the active player has controlled " + + "continuously since the beginning of the turn. That creature attacks this turn if able"), + new TapSourceCost(), NettlingImpTurnCondition.instance + ); ability.addEffect(new NettlingImpDelayedDestroyEffect()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } @@ -68,17 +68,17 @@ public final class NettlingImp extends CardImpl { } } -class NettlingImpTurnCondition implements Condition { +enum NettlingImpTurnCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { - Player activePlayer = game.getPlayer(game.getActivePlayerId()); - return activePlayer != null && activePlayer.hasOpponent(source.getControllerId(), game) && game.getPhase().getStep().getType().getIndex() < 5; + return OpponentsTurnCondition.instance.apply(game, source) && !game.getTurn().isDeclareAttackersStepStarted(); } @Override public String toString() { - return ""; + return "during an opponent's turn, before attackers are declared"; } } @@ -86,7 +86,7 @@ class NettlingImpDelayedDestroyEffect extends OneShotEffect { NettlingImpDelayedDestroyEffect() { super(Outcome.Detriment); - this.staticText = "If it doesn't, destroy it at the beginning of the next end step"; + this.staticText = "Destroy it at the beginning of the next end step if it didn't attack this turn"; } private NettlingImpDelayedDestroyEffect(final NettlingImpDelayedDestroyEffect effect) { diff --git a/Mage.Sets/src/mage/cards/n/NeurokTransmuter.java b/Mage.Sets/src/mage/cards/n/NeurokTransmuter.java index 0e81a40e425..6d0df71f8d2 100644 --- a/Mage.Sets/src/mage/cards/n/NeurokTransmuter.java +++ b/Mage.Sets/src/mage/cards/n/NeurokTransmuter.java @@ -17,6 +17,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -47,7 +48,7 @@ public final class NeurokTransmuter extends CardImpl { Effect blueEffect = new BecomesColorTargetEffect(ObjectColor.BLUE, Duration.EndOfTurn); blueEffect.setText("Until end of turn, target artifact creature becomes blue"); Ability becomeBlueAbility = new SimpleActivatedAbility(blueEffect, new ManaCostsImpl<>("{U}")); - becomeBlueAbility.addTarget(new TargetCreaturePermanent(filter)); + becomeBlueAbility.addTarget(new TargetPermanent(filter)); Effect loseArtifactEffect = new LoseArtifactTypeTargetEffect(Duration.EndOfTurn); loseArtifactEffect.setText("and isn't an artifact"); becomeBlueAbility.addEffect(loseArtifactEffect); diff --git a/Mage.Sets/src/mage/cards/n/NeyaliSunsVanguard.java b/Mage.Sets/src/mage/cards/n/NeyaliSunsVanguard.java index 6955a000629..10e73a88ab8 100644 --- a/Mage.Sets/src/mage/cards/n/NeyaliSunsVanguard.java +++ b/Mage.Sets/src/mage/cards/n/NeyaliSunsVanguard.java @@ -2,7 +2,7 @@ package mage.cards.n; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.AttacksPlayerWithCreaturesTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -12,11 +12,10 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.permanent.AttackingPredicate; import mage.filter.predicate.permanent.TokenPredicate; -import mage.game.Controllable; import mage.game.Game; -import mage.game.events.DefenderAttackedEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentToken; @@ -33,11 +32,13 @@ import java.util.UUID; */ public final class NeyaliSunsVanguard extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("attacking tokens"); + private static final FilterPermanent filterAttacking = new FilterPermanent("attacking tokens"); + private static final FilterPermanent filterControlled = new FilterControlledPermanent("tokens you control"); static { - filter.add(AttackingPredicate.instance); - filter.add(TokenPredicate.TRUE); + filterAttacking.add(AttackingPredicate.instance); + filterAttacking.add(TokenPredicate.TRUE); + filterControlled.add(TokenPredicate.TRUE); } public NeyaliSunsVanguard(UUID ownerId, CardSetInfo setInfo) { @@ -51,11 +52,13 @@ public final class NeyaliSunsVanguard extends CardImpl { // Attacking tokens you control have double strike. this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - DoubleStrikeAbility.getInstance(), Duration.WhileOnBattlefield, filter + DoubleStrikeAbility.getInstance(), Duration.WhileOnBattlefield, filterAttacking ))); // Whenever one or more tokens you control attack a player, exile the top card of your library. During any turn you attacked with a token, you may play that card. - this.addAbility(new NeyaliSunsVanguardTriggeredAbility()); + Ability ability = new AttacksPlayerWithCreaturesTriggeredAbility(new NeyaliSunsVanguardEffect(), filterControlled, SetTargetPointer.NONE); + ability.addWatcher(new NeyaliSunsVanguardWatcher()); + this.addAbility(ability); } private NeyaliSunsVanguard(final NeyaliSunsVanguard card) { @@ -68,49 +71,11 @@ public final class NeyaliSunsVanguard extends CardImpl { } } -class NeyaliSunsVanguardTriggeredAbility extends TriggeredAbilityImpl { - - NeyaliSunsVanguardTriggeredAbility() { - super(Zone.BATTLEFIELD, new NeyaliSunsVanguardEffect()); - this.addWatcher(new NeyaliSunsVanguardWatcher()); - } - - private NeyaliSunsVanguardTriggeredAbility(final NeyaliSunsVanguardTriggeredAbility ability) { - super(ability); - } - - @Override - public NeyaliSunsVanguardTriggeredAbility copy() { - return new NeyaliSunsVanguardTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DEFENDER_ATTACKED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - return game.getPlayer(event.getTargetId()) != null - && ((DefenderAttackedEvent) event) - .getAttackers(game) - .stream() - .filter(PermanentToken.class::isInstance) - .map(Controllable::getControllerId) - .anyMatch(this::isControlledBy); - } - - @Override - public String getRule() { - return "Whenever one or more tokens you control attack a player, exile the top card of your library. " + - "During any turn you attacked with a token, you may play that card."; - } -} - class NeyaliSunsVanguardEffect extends OneShotEffect { NeyaliSunsVanguardEffect() { super(Outcome.Benefit); + this.setText("exile the top card of your library. During any turn you attacked with a token, you may play that card."); } private NeyaliSunsVanguardEffect(final NeyaliSunsVanguardEffect effect) { diff --git a/Mage.Sets/src/mage/cards/n/NeyamShaiMurad.java b/Mage.Sets/src/mage/cards/n/NeyamShaiMurad.java index f66a570ca28..94a351ee75a 100644 --- a/Mage.Sets/src/mage/cards/n/NeyamShaiMurad.java +++ b/Mage.Sets/src/mage/cards/n/NeyamShaiMurad.java @@ -7,11 +7,15 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.*; -import mage.filter.StaticFilters; +import mage.filter.FilterCard; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.card.OwnerIdPredicate; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInGraveyard; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; import java.util.UUID; @@ -21,6 +25,8 @@ import java.util.UUID; */ public final class NeyamShaiMurad extends CardImpl { + private static final FilterCard filter = new FilterPermanentCard("permanent card from their graveyard"); + public NeyamShaiMurad(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{B}"); @@ -32,10 +38,11 @@ public final class NeyamShaiMurad extends CardImpl { // Rogue Trader -- Whenever Neyam Shai Murad deals combat damage to a player, you may have that player return target permanent card from their graveyard to their hand. // If you do, that player chooses a permanent card in your graveyard, then you put it onto the battlefield under your control. - - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new NeyamShaiMuradEffect(), true, true) - .withFlavorWord("Rogue Trader") - ); //TODO: The first should target when triggered, not on resolution + Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new NeyamShaiMuradEffect(), true, true) + .withFlavorWord("Rogue Trader"); + ability.addTarget(new TargetCardInGraveyard(filter)); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster(true)); + this.addAbility(ability); } private NeyamShaiMurad(final NeyamShaiMurad card) { @@ -67,28 +74,26 @@ class NeyamShaiMuradEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + Object playerId = getValue("damagedPlayer"); Player controller = game.getPlayer(source.getControllerId()); - Cards playerGraveyard = player.getGraveyard(); + if (controller == null || !(playerId instanceof UUID)) { + return false; + } + + Player player = game.getPlayer((UUID) playerId); + Cards cards = new CardsImpl(getTargetPointer().getTargets(game, source)); + cards.retainZone(Zone.GRAVEYARD, game); //verify the target card is still in the graveyard + if (player == null || cards.isEmpty() || !player.moveCards(cards, Zone.HAND, source, game)) { + return false; + } + Cards controllerGraveyard = controller.getGraveyard(); - if (player == null || controller == null || playerGraveyard.isEmpty()) { + FilterCard filter = new FilterPermanentCard("a permanent card in your graveyard"); + filter.add(new OwnerIdPredicate(source.getControllerId())); + TargetCardInGraveyard target = new TargetCardInGraveyard(1, 1, filter, true); + if (!target.choose(Outcome.PutCreatureInPlay, player.getId(), source, game)) { return false; } - - TargetCardInGraveyard target = new TargetCardInGraveyard(StaticFilters.FILTER_CARD_PERMANENT); - - if (!controller.chooseTarget(Outcome.ReturnToHand, playerGraveyard, target, source, game) - || !playerGraveyard.contains(target.getFirstTarget()) - || !player.moveCards(playerGraveyard.get(target.getFirstTarget(), game), Zone.HAND, source, game)) { - return false; - } - - target.clearChosen(); - target.withNotTarget(true); - if (!player.choose(Outcome.PutCreatureInPlay, controllerGraveyard, target, source, game)) { - return false; - } - return controllerGraveyard.contains(target.getFirstTarget()) && controller.moveCards(controllerGraveyard.get(target.getFirstTarget(), game), Zone.BATTLEFIELD, source, game); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/n/NibelheimAflame.java b/Mage.Sets/src/mage/cards/n/NibelheimAflame.java index 43362e5b1fc..996db588a9e 100644 --- a/Mage.Sets/src/mage/cards/n/NibelheimAflame.java +++ b/Mage.Sets/src/mage/cards/n/NibelheimAflame.java @@ -78,6 +78,9 @@ class NibelheimAflameEffect extends OneShotEffect { for (Permanent creature : game.getBattlefield().getActivePermanents( StaticFilters.FILTER_ANOTHER_CREATURE, source.getControllerId(), source, game )) { + if(creature.equals(permanent)){ + continue; + } creature.damage(power, permanent.getId(), source, game); } return true; diff --git a/Mage.Sets/src/mage/cards/n/NiblisOfFrost.java b/Mage.Sets/src/mage/cards/n/NiblisOfFrost.java index 37f28345f74..ab718b6eb53 100644 --- a/Mage.Sets/src/mage/cards/n/NiblisOfFrost.java +++ b/Mage.Sets/src/mage/cards/n/NiblisOfFrost.java @@ -12,10 +12,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * @author fireshoes */ @@ -35,7 +38,7 @@ public final class NiblisOfFrost extends CardImpl { // Whenever you cast an instant or sorcery spell, tap target creature an opponent controls. That creature doesn't untap during its controller's next untap step. Ability ability = new SpellCastControllerTriggeredAbility(new TapTargetEffect(), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("That creature")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NightpackAmbusher.java b/Mage.Sets/src/mage/cards/n/NightpackAmbusher.java index 0287715e60d..2bbf4a83e84 100644 --- a/Mage.Sets/src/mage/cards/n/NightpackAmbusher.java +++ b/Mage.Sets/src/mage/cards/n/NightpackAmbusher.java @@ -2,13 +2,12 @@ package mage.cards.n; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.keyword.FlashAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -53,12 +52,8 @@ public final class NightpackAmbusher extends CardImpl { ))); // At the beginning of your end step, if you didn't cast a spell this turn, create a 2/2 green Wolf creature token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - new CreateTokenEffect(new WolfToken()) - ), NightpackAmbusherCondition.instance, "At the beginning of your end step, " + - "if you didn't cast a spell this turn, create a 2/2 green Wolf creature token." - )); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new CreateTokenEffect(new WolfToken())) + .withInterveningIf(NightpackAmbusherCondition.instance)); } private NightpackAmbusher(final NightpackAmbusher card) { @@ -79,4 +74,9 @@ enum NightpackAmbusherCondition implements Condition { CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); return watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(source.getControllerId()) == 0; } + + @Override + public String toString() { + return "you didn't cast a spell this turn"; + } } diff --git a/Mage.Sets/src/mage/cards/n/NightscapeBattlemage.java b/Mage.Sets/src/mage/cards/n/NightscapeBattlemage.java index 9015c8818c1..7cce905a035 100644 --- a/Mage.Sets/src/mage/cards/n/NightscapeBattlemage.java +++ b/Mage.Sets/src/mage/cards/n/NightscapeBattlemage.java @@ -1,11 +1,10 @@ package mage.cards.n; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.KickedCostCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.KickerAbility; @@ -14,18 +13,21 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetLandPermanent; -/** - * - * @author LoneFox +import java.util.UUID; +/** + * @author LoneFox */ public final class NightscapeBattlemage extends CardImpl { + private static final Condition condition = new KickedCostCondition("{2}{U}"); + private static final Condition condition2 = new KickedCostCondition("{2}{R}"); + public NightscapeBattlemage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.WIZARD); this.power = new MageInt(2); @@ -35,16 +37,16 @@ public final class NightscapeBattlemage extends CardImpl { KickerAbility kickerAbility = new KickerAbility("{2}{U}"); kickerAbility.addKickerCost("{2}{R}"); this.addAbility(kickerAbility); + // When Nightscape Battlemage enters the battlefield, if it was kicked with its {2}{U} kicker, return up to two target nonblack creatures to their owners' hands. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), false); - ability.addTarget(new TargetCreaturePermanent(0, 2, StaticFilters.FILTER_PERMANENT_CREATURES_NON_BLACK, false)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new KickedCostCondition("{2}{U}"), - "When {this} enters, if it was kicked with its {2}{U} kicker, return up to two target nonblack creatures to their owners' hands.")); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), false).withInterveningIf(condition); + ability.addTarget(new TargetPermanent(0, 2, StaticFilters.FILTER_PERMANENT_CREATURES_NON_BLACK)); + this.addAbility(ability); + // When Nightscape Battlemage enters the battlefield, if it was kicked with its {2}{R} kicker, destroy target land. - ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), false); + ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), false).withInterveningIf(condition2); ability.addTarget(new TargetLandPermanent()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new KickedCostCondition("{2}{R}"), - "When {this} enters, if it was kicked with its {2}{R} kicker, destroy target land.")); + this.addAbility(ability); } private NightscapeBattlemage(final NightscapeBattlemage card) { diff --git a/Mage.Sets/src/mage/cards/n/NightsquadCommando.java b/Mage.Sets/src/mage/cards/n/NightsquadCommando.java index 387cf95ce49..def1b83c2d2 100644 --- a/Mage.Sets/src/mage/cards/n/NightsquadCommando.java +++ b/Mage.Sets/src/mage/cards/n/NightsquadCommando.java @@ -3,7 +3,6 @@ package mage.cards.n; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.common.RaidHint; import mage.cards.CardImpl; @@ -29,11 +28,8 @@ public final class NightsquadCommando extends CardImpl { this.toughness = new MageInt(3); // When Nightsquad Commando enters the battlefield, if you attacked this turn, create a 1/1 white Human Soldier creature token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new HumanSoldierToken())), - RaidCondition.instance, "When {this} enters, " + - "if you attacked this turn, create a 1/1 white Human Soldier creature token." - ).addHint(RaidHint.instance), new PlayerAttackedWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new HumanSoldierToken())) + .withInterveningIf(RaidCondition.instance).addHint(RaidHint.instance), new PlayerAttackedWatcher()); } private NightsquadCommando(final NightsquadCommando card) { diff --git a/Mage.Sets/src/mage/cards/n/NihilisticGlee.java b/Mage.Sets/src/mage/cards/n/NihilisticGlee.java index 8975f9cd2f5..05645305410 100644 --- a/Mage.Sets/src/mage/cards/n/NihilisticGlee.java +++ b/Mage.Sets/src/mage/cards/n/NihilisticGlee.java @@ -7,7 +7,7 @@ import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.costs.common.PayLifeCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; @@ -15,7 +15,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.Zone; import mage.target.common.TargetOpponent; import java.util.UUID; @@ -39,15 +38,12 @@ public final class NihilisticGlee extends CardImpl { this.addAbility(ability); // Hellbent - {1}, Pay 2 life: Draw a card. Activate this ability only if you have no cards in hand. - ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, + ability = new ActivateIfConditionActivatedAbility( new DrawCardSourceControllerEffect(1), - new GenericManaCost(1), - HellbentCondition.instance + new GenericManaCost(1), HellbentCondition.instance ); ability.addCost(new PayLifeCost(2)); - ability.setAbilityWord(AbilityWord.HELLBENT); - this.addAbility(ability); + this.addAbility(ability.setAbilityWord(AbilityWord.HELLBENT)); } private NihilisticGlee(final NihilisticGlee card) { diff --git a/Mage.Sets/src/mage/cards/n/Nihilith.java b/Mage.Sets/src/mage/cards/n/Nihilith.java index e612be96fd2..144dfcff9d9 100644 --- a/Mage.Sets/src/mage/cards/n/Nihilith.java +++ b/Mage.Sets/src/mage/cards/n/Nihilith.java @@ -1,51 +1,42 @@ - package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.PutCardIntoGraveFromAnywhereAllTriggeredAbility; import mage.abilities.condition.common.SuspendedCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; import mage.abilities.keyword.FearAbility; import mage.abilities.keyword.SuspendAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SetTargetPointer; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.counters.CounterType; -import mage.filter.FilterCard; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class Nihilith extends CardImpl { public Nihilith(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); this.subtype.add(SubType.HORROR); this.power = new MageInt(4); this.toughness = new MageInt(4); // Fear this.addAbility(FearAbility.getInstance()); - + // Suspend 7-{1}{B} this.addAbility(new SuspendAbility(7, new ManaCostsImpl<>("{1}{B}"), this, false)); - + // Whenever a card is put into an opponent's graveyard from anywhere, if Nihilith is suspended, you may remove a time counter from Nihilith. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new PutCardIntoGraveFromAnywhereAllTriggeredAbility(Zone.EXILED, new RemoveCounterSourceEffect(CounterType.TIME.createInstance()), true, - new FilterCard(), TargetController.OPPONENT, SetTargetPointer.NONE), - SuspendedCondition.instance, - "Whenever a card is put into an opponent's graveyard from anywhere, if {this} is suspended, you may remove a time counter from {this}." - )); - + this.addAbility(new PutCardIntoGraveFromAnywhereAllTriggeredAbility( + Zone.EXILED, new RemoveCounterSourceEffect(CounterType.TIME.createInstance()).setText("remove a time counter from this card"), true, + StaticFilters.FILTER_CARD_A, TargetController.OPPONENT, SetTargetPointer.NONE + ).withInterveningIf(SuspendedCondition.instance)); } private Nihilith(final Nihilith card) { diff --git a/Mage.Sets/src/mage/cards/n/NikoLightOfHope.java b/Mage.Sets/src/mage/cards/n/NikoLightOfHope.java index 3422ccb86fc..654f6be857e 100644 --- a/Mage.Sets/src/mage/cards/n/NikoLightOfHope.java +++ b/Mage.Sets/src/mage/cards/n/NikoLightOfHope.java @@ -1,9 +1,7 @@ package mage.cards.n; -import java.util.UUID; - -import mage.abilities.Ability; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; @@ -14,9 +12,9 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; import mage.cards.Card; -import mage.constants.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; @@ -25,17 +23,18 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.ShardToken; import mage.players.Player; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.targetpointer.FixedTarget; import mage.util.functions.EmptyCopyApplier; +import java.util.UUID; + /** - * * @author Grath */ public final class NikoLightOfHope extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("nonlegendary creature you control"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("nonlegendary creature you control"); static { filter.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); @@ -43,7 +42,7 @@ public final class NikoLightOfHope extends CardImpl { public NikoLightOfHope(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{U}"); - + this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); @@ -56,7 +55,7 @@ public final class NikoLightOfHope extends CardImpl { // {2}, {T}: Exile target nonlegendary creature you control. Shards you control become copies of it until the beginning of the next end step. Return it to the battlefield under its owner's control at the beginning of the next end step. Ability ability = new SimpleActivatedAbility(new NikoLightOfHopeEffect(), new GenericManaCost(2)); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetControlledCreaturePermanent(1, 1, filter, false)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } @@ -90,26 +89,27 @@ class NikoLightOfHopeEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent != null && controller != null) { - if (permanent.moveToExile(source.getSourceId(), "Niko, Light of Hope", source, game)) { - FilterPermanent filter = new FilterPermanent("shards"); - filter.add(SubType.SHARD.getPredicate()); - for (Permanent copyTo : game.getBattlefield().getAllActivePermanents(filter, controller.getId(), game)) { - game.copyPermanent(Duration.UntilNextEndStep, permanent, copyTo.getId(), source, new EmptyCopyApplier()); - } - ExileZone exile = game.getExile().getExileZone(source.getSourceId()); - if (exile != null && !exile.isEmpty()) { - Card card = game.getCard(permanent.getId()); - if (card != null) { - Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false); - effect.setTargetPointer(new FixedTarget(card.getId())); - game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source); - } - } - return true; - } + if (permanent == null || controller == null + || !permanent.moveToExile(source.getSourceId(), "Niko, Light of Hope", source, game)) { + return false; } - return false; + FilterPermanent filter = new FilterPermanent("shards"); + filter.add(SubType.SHARD.getPredicate()); + for (Permanent copyTo : game.getBattlefield().getAllActivePermanents(filter, controller.getId(), game)) { + game.copyPermanent(Duration.UntilNextEndStep, permanent, copyTo.getId(), source, new EmptyCopyApplier()); + } + ExileZone exile = game.getExile().getExileZone(source.getSourceId()); + if (exile == null || exile.isEmpty()) { + return true; + } + Card card = game.getCard(permanent.getId()); + if (card == null) { + return true; + } + Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false); + effect.setTargetPointer(new FixedTarget(card.getId())); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source); + return true; } } diff --git a/Mage.Sets/src/mage/cards/n/NimDevourer.java b/Mage.Sets/src/mage/cards/n/NimDevourer.java index 62146fa374c..4f014a147dc 100644 --- a/Mage.Sets/src/mage/cards/n/NimDevourer.java +++ b/Mage.Sets/src/mage/cards/n/NimDevourer.java @@ -5,7 +5,7 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.dynamicvalue.common.ArtifactYouControlCount; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; @@ -14,7 +14,10 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.hint.common.ArtifactYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; import mage.filter.StaticFilters; import java.util.UUID; @@ -37,10 +40,9 @@ public final class NimDevourer extends CardImpl { ); // {B}{B}: Return Nim Devourer from your graveyard to the battlefield, then sacrifice a creature. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility(Zone.GRAVEYARD, - new ReturnSourceFromGraveyardToBattlefieldEffect(false, false), - new ManaCostsImpl<>("{B}{B}"), - new IsStepCondition(PhaseStep.UPKEEP), null); + Ability ability = new ActivateIfConditionActivatedAbility( + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(false, false), + new ManaCostsImpl<>("{B}{B}"), IsStepCondition.getMyUpkeep()); ability.addEffect(new SacrificeControllerEffect(StaticFilters.FILTER_PERMANENT_A_CREATURE, 1, ", then")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NimbleTrapfinder.java b/Mage.Sets/src/mage/cards/n/NimbleTrapfinder.java index 99ac134be42..c9c4a5ecf94 100644 --- a/Mage.Sets/src/mage/cards/n/NimbleTrapfinder.java +++ b/Mage.Sets/src/mage/cards/n/NimbleTrapfinder.java @@ -3,12 +3,10 @@ package mage.cards.n; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.FullPartyCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.decorator.ConditionalRestrictionEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; @@ -16,9 +14,13 @@ import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; import mage.abilities.hint.common.PartyCountHint; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.WatcherScope; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; @@ -51,15 +53,13 @@ public final class NimbleTrapfinder extends CardImpl { )).addHint(NimbleTrapfinderCondition.getHint()), new NimbleTrapfinderWatcher()); // At the beginning of combat on your turn, if you have a full party, creatures you control gain "Whenever this creature deals combat damage to a player, draw a card" until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - new GainAbilityAllEffect(new DealsCombatDamageToAPlayerTriggeredAbility( - new DrawCardSourceControllerEffect(1), false - ), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES) - ), FullPartyCondition.instance, "At the beginning of combat on your turn, " + - "if you have a full party, creatures you control gain " + - "\"Whenever this creature deals combat damage to a player, draw a card\" until end of turn." - ).addHint(PartyCountHint.instance)); + this.addAbility(new BeginningOfCombatTriggeredAbility(new GainAbilityAllEffect( + new DealsCombatDamageToAPlayerTriggeredAbility( + new DrawCardSourceControllerEffect(1), false + ), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES + ).setText("creatures you control gain \"Whenever this creature " + + "deals combat damage to a player, draw a card\" until end of turn")) + .withInterveningIf(FullPartyCondition.instance).addHint(PartyCountHint.instance)); } private NimbleTrapfinder(final NimbleTrapfinder card) { diff --git a/Mage.Sets/src/mage/cards/n/NineLivesFamiliar.java b/Mage.Sets/src/mage/cards/n/NineLivesFamiliar.java index 0fcd7ecfcdc..c6502d09e93 100644 --- a/Mage.Sets/src/mage/cards/n/NineLivesFamiliar.java +++ b/Mage.Sets/src/mage/cards/n/NineLivesFamiliar.java @@ -7,7 +7,6 @@ import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldWithCounterEffect; @@ -20,18 +19,18 @@ import mage.constants.SubType; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.util.CardUtil; import java.util.UUID; /** - * * @author ciaconna007 */ public final class NineLivesFamiliar extends CardImpl { public NineLivesFamiliar(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); - + this.subtype.add(SubType.CAT); this.power = new MageInt(1); this.toughness = new MageInt(1); @@ -44,15 +43,10 @@ public final class NineLivesFamiliar extends CardImpl { )); // When this creature dies, if it had a revival counter on it, return it to the battlefield with one fewer revival counter on it at the beginning of the next end step. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new DiesSourceTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( - new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new NineLivesFamiliarEffect()) - )), - NineLivesFamiliarCondition.instance, - "When this creature dies, if it had a revival counter on it, " - + "return it to the battlefield with one fewer revival counter on it " - + "at the beginning of the next end step." - )); + this.addAbility(new DiesSourceTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( + new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new NineLivesFamiliarEffect()) + ).setText("return it to the battlefield with one fewer revival counter " + + "on it at the beginning of the next end step")).withInterveningIf(NineLivesFamiliarCondition.instance)); } private NineLivesFamiliar(final NineLivesFamiliar card) { @@ -70,8 +64,15 @@ enum NineLivesFamiliarCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) source.getEffects().get(0).getValue("permanentLeftBattlefield"); - return permanent != null && permanent.getCounters(game).getCount(CounterType.REVIVAL) > 0; + return CardUtil + .getEffectValueFromAbility(source, "permanentLeftBattlefield", Permanent.class) + .filter(permanent -> permanent.getCounters(game).getCount(CounterType.REVIVAL) > 0) + .isPresent(); + } + + @Override + public String toString() { + return "it had a revival counter on it"; } } diff --git a/Mage.Sets/src/mage/cards/n/NissaVastwoodSeer.java b/Mage.Sets/src/mage/cards/n/NissaVastwoodSeer.java index dc7261ef512..14fac45f978 100644 --- a/Mage.Sets/src/mage/cards/n/NissaVastwoodSeer.java +++ b/Mage.Sets/src/mage/cards/n/NissaVastwoodSeer.java @@ -1,13 +1,10 @@ - package mage.cards.n; -import java.util.UUID; import mage.MageInt; -import mage.constants.Pronoun; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.LandfallAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ExileAndReturnSourceEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.keyword.TransformAbility; @@ -18,20 +15,27 @@ import mage.filter.FilterCard; import mage.filter.common.FilterLandPermanent; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author emerald000 */ public final class NissaVastwoodSeer extends CardImpl { - + private static final FilterCard filter = new FilterCard("basic Forest card"); + static { filter.add(SuperType.BASIC.getPredicate()); filter.add(SubType.FOREST.getPredicate()); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterLandPermanent("you control seven or more lands"), + ComparisonType.MORE_THAN, 6, true + ); + public NissaVastwoodSeer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.ELF); this.subtype.add(SubType.SCOUT); @@ -41,14 +45,15 @@ public final class NissaVastwoodSeer extends CardImpl { this.secondSideCardClazz = mage.cards.n.NissaSageAnimist.class; // When Nissa, Vastwood Seer enters the battlefield, you may search your library for a basic Forest card, reveal it, put it into your hand, then shuffle your library. - this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true), true)); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true), true + )); // Whenever a land you control enters, if you control seven or more lands, exile Nissa, then return her to the battlefield transformed under her owner's control. this.addAbility(new TransformAbility()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldControlledTriggeredAbility(new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED,Pronoun.SHE), new FilterLandPermanent()), - new PermanentsOnTheBattlefieldCondition(new FilterLandPermanent(), ComparisonType.MORE_THAN, 6, true), - "Whenever a land you control enters, if you control seven or more lands, exile {this}, then return her to the battlefield transformed under her owner's control.")); + this.addAbility(new LandfallAbility(new ExileAndReturnSourceEffect( + PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.SHE + )).withInterveningIf(condition).setAbilityWord(null)); } private NissaVastwoodSeer(final NissaVastwoodSeer card) { diff --git a/Mage.Sets/src/mage/cards/n/NissasJudgment.java b/Mage.Sets/src/mage/cards/n/NissasJudgment.java index 55e9a5bbf26..288b4560ca5 100644 --- a/Mage.Sets/src/mage/cards/n/NissasJudgment.java +++ b/Mage.Sets/src/mage/cards/n/NissasJudgment.java @@ -1,6 +1,5 @@ package mage.cards.n; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -13,11 +12,12 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; import mage.target.targetpointer.SecondTargetPointer; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class NissasJudgment extends CardImpl { @@ -32,7 +32,7 @@ public final class NissasJudgment extends CardImpl { // Choose up to one target creature an opponent controls. Each creature you control with a +1/+1 counter on it deals damage equal to its power to that creature. effect = new NissasJudgmentEffect(); effect.setTargetPointer(new SecondTargetPointer()); // First target is used by Support - getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, false)); + getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent(0, 1)); getSpellAbility().addEffect(effect); } diff --git a/Mage.Sets/src/mage/cards/n/NivMizzetVisionary.java b/Mage.Sets/src/mage/cards/n/NivMizzetVisionary.java index 226519cb674..05bda5060ee 100644 --- a/Mage.Sets/src/mage/cards/n/NivMizzetVisionary.java +++ b/Mage.Sets/src/mage/cards/n/NivMizzetVisionary.java @@ -1,21 +1,21 @@ package mage.cards.n; -import java.util.Objects; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.SourceDealsNoncombatDamageToOpponentTriggeredAbility; import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; -import mage.constants.*; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; -import mage.game.events.GameEvent; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; + +import java.util.UUID; /** * @@ -40,7 +40,7 @@ public final class NivMizzetVisionary extends CardImpl { this.addAbility(new SimpleStaticAbility(effect)); // Whenever a source you control deals noncombat damage to an opponent, you draw that many cards. - this.addAbility(new NivMizzetVisionaryAbility()); + this.addAbility(new SourceDealsNoncombatDamageToOpponentTriggeredAbility(new DrawCardSourceControllerEffect(SavedDamageValue.MANY, true))); } private NivMizzetVisionary(final NivMizzetVisionary card) { @@ -52,41 +52,3 @@ public final class NivMizzetVisionary extends CardImpl { return new NivMizzetVisionary(this); } } - -class NivMizzetVisionaryAbility extends TriggeredAbilityImpl { - - NivMizzetVisionaryAbility() { - super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(SavedDamageValue.MANY)); - } - - private NivMizzetVisionaryAbility(final NivMizzetVisionaryAbility ability) { - super(ability); - } - - @Override - public NivMizzetVisionaryAbility copy() { - return new NivMizzetVisionaryAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; - if (damageEvent.isCombatDamage() - || !game.getOpponents(controllerId).contains(event.getTargetId()) - || !Objects.equals(controllerId, game.getControllerId(event.getSourceId()))) { - return false; - } - getAllEffects().setValue("damage", event.getAmount()); - return true; - } - - @Override - public String getRule() { - return "Whenever a source you control deals noncombat damage to an opponent, you draw that many cards."; - } -} diff --git a/Mage.Sets/src/mage/cards/n/NobleHeritage.java b/Mage.Sets/src/mage/cards/n/NobleHeritage.java index 34827c2dc04..39734f0f957 100644 --- a/Mage.Sets/src/mage/cards/n/NobleHeritage.java +++ b/Mage.Sets/src/mage/cards/n/NobleHeritage.java @@ -14,7 +14,6 @@ import mage.constants.*; import mage.counters.CounterType; import mage.filter.FilterPlayer; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.other.PlayerIdPredicate; import mage.game.Game; import mage.game.events.GameEvent; @@ -25,7 +24,7 @@ import mage.target.common.TargetControlledCreaturePermanent; import java.util.ArrayList; import java.util.List; -import java.util.Objects; +import java.util.Optional; import java.util.UUID; /** @@ -40,7 +39,8 @@ public final class NobleHeritage extends CardImpl { this.subtype.add(SubType.BACKGROUND); // Commander creatures you own have “When this creature enters the battlefield and at the beginning of your upkeep, each player may put two +1/+1 counters on a creature they control. For each opponent who does, you gain protection from that player until your next turn.” (You can’t be targeted, dealt damage, or enchanted by anything controlled by that player.) - this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect(new NobleHeritageTriggeredAbility(), Duration.WhileOnBattlefield, + this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( + new NobleHeritageTriggeredAbility(), Duration.WhileOnBattlefield, StaticFilters.FILTER_CREATURES_OWNED_COMMANDER ))); } @@ -122,39 +122,44 @@ class NobleHeritageEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - List players = new ArrayList<>(); - List creatures = new ArrayList<>(); - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - if (player.chooseUse(outcome, "Put two +1/+1 counters on a creature you control?", source, game)) { - Target target = new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("a creature you control (to add two +1/+1 counters on it)")); - if (player.choose(outcome, target, source, game)) { - creatures.add(target.getFirstTarget()); - players.add(player.getId()); - } - - } - } - } - for (UUID creatureId : creatures) { - Permanent creature = game.getPermanent(creatureId); - if (creature != null) { - creature.addCounters(CounterType.P1P1.createInstance(2), creature.getControllerId(), source, game); - } - } - for (UUID playerId : players) { - if (!Objects.equals(playerId, source.getControllerId())) { - FilterPlayer filter = new FilterPlayer(); - filter.add(new PlayerIdPredicate(playerId)); - game.addEffect(new GainAbilityControllerEffect( - new ProtectionAbility(filter), Duration.UntilYourNextTurn - ), source); - } - } - return true; + if (controller == null) { + return false; } - return false; + List players = new ArrayList<>(); + List creatures = new ArrayList<>(); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player == null || !player.chooseUse(outcome, "Put two +1/+1 counters on a creature you control?", source, game)) { + continue; + } + Target target = new TargetControlledCreaturePermanent(0, 1); + target.withNotTarget(true); + target.withChooseHint("to add counters to"); + player.choose(outcome, target, source, game); + Optional.ofNullable(target) + .map(Target::getFirstTarget) + .map(game::getPermanent) + .ifPresent(permanent -> { + creatures.add(permanent.getId()); + players.add(player.getId()); + }); + } + for (UUID creatureId : creatures) { + Permanent creature = game.getPermanent(creatureId); + if (creature != null) { + creature.addCounters(CounterType.P1P1.createInstance(2), creature.getControllerId(), source, game); + } + } + for (UUID playerId : players) { + if (source.isControlledBy(playerId)) { + continue; + } + FilterPlayer filter = new FilterPlayer(); + filter.add(new PlayerIdPredicate(playerId)); + game.addEffect(new GainAbilityControllerEffect( + new ProtectionAbility(filter), Duration.UntilYourNextTurn + ), source); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/n/NobleQuarry.java b/Mage.Sets/src/mage/cards/n/NobleQuarry.java index b80487bf4bf..4e343e1934c 100644 --- a/Mage.Sets/src/mage/cards/n/NobleQuarry.java +++ b/Mage.Sets/src/mage/cards/n/NobleQuarry.java @@ -1,7 +1,6 @@ package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -14,9 +13,10 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AttachmentType; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** * @@ -35,7 +35,7 @@ public final class NobleQuarry extends CardImpl { this.addAbility(new BestowAbility(this, "{5}{G}")); // All creatures able to block Noble Quarry or enchanted creature do so. Effect effect = new MustBeBlockedByAllSourceEffect(Duration.WhileOnBattlefield); - effect.setText("All creatures able to block Noble Quarry"); + effect.setText("All creatures able to block {this}"); Ability ability = new SimpleStaticAbility(effect); effect = new MustBeBlockedByAllAttachedEffect(Duration.WhileOnBattlefield, AttachmentType.AURA); effect.setText("or enchanted creature do so"); diff --git a/Mage.Sets/src/mage/cards/n/NoggleHedgeMage.java b/Mage.Sets/src/mage/cards/n/NoggleHedgeMage.java index 0a274af4c38..2abf9a9d54b 100644 --- a/Mage.Sets/src/mage/cards/n/NoggleHedgeMage.java +++ b/Mage.Sets/src/mage/cards/n/NoggleHedgeMage.java @@ -1,12 +1,10 @@ - package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.TapTargetEffect; import mage.cards.CardImpl; @@ -14,28 +12,26 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterLandPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPermanent; import mage.target.TargetPermanent; import mage.target.common.TargetPlayerOrPlaneswalker; +import java.util.UUID; + /** - * * @author jeffwadsworth - * */ public final class NoggleHedgeMage extends CardImpl { - private static final FilterLandPermanent filter = new FilterLandPermanent(); - private static final FilterLandPermanent filter2 = new FilterLandPermanent(); - - static { - filter.add(SubType.ISLAND.getPredicate()); - filter2.add(SubType.MOUNTAIN.getPredicate()); - } - - private static final String rule = "When {this} enters, if you control two or more Islands, you may tap two target permanents."; - private static final String rule2 = "When {this} enters, if you control two or more Mountains, you may have {this} deal 2 damage to target player or planeswalker."; + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.ISLAND, "you control two or more Islands"), + ComparisonType.MORE_THAN, 1 + ); + private static final Condition condition2 = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.MOUNTAIN, "you control two or more Mountains"), + ComparisonType.MORE_THAN, 1 + ); public NoggleHedgeMage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U/R}"); @@ -46,14 +42,14 @@ public final class NoggleHedgeMage extends CardImpl { this.toughness = new MageInt(2); // When Noggle Hedge-Mage enters the battlefield, if you control two or more Islands, you may tap two target permanents. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new TapTargetEffect(), true), new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1), rule); - ability.addTarget(new TargetPermanent(2, new FilterPermanent())); + Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect(), true).withInterveningIf(condition); + ability.addTarget(new TargetPermanent(2, StaticFilters.FILTER_PERMANENTS)); this.addAbility(ability); // When Noggle Hedge-Mage enters the battlefield, if you control two or more Mountains, you may have Noggle Hedge-Mage deal 2 damage to target player. - Ability ability2 = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2), true), new PermanentsOnTheBattlefieldCondition(filter2, ComparisonType.MORE_THAN, 1), rule2); - ability2.addTarget(new TargetPlayerOrPlaneswalker()); - this.addAbility(ability2); + ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2), true).withInterveningIf(condition2); + ability.addTarget(new TargetPlayerOrPlaneswalker()); + this.addAbility(ability); } private NoggleHedgeMage(final NoggleHedgeMage card) { diff --git a/Mage.Sets/src/mage/cards/n/NogiDracoZealot.java b/Mage.Sets/src/mage/cards/n/NogiDracoZealot.java index 3c4d704ea80..226d1b4b1b5 100644 --- a/Mage.Sets/src/mage/cards/n/NogiDracoZealot.java +++ b/Mage.Sets/src/mage/cards/n/NogiDracoZealot.java @@ -1,12 +1,10 @@ package mage.cards.n; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; @@ -28,11 +26,10 @@ import java.util.UUID; */ public final class NogiDracoZealot extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent(); + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.DRAGON, "you control three or more Dragons"); private static final FilterCard filter2 = new FilterCard("Dragon spells"); static { - filter.add(SubType.DRAGON.getPredicate()); filter2.add(SubType.DRAGON.getPredicate()); } @@ -54,16 +51,12 @@ public final class NogiDracoZealot extends CardImpl { // Whenever Nogi, Draco-Zealot attacks, if you control three or more Dragons, until end // of turn, Nogi becomes a Dragon with base power and toughness 5/5 and gains flying. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new BecomesCreatureSourceEffect( - new CreatureToken(5, 5, "Dragon with base power and toughness 5/5 and gains flying") - .withSubType(SubType.DRAGON) - .withAbility(FlyingAbility.getInstance()), - CardType.CREATURE, Duration.EndOfTurn), false - ), condition, "Whenever {this} attacks, if you control three or more Dragons, until end of turn, " + - "{this} becomes a Dragon with base power and toughness 5/5 and gains flying" - ); - this.addAbility(ability.addHint(hint)); + this.addAbility(new AttacksTriggeredAbility(new BecomesCreatureSourceEffect( + new CreatureToken( + 5, 5, "Dragon with base power and toughness 5/5 and gains flying" + ).withSubType(SubType.DRAGON).withAbility(FlyingAbility.getInstance()), + CardType.CREATURE, Duration.EndOfTurn + ), false).withInterveningIf(condition).addHint(hint)); } private NogiDracoZealot(final NogiDracoZealot card) { diff --git a/Mage.Sets/src/mage/cards/n/NomadDecoy.java b/Mage.Sets/src/mage/cards/n/NomadDecoy.java index ae6c27590a6..dae84f6f8d9 100644 --- a/Mage.Sets/src/mage/cards/n/NomadDecoy.java +++ b/Mage.Sets/src/mage/cards/n/NomadDecoy.java @@ -2,11 +2,11 @@ package mage.cards.n; import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.ThresholdCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.TapTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -37,7 +37,7 @@ public final class NomadDecoy extends CardImpl { this.addAbility(ability); // Threshold - {W}{W}, {T}: Tap two target creatures. Activate this ability only if seven or more cards are in your graveyard. - Ability thresholdAbility = new ConditionalActivatedAbility( + Ability thresholdAbility = new ActivateIfConditionActivatedAbility( new TapTargetEffect(), new ManaCostsImpl<>("{W}{W}"), ThresholdCondition.instance ); thresholdAbility.addCost(new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/n/NomadStadium.java b/Mage.Sets/src/mage/cards/n/NomadStadium.java index 5bca3530f0a..67b7d234c84 100644 --- a/Mage.Sets/src/mage/cards/n/NomadStadium.java +++ b/Mage.Sets/src/mage/cards/n/NomadStadium.java @@ -5,7 +5,7 @@ import mage.abilities.condition.common.ThresholdCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.mana.WhiteManaAbility; @@ -30,7 +30,7 @@ public final class NomadStadium extends CardImpl { this.addAbility(manaAbility); // Threshold - {W}, {tap}, Sacrifice Nomad Stadium: You gain 4 life. Activate this ability only if seven or more cards are in your graveyard. - Ability thresholdAbility = new ConditionalActivatedAbility( + Ability thresholdAbility = new ActivateIfConditionActivatedAbility( new GainLifeEffect(4), new ManaCostsImpl<>("{W}"), ThresholdCondition.instance ); thresholdAbility.addCost(new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/n/NoosegrafMob.java b/Mage.Sets/src/mage/cards/n/NoosegrafMob.java index 319f669d11f..2bf724ef143 100644 --- a/Mage.Sets/src/mage/cards/n/NoosegrafMob.java +++ b/Mage.Sets/src/mage/cards/n/NoosegrafMob.java @@ -1,7 +1,6 @@ package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; @@ -13,14 +12,16 @@ import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.ZombieToken; import mage.players.Player; +import java.util.UUID; + /** * * @author fireshoes @@ -54,7 +55,7 @@ class NoosegrafMobEffect extends OneShotEffect { NoosegrafMobEffect() { super(Outcome.Benefit); - staticText = "remove a +1/+1 counter from Noosegraf Mob. If you do, create a 2/2 black Zombie creature token"; + staticText = "remove a +1/+1 counter from {this}. If you do, create a 2/2 black Zombie creature token"; } private NoosegrafMobEffect(final NoosegrafMobEffect effect) { diff --git a/Mage.Sets/src/mage/cards/n/NornsDecree.java b/Mage.Sets/src/mage/cards/n/NornsDecree.java index f3b013b4745..b41b1a3d6f8 100644 --- a/Mage.Sets/src/mage/cards/n/NornsDecree.java +++ b/Mage.Sets/src/mage/cards/n/NornsDecree.java @@ -1,37 +1,41 @@ package mage.cards.n; -import java.util.UUID; - +import mage.abilities.Ability; import mage.abilities.common.CombatDamageDealtToYouTriggeredAbility; import mage.abilities.common.PlayerAttacksTriggeredAbility; -import mage.abilities.condition.common.AttackedPlayersPoisonedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.effects.common.DrawCardTargetEffect; import mage.abilities.effects.common.counter.AddPoisonCounterTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.combat.CombatGroup; + +import java.util.Objects; +import java.util.UUID; /** - * * @author alexander-novo */ public final class NornsDecree extends CardImpl { public NornsDecree(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[] { CardType.ENCHANTMENT }, "{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); // Whenever one or more creatures an opponent controls deal combat damage to you, that opponent gets a poison counter. - this.addAbility(new CombatDamageDealtToYouTriggeredAbility(Zone.BATTLEFIELD, + this.addAbility(new CombatDamageDealtToYouTriggeredAbility( + Zone.BATTLEFIELD, new AddPoisonCounterTargetEffect(1).setText("that opponent gets a poison counter"), - true, false)); + true, false + )); // Whenever a player attacks, if one or more players being attacked are poisoned, the attacking player draws a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new PlayerAttacksTriggeredAbility(new DrawCardTargetEffect(1), true), - AttackedPlayersPoisonedCondition.instance, - "Whenever a player attacks, if one or more players being attacked are poisoned, the attacking player draws a card.")); + this.addAbility(new PlayerAttacksTriggeredAbility( + new DrawCardTargetEffect(1).setText("the attacking player draws a card"), true + ).withInterveningIf(NornsDecreeCondition.instance)); } private NornsDecree(final NornsDecree card) { @@ -44,3 +48,25 @@ public final class NornsDecree extends CardImpl { } } + +enum NornsDecreeCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return game.getCombat() + .getGroups() + .stream() + .map(CombatGroup::getDefenderId) + .filter(Objects::nonNull) + .distinct() + .map(game::getPlayer) + .filter(Objects::nonNull) + .anyMatch(player -> player.getCountersCount(CounterType.POISON) > 0); + } + + @Override + public String toString() { + return "one or more players being attacked are poisoned"; + } +} diff --git a/Mage.Sets/src/mage/cards/n/Norritt.java b/Mage.Sets/src/mage/cards/n/Norritt.java index 6d00e0954ba..c76919d7ec1 100644 --- a/Mage.Sets/src/mage/cards/n/Norritt.java +++ b/Mage.Sets/src/mage/cards/n/Norritt.java @@ -1,6 +1,5 @@ package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -10,7 +9,7 @@ import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.BeforeAttackersAreDeclaredCondition; import mage.abilities.condition.common.TargetAttackedThisTurnCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.UntapTargetEffect; @@ -23,11 +22,13 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.permanent.ControlledFromStartOfControllerTurnPredicate; import mage.game.Game; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author MTGfan & L_J */ public final class Norritt extends CardImpl { @@ -38,13 +39,12 @@ public final class Norritt extends CardImpl { filterBlue.add(new ColorPredicate(ObjectColor.BLUE)); } - private static final FilterCreaturePermanent filterCreature = new FilterCreaturePermanent("non-Wall creature"); + private static final FilterCreaturePermanent filterCreature = new FilterCreaturePermanent("non-Wall creature the active player has controlled continuously since the beginning of the turn"); static { filterCreature.add(Predicates.not(SubType.WALL.getPredicate())); filterCreature.add(new ControlledFromStartOfControllerTurnPredicate()); filterCreature.add(TargetController.ACTIVE.getControllerPredicate()); - filterCreature.setMessage("non-Wall creature the active player has controlled continuously since the beginning of the turn."); } public Norritt(UUID ownerId, CardSetInfo setInfo) { @@ -56,17 +56,18 @@ public final class Norritt extends CardImpl { // {T}: Untap target blue creature. Ability ability1 = new SimpleActivatedAbility(new UntapTargetEffect(), new TapSourceCost()); - ability1.addTarget(new TargetCreaturePermanent(filterBlue)); + ability1.addTarget(new TargetPermanent(filterBlue)); this.addAbility(ability1); // {T}: Choose target non-Wall creature the active player has controlled continuously since the beginning of the turn. That creature attacks this turn if able. If it doesn't, destroy it at the beginning of the next end step. Activate this ability only before attackers are declared. - Ability ability2 = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new AttacksIfAbleTargetEffect(Duration.EndOfTurn), - new TapSourceCost(), BeforeAttackersAreDeclaredCondition.instance, - "{T}: Choose target non-Wall creature the active player has controlled continuously since the beginning of the turn. " - + "That creature attacks this turn if able. Destroy it at the beginning of the next end step if it didn't attack this turn. " - + "Activate only before attackers are declared."); + Ability ability2 = new ActivateIfConditionActivatedAbility( + new AttacksIfAbleTargetEffect(Duration.EndOfTurn) + .setText("choose target non-Wall creature the active player has controlled continuously " + + "since the beginning of the turn. That creature attacks this turn if able"), + new TapSourceCost(), BeforeAttackersAreDeclaredCondition.instance + ); ability2.addEffect(new NorrittDelayedDestroyEffect()); - ability2.addTarget(new TargetCreaturePermanent(filterCreature)); + ability2.addTarget(new TargetPermanent(filterCreature)); this.addAbility(ability2); } @@ -85,7 +86,7 @@ class NorrittDelayedDestroyEffect extends OneShotEffect { NorrittDelayedDestroyEffect() { super(Outcome.Detriment); - this.staticText = "If it doesn't, destroy it at the beginning of the next end step"; + this.staticText = "Destroy it at the beginning of the next end step if it didn't attack this turn"; } private NorrittDelayedDestroyEffect(final NorrittDelayedDestroyEffect effect) { diff --git a/Mage.Sets/src/mage/cards/n/NorwoodPriestess.java b/Mage.Sets/src/mage/cards/n/NorwoodPriestess.java index 671936209f3..dcba5817404 100644 --- a/Mage.Sets/src/mage/cards/n/NorwoodPriestess.java +++ b/Mage.Sets/src/mage/cards/n/NorwoodPriestess.java @@ -1,7 +1,5 @@ - package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -12,17 +10,18 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.ColorPredicate; +import java.util.UUID; + /** - * * @author fireshoes */ public final class NorwoodPriestess extends CardImpl { - private static final FilterCreatureCard filter = new FilterCreatureCard("a green creature card"); + private static final FilterCard filter = new FilterCreatureCard("a green creature card"); static { filter.add(new ColorPredicate(ObjectColor.GREEN)); @@ -37,10 +36,8 @@ public final class NorwoodPriestess extends CardImpl { // {tap}: You may put a green creature card from your hand onto the battlefield. Activate this ability only during your turn, before attackers are declared. this.addAbility(new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new PutCardFromHandOntoBattlefieldEffect(filter), - new TapSourceCost(), - MyTurnBeforeAttackersDeclaredCondition.instance + new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance )); } diff --git a/Mage.Sets/src/mage/cards/n/NosyGoblin.java b/Mage.Sets/src/mage/cards/n/NosyGoblin.java index aef639a100d..5ff6ce49e53 100644 --- a/Mage.Sets/src/mage/cards/n/NosyGoblin.java +++ b/Mage.Sets/src/mage/cards/n/NosyGoblin.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.card.FaceDownPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class NosyGoblin extends CardImpl { // {tap}, Sacrifice Nosy Goblin: Destroy target face-down creature. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NotoriousAssassin.java b/Mage.Sets/src/mage/cards/n/NotoriousAssassin.java index 95def99ef00..88ec18e7f11 100644 --- a/Mage.Sets/src/mage/cards/n/NotoriousAssassin.java +++ b/Mage.Sets/src/mage/cards/n/NotoriousAssassin.java @@ -14,8 +14,11 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author LoneFox @@ -34,7 +37,7 @@ public final class NotoriousAssassin extends CardImpl { Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(true), new ManaCostsImpl<>("{2}{B}")); ability.addCost(new TapSourceCost()); ability.addCost(new DiscardCardCost()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + ability.addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NovaHellkite.java b/Mage.Sets/src/mage/cards/n/NovaHellkite.java new file mode 100644 index 00000000000..57478a13c6c --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NovaHellkite.java @@ -0,0 +1,53 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.WarpAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NovaHellkite extends CardImpl { + + public NovaHellkite(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + + this.subtype.add(SubType.DRAGON); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // When this creature enters, it deals 1 damage to target creature an opponent controls. + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(1)); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + + // Warp {2}{R} + this.addAbility(new WarpAbility(this, "{2}{R}")); + } + + private NovaHellkite(final NovaHellkite card) { + super(card); + } + + @Override + public NovaHellkite copy() { + return new NovaHellkite(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NoxiousDragon.java b/Mage.Sets/src/mage/cards/n/NoxiousDragon.java index 457d9dcdb89..f8ff2ac679d 100644 --- a/Mage.Sets/src/mage/cards/n/NoxiousDragon.java +++ b/Mage.Sets/src/mage/cards/n/NoxiousDragon.java @@ -14,6 +14,7 @@ import mage.constants.SubType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class NoxiousDragon extends CardImpl { // When Noxious Dragon dies, you may destroy target creature with converted mana cost 3 or less. Ability ability = new DiesSourceTriggeredAbility(new DestroyTargetEffect(), true); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NoxiousGearhulk.java b/Mage.Sets/src/mage/cards/n/NoxiousGearhulk.java index cfc81a62686..e4786a4964f 100644 --- a/Mage.Sets/src/mage/cards/n/NoxiousGearhulk.java +++ b/Mage.Sets/src/mage/cards/n/NoxiousGearhulk.java @@ -16,8 +16,11 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * * @author fireshoes @@ -35,7 +38,7 @@ public final class NoxiousGearhulk extends CardImpl { // When Noxious Gearhulk enters the battlefield, you may destroy another target creature. If a creature is destroyed this way, you gain life equal to its toughness. Ability ability = new EntersBattlefieldTriggeredAbility(new NoxiousGearhulkEffect()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NukaNukeLauncher.java b/Mage.Sets/src/mage/cards/n/NukaNukeLauncher.java new file mode 100644 index 00000000000..61f42edf696 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NukaNukeLauncher.java @@ -0,0 +1,116 @@ +package mage.cards.n; + +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.AttacksAttachedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.IntimidateAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NukaNukeLauncher extends CardImpl { + + public NukaNukeLauncher(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Equipped creature gets +3/+0 and has intimidate. + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(3, 0)); + ability.addEffect(new GainAbilityAttachedEffect( + IntimidateAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText("and has intimidate")); + this.addAbility(ability); + + // Whenever equipped creature attacks, until the end of defending player's next turn, that player gets two rad counters whenever they cast a spell. + this.addAbility(new AttacksAttachedTriggeredAbility( + new CreateDelayedTriggeredAbilityEffect(new NukaNukeLauncherDelayedTriggeredAbility()), + AttachmentType.EQUIPMENT, false, SetTargetPointer.PLAYER + )); + + // Equip {3} + this.addAbility(new EquipAbility(3)); + } + + private NukaNukeLauncher(final NukaNukeLauncher card) { + super(card); + } + + @Override + public NukaNukeLauncher copy() { + return new NukaNukeLauncher(this); + } +} + +class NukaNukeLauncherDelayedTriggeredAbility extends DelayedTriggeredAbility { + + private UUID playerId = null; + + NukaNukeLauncherDelayedTriggeredAbility() { + super(new AddCountersTargetEffect(CounterType.RAD.createInstance(2)), Duration.Custom, false, false); + } + + private NukaNukeLauncherDelayedTriggeredAbility(final NukaNukeLauncherDelayedTriggeredAbility ability) { + super(ability); + } + + @Override + public NukaNukeLauncherDelayedTriggeredAbility copy() { + return new NukaNukeLauncherDelayedTriggeredAbility(this); + } + + @Override + public void init(Game game) { + super.init(game); + this.playerId = this + .getEffects() + .stream() + .map(Effect::getTargetPointer) + .map(targetPointer -> targetPointer.getFirst(game, this)) + .findAny() + .orElse(null); + } + + @Override + public boolean isInactive(Game game) { + if (playerId == null) { + return true; + } + if (game.isActivePlayer(playerId)) { + this.setDuration(Duration.EndOfTurn); + } + return super.isInactive(game); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SPELL_CAST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Spell spell = game.getSpell(event.getTargetId()); + return spell != null && spell.isControlledBy(playerId); + } + + @Override + public String getRule() { + return "Until the end of defending player's next turn, that player gets two rad counters whenever they cast a spell"; + } +} diff --git a/Mage.Sets/src/mage/cards/n/NullmageShepherd.java b/Mage.Sets/src/mage/cards/n/NullmageShepherd.java index 1918253be4c..e70d5b0d187 100644 --- a/Mage.Sets/src/mage/cards/n/NullmageShepherd.java +++ b/Mage.Sets/src/mage/cards/n/NullmageShepherd.java @@ -1,4 +1,3 @@ - package mage.cards.n; import mage.MageInt; @@ -10,28 +9,18 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; import mage.target.TargetPermanent; -import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; /** - * * @author Loki */ public final class NullmageShepherd extends CardImpl { - private static final FilterControlledCreaturePermanent filterCost = new FilterControlledCreaturePermanent("untapped creatures you control"); - static { - filterCost.add(TappedPredicate.UNTAPPED); - } - public NullmageShepherd(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.SHAMAN); @@ -39,7 +28,7 @@ public final class NullmageShepherd extends CardImpl { this.toughness = new MageInt(4); // Tap four untapped creatures you control: Destroy target artifact or enchantment. - Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new TapTargetCost(new TargetControlledCreaturePermanent(4, 4, filterCost, true))); + Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new TapTargetCost(4, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES)); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NullpriestOfOblivion.java b/Mage.Sets/src/mage/cards/n/NullpriestOfOblivion.java index 498c3ca4f47..1f7eb3d2dc0 100644 --- a/Mage.Sets/src/mage/cards/n/NullpriestOfOblivion.java +++ b/Mage.Sets/src/mage/cards/n/NullpriestOfOblivion.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.keyword.KickerAbility; import mage.abilities.keyword.LifelinkAbility; @@ -41,11 +40,8 @@ public final class NullpriestOfOblivion extends CardImpl { this.addAbility(LifelinkAbility.getInstance()); // When this creature enters the battlefield, if it was kicked, return target creature card from your graveyard to the battlefield. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()), - KickedCondition.ONCE, "When this creature enters, if it was kicked, " + - "return target creature card from your graveyard to the battlefield." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()) + .withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/o/OKagachiVengefulKami.java b/Mage.Sets/src/mage/cards/o/OKagachiVengefulKami.java index 403faf3ab60..8fb3f30b2c9 100644 --- a/Mage.Sets/src/mage/cards/o/OKagachiVengefulKami.java +++ b/Mage.Sets/src/mage/cards/o/OKagachiVengefulKami.java @@ -1,22 +1,26 @@ package mage.cards.o; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.WatcherScope; import mage.filter.FilterPermanent; import mage.filter.common.FilterNonlandPermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; -import mage.players.Player; import mage.target.TargetPermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; +import mage.util.CardUtil; import mage.watchers.Watcher; import java.util.*; @@ -26,6 +30,8 @@ import java.util.*; */ public final class OKagachiVengefulKami extends CardImpl { + private static final FilterPermanent filter = new FilterNonlandPermanent("nonland permanent that player controls"); + public OKagachiVengefulKami(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}{B}{R}{G}"); @@ -42,7 +48,11 @@ public final class OKagachiVengefulKami extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Whenever O-Kagachi, Vengeful Kami deals combat damage to a player, if that player attacked you during their last turn, exile target nonland permanent that player controls - this.addAbility(new OKagachiVengefulKamiTriggeredAbility()); + TriggeredAbility ability = new DealsCombatDamageToAPlayerTriggeredAbility(new ExileTargetEffect(), false, true); + ability.addTarget(new TargetPermanent(filter)); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); + ability.withInterveningIf(KagachiVengefulKamiCondition.instance); + this.addAbility(ability); } private OKagachiVengefulKami(final OKagachiVengefulKami card) { @@ -55,66 +65,25 @@ public final class OKagachiVengefulKami extends CardImpl { } } -class OKagachiVengefulKamiTriggeredAbility extends TriggeredAbilityImpl { - - OKagachiVengefulKamiTriggeredAbility() { - super(Zone.BATTLEFIELD, new ExileTargetEffect(), false); - this.addWatcher(new OKagachiVengefulKamiWatcher()); - } - - private OKagachiVengefulKamiTriggeredAbility(final OKagachiVengefulKamiTriggeredAbility ability) { - super(ability); - } +enum KagachiVengefulKamiCondition implements Condition { + instance; @Override - public OKagachiVengefulKamiTriggeredAbility copy() { - return new OKagachiVengefulKamiTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Player player = game.getPlayer(event.getTargetId()); - if (player == null - || !((DamagedPlayerEvent) event).isCombatDamage() - || !event.getSourceId().equals(getSourceId())) { - return false; - } - this.getEffects().setValue("damagedPlayer", event.getTargetId()); - FilterPermanent filter = new FilterNonlandPermanent("nonland permanent controlled by " + player.getName()); - filter.add(new ControllerIdPredicate(event.getTargetId())); - this.getTargets().clear(); - this.addTarget(new TargetPermanent(filter)); - return true; - } - - @Override - public boolean checkInterveningIfClause(Game game) { + public boolean apply(Game game, Ability source) { OKagachiVengefulKamiWatcher watcher = game.getState().getWatcher(OKagachiVengefulKamiWatcher.class); if (watcher == null) { return false; } - UUID playerId = null; - for (Effect effect : this.getEffects()) { - Object obj = effect.getValue("damagedPlayer"); - if (obj instanceof UUID) { - playerId = (UUID) obj; - break; - } - } - return watcher.checkPlayer(getControllerId(), playerId); + return CardUtil.getEffectValueFromAbility(source, "damagedPlayer", UUID.class) + .filter(uuid -> watcher.checkPlayer(source.getControllerId(), uuid)) + .isPresent(); } @Override - public String getRule() { - return "Whenever {this} deals combat damage to a player, " + - "if that player attacked you during their last turn, " + - "exile target nonland permanent that player controls."; + public String toString() { + return "if that player attacked you during their last turn"; } + } class OKagachiVengefulKamiWatcher extends Watcher { diff --git a/Mage.Sets/src/mage/cards/o/ONaginata.java b/Mage.Sets/src/mage/cards/o/ONaginata.java index c34f02b7fd9..104488f9627 100644 --- a/Mage.Sets/src/mage/cards/o/ONaginata.java +++ b/Mage.Sets/src/mage/cards/o/ONaginata.java @@ -1,12 +1,8 @@ - package mage.cards.o; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.AttachableToRestrictedAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EquipAbility; @@ -15,17 +11,15 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AttachmentType; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.SubType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; -import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class ONaginata extends CardImpl { @@ -37,24 +31,21 @@ public final class ONaginata extends CardImpl { } public ONaginata(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{1}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); this.subtype.add(SubType.EQUIPMENT); - Target target = new TargetControlledCreaturePermanent(1, 1, filter, false); // O-Naginata can be attached only to a creature with 3 or more power. - this.addAbility(new AttachableToRestrictedAbility(target)); + this.addAbility(new AttachableToRestrictedAbility(new TargetPermanent(filter))); // Equipped creature gets +3/+0 and has trample. - Effect effect = new BoostEquippedEffect(3, 0); - effect.setText("Equipped creature gets +3/+0"); - Ability ability = new SimpleStaticAbility(effect); - effect = new GainAbilityAttachedEffect(TrampleAbility.getInstance(), AttachmentType.EQUIPMENT); - effect.setText("and has trample"); - ability.addEffect(effect); + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(3, 0)); + ability.addEffect(new GainAbilityAttachedEffect( + TrampleAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText("and has trample")); this.addAbility(ability); // Equip {2} - this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2), target)); + this.addAbility(new EquipAbility(2)); } private ONaginata(final ONaginata card) { diff --git a/Mage.Sets/src/mage/cards/o/OathOfChandra.java b/Mage.Sets/src/mage/cards/o/OathOfChandra.java index d4c77f71cef..d3cb3b769d9 100644 --- a/Mage.Sets/src/mage/cards/o/OathOfChandra.java +++ b/Mage.Sets/src/mage/cards/o/OathOfChandra.java @@ -1,18 +1,12 @@ - package mage.cards.o; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -20,31 +14,36 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.watchers.Watcher; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** - * * @author LevelX2 */ public final class OathOfChandra extends CardImpl { public OathOfChandra(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); this.supertype.add(SuperType.LEGENDARY); // When Oath of Chandra enters the battlefield, it deals 3 damage to target creature an opponent controls. - Effect effect = new DamageTargetEffect(3); - effect.setText("it deals 3 damage to target creature an opponent controls"); - Ability ability = new EntersBattlefieldTriggeredAbility(effect, false); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(3, "it")); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); // At the beginning of each end step, if a planeswalker entered the battlefield under your control this turn, Oath of Chandra deals 2 damage to each opponent. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new BeginningOfEndStepTriggeredAbility( - TargetController.ANY, new DamagePlayersEffect(Outcome.Damage, StaticValue.get(2), TargetController.OPPONENT), - false), OathOfChandraCondition.instance, - "At the beginning of each end step, if a planeswalker entered the battlefield under your control this turn, {this} deals 2 damage to each opponent."), new OathOfChandraWatcher()); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.ANY, + new DamagePlayersEffect(Outcome.Damage, StaticValue.get(2), TargetController.OPPONENT), + false, OathOfChandraCondition.instance + ), new OathOfChandraWatcher()); } private OathOfChandra(final OathOfChandra card) { @@ -58,7 +57,6 @@ public final class OathOfChandra extends CardImpl { } enum OathOfChandraCondition implements Condition { - instance; @Override @@ -69,7 +67,7 @@ enum OathOfChandraCondition implements Condition { @Override public String toString() { - return "if a planeswalker entered the battlefield under your control this turn"; + return "a planeswalker entered the battlefield under your control this turn"; } } @@ -101,5 +99,4 @@ class OathOfChandraWatcher extends Watcher { public boolean enteredPlaneswalkerForPlayer(UUID playerId) { return players.contains(playerId); } - } diff --git a/Mage.Sets/src/mage/cards/o/OathOfLiliana.java b/Mage.Sets/src/mage/cards/o/OathOfLiliana.java index b47cf7e38c5..ceff40926e3 100644 --- a/Mage.Sets/src/mage/cards/o/OathOfLiliana.java +++ b/Mage.Sets/src/mage/cards/o/OathOfLiliana.java @@ -1,16 +1,11 @@ - package mage.cards.o; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.SacrificeOpponentsEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -21,6 +16,10 @@ import mage.game.events.ZoneChangeEvent; import mage.game.permanent.token.ZombieToken; import mage.watchers.Watcher; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** * @author fireshoes */ @@ -31,14 +30,15 @@ public final class OathOfLiliana extends CardImpl { this.supertype.add(SuperType.LEGENDARY); // When Oath of Liliana enters the battlefield, each opponent sacrifices a creature. - this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeOpponentsEffect(StaticFilters.FILTER_PERMANENT_CREATURE), false)); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SacrificeOpponentsEffect(StaticFilters.FILTER_PERMANENT_CREATURE) + )); // At the beginning of each end step, if a planeswalker entered the battlefield under your control this turn, create a 2/2 black Zombie creature token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new BeginningOfEndStepTriggeredAbility( + this.addAbility(new BeginningOfEndStepTriggeredAbility( TargetController.ANY, new CreateTokenEffect(new ZombieToken()), - false), OathOfLilianaCondition.instance, - "At the beginning of each end step, if a planeswalker entered the battlefield under your control this turn, " - + "create a 2/2 black Zombie creature token."), new OathOfLilianaWatcher()); + false, OathOfLilianaCondition.instance + ), new OathOfLilianaWatcher()); } private OathOfLiliana(final OathOfLiliana card) { @@ -63,7 +63,7 @@ enum OathOfLilianaCondition implements Condition { @Override public String toString() { - return "if a planeswalker entered the battlefield under your control this turn"; + return "a planeswalker entered the battlefield under your control this turn"; } } @@ -95,6 +95,4 @@ class OathOfLilianaWatcher extends Watcher { public boolean enteredPlaneswalkerForPlayer(UUID playerId) { return players.contains(playerId); } - - } diff --git a/Mage.Sets/src/mage/cards/o/ObscuraAscendancy.java b/Mage.Sets/src/mage/cards/o/ObscuraAscendancy.java index de99ac113b5..5593e56ebc0 100644 --- a/Mage.Sets/src/mage/cards/o/ObscuraAscendancy.java +++ b/Mage.Sets/src/mage/cards/o/ObscuraAscendancy.java @@ -1,15 +1,11 @@ package mage.cards.o; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.Effects; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; @@ -24,9 +20,11 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.Spirit22Token; import mage.game.stack.Spell; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author weirddan455 */ public final class ObscuraAscendancy extends CardImpl { @@ -37,11 +35,11 @@ public final class ObscuraAscendancy extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}{U}{B}"); // Whenever you cast a spell, if its mana value is equal to the number of soul counters on Obscura Ascendancy plus one, put a soul counter on Obscura Ascendancy, then create a 2/2 white Spirit creature token with flying. - SpellCastControllerTriggeredAbility triggeredAbility = new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.SOUL.createInstance()), false); - triggeredAbility.addEffect(new CreateTokenEffect(new Spirit22Token())); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(triggeredAbility, ObscuraAscendancyCondition.instance, - "Whenever you cast a spell, if its mana value is equal to 1 plus the number of soul counters on {this}, put a soul counter on {this}, then create a 2/2 white Spirit creature token with flying." - )); + Ability ability = new SpellCastControllerTriggeredAbility( + new AddCountersSourceEffect(CounterType.SOUL.createInstance()), false + ).withInterveningIf(ObscuraAscendancyCondition.instance); + ability.addEffect(new CreateTokenEffect(new Spirit22Token()).concatBy(", then")); + this.addAbility(ability); // As long as Obscura Ascendancy has five or more soul counters on it, Spirits you control get +3/+3. this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( @@ -67,15 +65,16 @@ enum ObscuraAscendancyCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Permanent permanent = source.getSourcePermanentOrLKI(game); - if (permanent != null) { - Effects effects = source.getEffects(); - if (!effects.isEmpty()) { - Object spellCast = effects.get(0).getValue("spellCast"); - if (spellCast instanceof Spell) { - return ((Spell) spellCast).getManaValue() == permanent.getCounters(game).getCount(CounterType.SOUL) + 1; - } - } - } - return false; + return permanent != null + && CardUtil + .getEffectValueFromAbility(source, "spellCast", Spell.class) + .map(Spell::getManaValue) + .filter(x -> x == permanent.getCounters(game).getCount(CounterType.SOUL) + 1) + .isPresent(); + } + + @Override + public String toString() { + return "its mana value is equal to 1 plus the number of soul counters on {this}"; } } diff --git a/Mage.Sets/src/mage/cards/o/ObsessiveSkinner.java b/Mage.Sets/src/mage/cards/o/ObsessiveSkinner.java index 5d61c63a5d8..d469f876823 100644 --- a/Mage.Sets/src/mage/cards/o/ObsessiveSkinner.java +++ b/Mage.Sets/src/mage/cards/o/ObsessiveSkinner.java @@ -1,23 +1,23 @@ package mage.cards.o; -import java.util.UUID; - import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; import mage.counters.CounterType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * @author fireshoes */ @@ -37,14 +37,11 @@ public final class ObsessiveSkinner extends CardImpl { // Delirium — At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, // put a +1/+1 counter on target creature. - ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(TargetController.OPPONENT, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false), - DeliriumCondition.instance, - "Delirium — At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, " - + "put a +1/+1 counter on target creature."); + ability = new BeginningOfUpkeepTriggeredAbility( + TargetController.OPPONENT, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false + ).withInterveningIf(DeliriumCondition.instance); ability.addTarget(new TargetCreaturePermanent()); - ability.addHint(CardTypesInGraveyardCount.YOU.getHint()); - this.addAbility(ability); + this.addAbility(ability.setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); } private ObsessiveSkinner(final ObsessiveSkinner card) { diff --git a/Mage.Sets/src/mage/cards/o/ObsidianFireheart.java b/Mage.Sets/src/mage/cards/o/ObsidianFireheart.java index 84f8fc0cc08..ad07b6158f2 100644 --- a/Mage.Sets/src/mage/cards/o/ObsidianFireheart.java +++ b/Mage.Sets/src/mage/cards/o/ObsidianFireheart.java @@ -31,7 +31,7 @@ public final class ObsidianFireheart extends CardImpl { private static final String rule = "For as long as that land has a blaze counter " + "on it, it has \"At the beginning of your upkeep, this land deals 1 damage " - + "to you.\" (The land continues to burn after Obsidian Fireheart has left the battlefield.)"; + + "to you.\" (The land continues to burn after {this} has left the battlefield.)"; private static final FilterPermanent filter = new FilterLandPermanent("land without a blaze counter on it"); static { diff --git a/Mage.Sets/src/mage/cards/o/OchreJelly.java b/Mage.Sets/src/mage/cards/o/OchreJelly.java index 36dd3fc0234..c14906a72d4 100644 --- a/Mage.Sets/src/mage/cards/o/OchreJelly.java +++ b/Mage.Sets/src/mage/cards/o/OchreJelly.java @@ -6,7 +6,6 @@ import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; @@ -43,14 +42,11 @@ public final class OchreJelly extends CardImpl { this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.P1P1.createInstance()))); // Split — When Ochre Jelly dies, if it had two or more +1/+1 counters on it, create a token that's a copy of it at the beginning of the next end step. That token enters the battlefield with half that many +1/+1 counters on it, rounded down. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new DiesSourceTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( - new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new OchreJellyEffect()) - )), OchreJellyCondition.instance, CardUtil.italicizeWithEmDash("Split") - + "When {this} dies, if it had two or more +1/+1 counters on it, " - + "create a token that's a copy of it at the beginning of the next end step. " - + "The token enters the battlefield with half that many +1/+1 counters on it, rounded down." - )); + this.addAbility(new DiesSourceTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( + new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new OchreJellyEffect()) + ).setText("create a token that's a copy of it at the beginning of the next end step. " + + "The token enters with half that many +1/+1 counters on it, rounded down")) + .withInterveningIf(OchreJellyCondition.instance).withFlavorWord("Split")); } private OchreJelly(final OchreJelly card) { @@ -68,8 +64,15 @@ enum OchreJellyCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) source.getEffects().get(0).getValue("permanentLeftBattlefield"); - return permanent != null && permanent.getCounters(game).getCount(CounterType.P1P1) >= 2; + return CardUtil + .getEffectValueFromAbility(source, "permanentLeftBattlefield", Permanent.class) + .filter(permanent -> permanent.getCounters(game).getCount(CounterType.P1P1) >= 2) + .isPresent(); + } + + @Override + public String toString() { + return "it had two or more +1/+1 counters on it"; } } @@ -95,10 +98,8 @@ class OchreJellyEffect extends OneShotEffect { if (permanent == null) { return false; } - final int counters = permanent.getCounters(game).getCount(CounterType.P1P1) / 2; - CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(CounterType.P1P1, counters); - effect.setSavedPermanent(permanent); - effect.apply(game, source); - return true; + return new CreateTokenCopyTargetEffect( + CounterType.P1P1, permanent.getCounters(game).getCount(CounterType.P1P1) / 2 + ).setSavedPermanent(permanent).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/o/OctopusUmbra.java b/Mage.Sets/src/mage/cards/o/OctopusUmbra.java index 14dbf1bc87f..34b48a0d632 100644 --- a/Mage.Sets/src/mage/cards/o/OctopusUmbra.java +++ b/Mage.Sets/src/mage/cards/o/OctopusUmbra.java @@ -48,7 +48,7 @@ public final class OctopusUmbra extends CardImpl { // Enchanted creature has base power and toughness 8/8 and has "Whenever this creature attacks, you may tap target creature with power 8 or less." Ability abilityToAdd = new AttacksTriggeredAbility(new TapTargetEffect(), true); - abilityToAdd.addTarget(new TargetCreaturePermanent(filter)); + abilityToAdd.addTarget(new TargetPermanent(filter)); ability = new SimpleStaticAbility( new SetBasePowerToughnessAttachedEffect(8, 8, AttachmentType.AURA) ); diff --git a/Mage.Sets/src/mage/cards/o/OgreGatecrasher.java b/Mage.Sets/src/mage/cards/o/OgreGatecrasher.java index f9eeaafab69..326830ce6ce 100644 --- a/Mage.Sets/src/mage/cards/o/OgreGatecrasher.java +++ b/Mage.Sets/src/mage/cards/o/OgreGatecrasher.java @@ -13,6 +13,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -36,7 +37,7 @@ public final class OgreGatecrasher extends CardImpl { // When Ogre Gatecrasher enters the battlefield, destroy target creature with defender. Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), false); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/o/OgreSavant.java b/Mage.Sets/src/mage/cards/o/OgreSavant.java index c75a9a291c3..9ae30f39e26 100644 --- a/Mage.Sets/src/mage/cards/o/OgreSavant.java +++ b/Mage.Sets/src/mage/cards/o/OgreSavant.java @@ -1,38 +1,35 @@ - package mage.cards.o; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.ManaWasSpentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.ColoredManaSymbol; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author FenrisulfrX */ public final class OgreSavant extends CardImpl { public OgreSavant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); this.subtype.add(SubType.OGRE); this.subtype.add(SubType.WIZARD); this.power = new MageInt(3); this.toughness = new MageInt(2); //When Ogre Savant enters the battlefield, if {U} was spent to cast Ogre Savant, return target creature to its owner’s hand. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(),false); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()) + .withInterveningIf(ManaWasSpentCondition.BLUE); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, ManaWasSpentCondition.BLUE, - "When {this} enters, if {U} was spent to cast it, return target creature to its owner's hand.")); + this.addAbility(ability); } private OgreSavant(final OgreSavant card) { diff --git a/Mage.Sets/src/mage/cards/o/OhranYeti.java b/Mage.Sets/src/mage/cards/o/OhranYeti.java index 092a8f5f895..0155af89ca0 100644 --- a/Mage.Sets/src/mage/cards/o/OhranYeti.java +++ b/Mage.Sets/src/mage/cards/o/OhranYeti.java @@ -16,6 +16,7 @@ import mage.constants.Duration; import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class OhranYeti extends CardImpl { // {2}{S}: Target snow creature gains first strike until end of turn. Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect( FirstStrikeAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{2}{S}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/o/OkinaNightwatch.java b/Mage.Sets/src/mage/cards/o/OkinaNightwatch.java index 1657a2ac65b..b912963b205 100644 --- a/Mage.Sets/src/mage/cards/o/OkinaNightwatch.java +++ b/Mage.Sets/src/mage/cards/o/OkinaNightwatch.java @@ -33,7 +33,7 @@ public final class OkinaNightwatch extends CardImpl { Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( new BoostSourceEffect(3,3, Duration.WhileOnBattlefield), MoreCardsInHandThanOpponentsCondition.instance, - "As long as you have more cards in hand than each opponent, Okina Nightwatch gets +3/+3")); + "As long as you have more cards in hand than each opponent, {this} gets +3/+3")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/o/OldGrowthTroll.java b/Mage.Sets/src/mage/cards/o/OldGrowthTroll.java index acf6b65c22b..b619622e09e 100644 --- a/Mage.Sets/src/mage/cards/o/OldGrowthTroll.java +++ b/Mage.Sets/src/mage/cards/o/OldGrowthTroll.java @@ -12,7 +12,6 @@ import mage.abilities.costs.Cost; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.AttachEffect; @@ -53,13 +52,8 @@ public final class OldGrowthTroll extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // When Old-Growth Troll dies, if it was a creature, return it to the battlefield. It's an Aura enchantment with enchant Forest you control and "Enchanted Forest has '{T}: Add {G}{G}' and '{1}, {T}, Sacrifice this land: Create a 4/4 green Troll Warrior creature token with trample.'" - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new DiesSourceTriggeredAbility(new OldGrowthTrollReturnEffect()), - OldGrowthTrollCondition.instance, "When {this} dies, if it was a creature, " + - "return it to the battlefield. It's an Aura enchantment with enchant Forest you control " + - "and \"Enchanted Forest has '{T}: Add {G}{G}' and '{1}, {T}, Sacrifice this land: " + - "Create a tapped 4/4 green Troll Warrior creature token with trample.'\"" - )); + this.addAbility(new DiesSourceTriggeredAbility(new OldGrowthTrollReturnEffect()) + .withInterveningIf(OldGrowthTrollCondition.instance)); } private OldGrowthTroll(final OldGrowthTroll card) { @@ -77,8 +71,15 @@ enum OldGrowthTrollCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) source.getEffects().get(0).getValue("permanentLeftBattlefield"); - return permanent != null && permanent.isCreature(game); + return CardUtil + .getEffectValueFromAbility(source, "permanentLeftBattlefield", Permanent.class) + .filter(permanent -> permanent.isCreature(game)) + .isPresent(); + } + + @Override + public String toString() { + return "it was a creature"; } } @@ -88,6 +89,9 @@ class OldGrowthTrollReturnEffect extends OneShotEffect { OldGrowthTrollReturnEffect() { super(Outcome.PutCardInPlay); + staticText = "return it to the battlefield. It's an Aura enchantment with enchant Forest you control " + + "and \"Enchanted Forest has '{T}: Add {G}{G}' and '{1}, {T}, Sacrifice this land: " + + "Create a tapped 4/4 green Troll Warrior creature token with trample.'\""; } private OldGrowthTrollReturnEffect(final OldGrowthTrollReturnEffect effect) { diff --git a/Mage.Sets/src/mage/cards/o/OliviaVoldaren.java b/Mage.Sets/src/mage/cards/o/OliviaVoldaren.java index 2c7bda1aa80..4f357294898 100644 --- a/Mage.Sets/src/mage/cards/o/OliviaVoldaren.java +++ b/Mage.Sets/src/mage/cards/o/OliviaVoldaren.java @@ -19,6 +19,7 @@ import mage.constants.SuperType; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -52,7 +53,7 @@ public final class OliviaVoldaren extends CardImpl { .setText("{this} deals 1 damage to another target creature"), new ManaCostsImpl<>("{1}{R}") ); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); Effect effect = new AddCardSubTypeTargetEffect(SubType.VAMPIRE, Duration.WhileOnBattlefield); effect.setText("That creature becomes a Vampire in addition to its other types"); ability.addEffect(effect); @@ -63,7 +64,7 @@ public final class OliviaVoldaren extends CardImpl { Ability ability2 = new SimpleActivatedAbility( new GainControlTargetEffect(Duration.WhileControlled), new ManaCostsImpl<>("{3}{B}{B}") ); - ability2.addTarget(new TargetCreaturePermanent(vampireFilter)); + ability2.addTarget(new TargetPermanent(vampireFilter)); this.addAbility(ability2); } diff --git a/Mage.Sets/src/mage/cards/o/OliviasBloodsworn.java b/Mage.Sets/src/mage/cards/o/OliviasBloodsworn.java index a277949ac54..40dedcfb3fd 100644 --- a/Mage.Sets/src/mage/cards/o/OliviasBloodsworn.java +++ b/Mage.Sets/src/mage/cards/o/OliviasBloodsworn.java @@ -17,6 +17,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -46,7 +47,7 @@ public final class OliviasBloodsworn extends CardImpl { // {R}: Target Vampire gains haste until end of turn. Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{R}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/o/OlorinsSearingLight.java b/Mage.Sets/src/mage/cards/o/OlorinsSearingLight.java index a1b9cecdeba..e865251f5a0 100644 --- a/Mage.Sets/src/mage/cards/o/OlorinsSearingLight.java +++ b/Mage.Sets/src/mage/cards/o/OlorinsSearingLight.java @@ -14,12 +14,11 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.*; /** - * * @author notgreat */ public final class OlorinsSearingLight extends CardImpl { @@ -41,17 +40,20 @@ public final class OlorinsSearingLight extends CardImpl { return new OlorinsSearingLight(this); } } + //See Crackling Doom class OlorinsSearingLightEffect extends OneShotEffect { static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature with the greatest power among creatures you control"); + static { filter.add(GreatestPowerControlledPredicate.instance); } + public OlorinsSearingLightEffect() { super(Outcome.Sacrifice); this.staticText = "Each opponent exiles a creature with the greatest power among creatures that player controls.
" - +"Spell mastery — If there are two or more instant and/or sorcery cards in your graveyard, {this} deals damage to each opponent equal to the power of the creature they exiled."; + + "Spell mastery — If there are two or more instant and/or sorcery cards in your graveyard, {this} deals damage to each opponent equal to the power of the creature they exiled."; } private OlorinsSearingLightEffect(final OlorinsSearingLightEffect effect) { @@ -72,7 +74,7 @@ class OlorinsSearingLightEffect extends OneShotEffect { if (controller.hasOpponent(playerId, game)) { Player opponent = game.getPlayer(playerId); if (opponent != null) { - Target target = new TargetControlledCreaturePermanent(filter); + Target target = new TargetPermanent(filter); target.withNotTarget(true); if (opponent.choose(outcome, target, source, game)) { Permanent permanentChosen = game.getPermanent(target.getFirstTarget()); @@ -91,7 +93,7 @@ class OlorinsSearingLightEffect extends OneShotEffect { opponent.moveCards(permanent, Zone.EXILED, source, game); } } - if (SpellMasteryCondition.instance.apply(game, source)){ + if (SpellMasteryCondition.instance.apply(game, source)) { game.processAction(); for (Map.Entry entry : damageList) { entry.getKey().damage(entry.getValue(), source, game); diff --git a/Mage.Sets/src/mage/cards/o/OminousSphinx.java b/Mage.Sets/src/mage/cards/o/OminousSphinx.java index 0ca9748423c..523392f371c 100644 --- a/Mage.Sets/src/mage/cards/o/OminousSphinx.java +++ b/Mage.Sets/src/mage/cards/o/OminousSphinx.java @@ -12,8 +12,11 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Duration; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author spjspj @@ -32,7 +35,7 @@ public final class OminousSphinx extends CardImpl { // Whenever you cycle or discard a card,target creature an opponent controls gets -2/-0 until end of turn. CycleOrDiscardControllerTriggeredAbility ability = new CycleOrDiscardControllerTriggeredAbility(new BoostTargetEffect(-2, -0, Duration.EndOfTurn)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/o/OnceMoreWithFeeling.java b/Mage.Sets/src/mage/cards/o/OnceMoreWithFeeling.java index ace067e1f21..5543200d25f 100644 --- a/Mage.Sets/src/mage/cards/o/OnceMoreWithFeeling.java +++ b/Mage.Sets/src/mage/cards/o/OnceMoreWithFeeling.java @@ -1,7 +1,6 @@ package mage.cards.o; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -19,8 +18,9 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** - * * @author L_J */ public final class OnceMoreWithFeeling extends CardImpl { @@ -38,7 +38,7 @@ public final class OnceMoreWithFeeling extends CardImpl { // DCI ruling — A deck can have only one card named Once More with Feeling. // (according to rule 112.6m, this shouldn't do anything) - this.getSpellAbility().addEffect(new InfoEffect("
DCI ruling — A deck can have only one card named {this}")); + this.getSpellAbility().addEffect(new InfoEffect("
DCI ruling — A deck can have only one card named Once More with Feeling")); } private OnceMoreWithFeeling(final OnceMoreWithFeeling card) { diff --git a/Mage.Sets/src/mage/cards/o/OpalAcrolith.java b/Mage.Sets/src/mage/cards/o/OpalAcrolith.java index 3faf035927a..7f52f026c94 100644 --- a/Mage.Sets/src/mage/cards/o/OpalAcrolith.java +++ b/Mage.Sets/src/mage/cards/o/OpalAcrolith.java @@ -1,13 +1,9 @@ package mage.cards.o; -import java.util.UUID; -import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SpellCastOpponentTriggeredAbility; -import mage.abilities.condition.common.SourceMatchesFilterCondition; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.effects.common.continuous.BecomesEnchantmentSourceEffect; import mage.cards.CardImpl; @@ -15,35 +11,28 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.FilterSpell; import mage.filter.StaticFilters; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class OpalAcrolith extends CardImpl { - private static final FilterSpell filter = new FilterSpell("creature spell"); - - static { - filter.add(CardType.CREATURE.getPredicate()); - } - public OpalAcrolith(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); // Whenever an opponent casts a creature spell, if Opal Acrolith is an enchantment, Opal Acrolith becomes a 2/4 Soldier creature. - TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new OpalAcrolithToken(), null, Duration.WhileOnBattlefield), - filter, false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), - "Whenever an opponent casts a creature spell, if Opal Acrolith is an enchantment, Opal Acrolith becomes a 2/4 Soldier creature.")); + this.addAbility(new SpellCastOpponentTriggeredAbility( + new BecomesCreatureSourceEffect(new CreatureToken( + 2, 4, "2/4 Soldier creature", SubType.SOLDIER + ), null, Duration.WhileOnBattlefield), StaticFilters.FILTER_SPELL_A_CREATURE, false + ).withInterveningIf(SourceIsEnchantmentCondition.instance).withRuleTextReplacement(true)); // {0}: Opal Acrolith becomes an enchantment. - this.addAbility(new SimpleActivatedAbility(new BecomesEnchantmentSourceEffect(), new ManaCostsImpl<>("{0}"))); - + this.addAbility(new SimpleActivatedAbility(new BecomesEnchantmentSourceEffect().setText("this permanent becomes an enchantment"), new ManaCostsImpl<>("{0}"))); } private OpalAcrolith(final OpalAcrolith card) { @@ -55,22 +44,3 @@ public final class OpalAcrolith extends CardImpl { return new OpalAcrolith(this); } } - -class OpalAcrolithToken extends TokenImpl { - - public OpalAcrolithToken() { - super("Soldier", "2/4 Soldier creature"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.SOLDIER); - power = new MageInt(2); - toughness = new MageInt(4); - } - - private OpalAcrolithToken(final OpalAcrolithToken token) { - super(token); - } - - public OpalAcrolithToken copy() { - return new OpalAcrolithToken(this); - } -} diff --git a/Mage.Sets/src/mage/cards/o/OpalArchangel.java b/Mage.Sets/src/mage/cards/o/OpalArchangel.java index 45a44a90a0b..7e82d75e61b 100644 --- a/Mage.Sets/src/mage/cards/o/OpalArchangel.java +++ b/Mage.Sets/src/mage/cards/o/OpalArchangel.java @@ -1,40 +1,38 @@ - package mage.cards.o; -import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.SpellCastOpponentTriggeredAbility; -import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreatureSpell; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; import java.util.UUID; /** - * * @author LoneFox - * */ public final class OpalArchangel extends CardImpl { public OpalArchangel(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{4}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{W}"); // When an opponent casts a creature spell, if Opal Archangel is an enchantment, Opal Archangel becomes a 5/5 Angel creature with flying and vigilance. - TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new OpalArchangelToken(), null, Duration.WhileOnBattlefield), - new FilterCreatureSpell(), false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), - "When an opponent casts a creature spell, if {this} is an enchantment, {this} becomes a 5/5 Angel creature with flying and vigilance.")); + this.addAbility(new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect( + new CreatureToken( + 5, 5, "5/5 Angel creature with flying and vigilance", SubType.ANGEL + ).withAbility(FlyingAbility.getInstance()).withAbility(VigilanceAbility.getInstance()), + null, Duration.WhileOnBattlefield + ), StaticFilters.FILTER_SPELL_A_CREATURE, false) + .withInterveningIf(SourceIsEnchantmentCondition.instance) + .withRuleTextReplacement(true) + .setTriggerPhrase("When an opponent casts a creature spell, ")); } private OpalArchangel(final OpalArchangel card) { @@ -46,23 +44,3 @@ public final class OpalArchangel extends CardImpl { return new OpalArchangel(this); } } - -class OpalArchangelToken extends TokenImpl { - - public OpalArchangelToken() { - super("Angel", "5/5 Angel creature with flying and vigilance"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.ANGEL); - power = new MageInt(5); - toughness = new MageInt(5); - this.addAbility(FlyingAbility.getInstance()); - this.addAbility(VigilanceAbility.getInstance()); - } - private OpalArchangelToken(final OpalArchangelToken token) { - super(token); - } - - public OpalArchangelToken copy() { - return new OpalArchangelToken(this); - } -} diff --git a/Mage.Sets/src/mage/cards/o/OpalAvenger.java b/Mage.Sets/src/mage/cards/o/OpalAvenger.java index 812059959bf..5f1f3bc6f02 100644 --- a/Mage.Sets/src/mage/cards/o/OpalAvenger.java +++ b/Mage.Sets/src/mage/cards/o/OpalAvenger.java @@ -1,7 +1,7 @@ package mage.cards.o; -import mage.MageInt; import mage.abilities.StateTriggeredAbility; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -11,8 +11,10 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; +import mage.players.Player; +import java.util.Optional; import java.util.UUID; /** @@ -40,9 +42,12 @@ public final class OpalAvenger extends CardImpl { class OpalAvengerStateTriggeredAbility extends StateTriggeredAbility { OpalAvengerStateTriggeredAbility() { - super(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new OpalAvengerToken(), null, Duration.Custom)); - this.withRuleTextReplacement(false); - setTriggerPhrase("When you have 10 or less life, if {this} is an enchantment, "); + super(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect( + new CreatureToken(3, 5, "3/5 Soldier creature", SubType.SOLDIER), null, Duration.Custom + )); + this.withInterveningIf(SourceIsEnchantmentCondition.instance); + this.withRuleTextReplacement(true); + this.setTriggerPhrase("When you have 10 or less life, "); } private OpalAvengerStateTriggeredAbility(final OpalAvengerStateTriggeredAbility ability) { @@ -56,38 +61,11 @@ class OpalAvengerStateTriggeredAbility extends StateTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (game.getState().getPlayer(getControllerId()) != null) { - return game.getState().getPlayer(getControllerId()).getLife() <= 10; - } - return false; - } - - @Override - public boolean checkInterveningIfClause(Game game) { - if (getSourcePermanentIfItStillExists(game) != null) { - return getSourcePermanentIfItStillExists(game).isEnchantment(game); - } - return false; - } - -} - -class OpalAvengerToken extends TokenImpl { - - public OpalAvengerToken() { - super("Soldier", "3/5 Soldier creature"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.SOLDIER); - power = new MageInt(3); - toughness = new MageInt(5); - } - - private OpalAvengerToken(final OpalAvengerToken token) { - super(token); - } - - @Override - public OpalAvengerToken copy() { - return new OpalAvengerToken(this); + return Optional + .ofNullable(getControllerId()) + .map(game::getPlayer) + .map(Player::getLife) + .filter(x -> x <= 10) + .isPresent(); } } diff --git a/Mage.Sets/src/mage/cards/o/OpalCaryatid.java b/Mage.Sets/src/mage/cards/o/OpalCaryatid.java index 21af43734ae..b0b0c7ca819 100644 --- a/Mage.Sets/src/mage/cards/o/OpalCaryatid.java +++ b/Mage.Sets/src/mage/cards/o/OpalCaryatid.java @@ -1,38 +1,35 @@ - package mage.cards.o; -import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.SpellCastOpponentTriggeredAbility; -import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreatureSpell; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; import java.util.UUID; /** - * * @author LoneFox - * */ public final class OpalCaryatid extends CardImpl { public OpalCaryatid(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); // When an opponent casts a creature spell, if Opal Caryatid is an enchantment, Opal Caryatid becomes a 2/2 Soldier creature. - TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new OpalCaryatidSoldierToken(), null, Duration.WhileOnBattlefield), - new FilterCreatureSpell(), false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), - "When an opponent casts a creature spell, if {this} is an enchantment, {this} becomes a 2/2 Soldier creature.")); + this.addAbility(new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect( + new CreatureToken( + 2, 2, "2/2 Soldier creature", SubType.SOLDIER + ), null, Duration.WhileOnBattlefield + ), StaticFilters.FILTER_SPELL_A_CREATURE, false) + .withInterveningIf(SourceIsEnchantmentCondition.instance) + .withRuleTextReplacement(true) + .setTriggerPhrase("When an opponent casts a creature spell, ")); } private OpalCaryatid(final OpalCaryatid card) { @@ -44,22 +41,3 @@ public final class OpalCaryatid extends CardImpl { return new OpalCaryatid(this); } } - -class OpalCaryatidSoldierToken extends TokenImpl { - - public OpalCaryatidSoldierToken() { - super("Soldier", "2/2 Soldier creature"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.SOLDIER); - power = new MageInt(2); - toughness = new MageInt(2); - } - - private OpalCaryatidSoldierToken(final OpalCaryatidSoldierToken token) { - super(token); - } - - public OpalCaryatidSoldierToken copy() { - return new OpalCaryatidSoldierToken(this); - } -} diff --git a/Mage.Sets/src/mage/cards/o/OpalChampion.java b/Mage.Sets/src/mage/cards/o/OpalChampion.java index f1b24cca13f..24e8386ebf7 100644 --- a/Mage.Sets/src/mage/cards/o/OpalChampion.java +++ b/Mage.Sets/src/mage/cards/o/OpalChampion.java @@ -1,39 +1,36 @@ - package mage.cards.o; -import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.SpellCastOpponentTriggeredAbility; -import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreatureSpell; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; import java.util.UUID; /** - * * @author LoneFox - * */ public final class OpalChampion extends CardImpl { public OpalChampion(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); // When an opponent casts a creature spell, if Opal Champion is an enchantment, Opal Champion becomes a 3/3 Knight creature with first strike. - TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new OpalChampionKnight(), null, Duration.WhileOnBattlefield), - new FilterCreatureSpell(), false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), - "When an opponent casts a creature spell, if {this} is an enchantment, {this} becomes a 3/3 Knight creature with first strike.")); + this.addAbility(new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect( + new CreatureToken( + 3, 3, "3/3 Knight creature with first strike", SubType.KNIGHT + ).withAbility(FirstStrikeAbility.getInstance()), null, Duration.WhileOnBattlefield + ), StaticFilters.FILTER_SPELL_A_CREATURE, false) + .withInterveningIf(SourceIsEnchantmentCondition.instance) + .withRuleTextReplacement(true) + .setTriggerPhrase("When an opponent casts a creature spell, ")); } private OpalChampion(final OpalChampion card) { @@ -45,22 +42,3 @@ public final class OpalChampion extends CardImpl { return new OpalChampion(this); } } - -class OpalChampionKnight extends TokenImpl { - - public OpalChampionKnight() { - super("Knight", "3/3 Knight creature with first strike"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.KNIGHT); - power = new MageInt(3); - toughness = new MageInt(3); - this.addAbility(FirstStrikeAbility.getInstance()); - } - private OpalChampionKnight(final OpalChampionKnight token) { - super(token); - } - - public OpalChampionKnight copy() { - return new OpalChampionKnight(this); - } -} diff --git a/Mage.Sets/src/mage/cards/o/OpalGargoyle.java b/Mage.Sets/src/mage/cards/o/OpalGargoyle.java index 584d69f6141..db6dd091d7d 100644 --- a/Mage.Sets/src/mage/cards/o/OpalGargoyle.java +++ b/Mage.Sets/src/mage/cards/o/OpalGargoyle.java @@ -1,39 +1,36 @@ - package mage.cards.o; -import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.SpellCastOpponentTriggeredAbility; -import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreatureSpell; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; import java.util.UUID; /** - * * @author LoneFox - * */ public final class OpalGargoyle extends CardImpl { public OpalGargoyle(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); // When an opponent casts a creature spell, if Opal Gargoyle is an enchantment, Opal Gargoyle becomes a 2/2 Gargoyle creature with flying. - TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new OpalGargoyleToken(), null, Duration.WhileOnBattlefield), - new FilterCreatureSpell(), false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), - "When an opponent casts a creature spell, if {this} is an enchantment, {this} becomes a 2/2 Gargoyle creature with flying.")); + this.addAbility(new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect( + new CreatureToken( + 2, 2, "2/2 Gargoyle creature with flying", SubType.GARGOYLE + ).withAbility(FlyingAbility.getInstance()), null, Duration.WhileOnBattlefield + ), StaticFilters.FILTER_SPELL_A_CREATURE, false) + .withInterveningIf(SourceIsEnchantmentCondition.instance) + .withRuleTextReplacement(true) + .setTriggerPhrase("When an opponent casts a creature spell, ")); } private OpalGargoyle(final OpalGargoyle card) { @@ -45,22 +42,3 @@ public final class OpalGargoyle extends CardImpl { return new OpalGargoyle(this); } } - -class OpalGargoyleToken extends TokenImpl { - - public OpalGargoyleToken() { - super("Gargoyle", "2/2 Gargoyle creature with flying"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.GARGOYLE); - power = new MageInt(2); - toughness = new MageInt(2); - this.addAbility(FlyingAbility.getInstance()); - } - private OpalGargoyleToken(final OpalGargoyleToken token) { - super(token); - } - - public OpalGargoyleToken copy() { - return new OpalGargoyleToken(this); - } -} diff --git a/Mage.Sets/src/mage/cards/o/OpalGuardian.java b/Mage.Sets/src/mage/cards/o/OpalGuardian.java index 40053381d52..8cf25a495c0 100644 --- a/Mage.Sets/src/mage/cards/o/OpalGuardian.java +++ b/Mage.Sets/src/mage/cards/o/OpalGuardian.java @@ -1,41 +1,39 @@ - package mage.cards.o; -import mage.MageInt; import mage.ObjectColor; -import mage.abilities.TriggeredAbility; import mage.abilities.common.SpellCastOpponentTriggeredAbility; -import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.ProtectionAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreatureSpell; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; import java.util.UUID; /** - * * @author LoneFox - * */ public final class OpalGuardian extends CardImpl { public OpalGuardian(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{W}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}{W}{W}"); // When an opponent casts a creature spell, if Opal Guardian is an enchantment, Opal Guardian becomes a 3/4 Gargoyle creature with flying and protection from red. - TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new OpalGuardianGargoyle(), null, Duration.WhileOnBattlefield), - new FilterCreatureSpell(), false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), - "When an opponent casts a creature spell, if {this} is an enchantment, {this} becomes a 3/4 Gargoyle creature with flying and protection from red.")); + this.addAbility(new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect( + new CreatureToken( + 3, 4, "3/4 Gargoyle creature with " + + "flying and protection from red", SubType.GARGOYLE + ).withAbility(FlyingAbility.getInstance()).withAbility(ProtectionAbility.from(ObjectColor.RED)), + null, Duration.WhileOnBattlefield + ), StaticFilters.FILTER_SPELL_A_CREATURE, false) + .withInterveningIf(SourceIsEnchantmentCondition.instance) + .setTriggerPhrase("When an opponent casts a creature spell, ")); } private OpalGuardian(final OpalGuardian card) { @@ -47,22 +45,3 @@ public final class OpalGuardian extends CardImpl { return new OpalGuardian(this); } } - -class OpalGuardianGargoyle extends TokenImpl { - public OpalGuardianGargoyle() { - super("Gargoyle", "3/4 Gargoyle creature with flying and protection from red"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.GARGOYLE); - power = new MageInt(3); - toughness = new MageInt(4); - this.addAbility(FlyingAbility.getInstance()); - this.addAbility(ProtectionAbility.from(ObjectColor.RED)); - } - private OpalGuardianGargoyle(final OpalGuardianGargoyle token) { - super(token); - } - - public OpalGuardianGargoyle copy() { - return new OpalGuardianGargoyle(this); - } -} diff --git a/Mage.Sets/src/mage/cards/o/OpalLakeGatekeepers.java b/Mage.Sets/src/mage/cards/o/OpalLakeGatekeepers.java index 9f9084899f1..aa933a62b71 100644 --- a/Mage.Sets/src/mage/cards/o/OpalLakeGatekeepers.java +++ b/Mage.Sets/src/mage/cards/o/OpalLakeGatekeepers.java @@ -2,35 +2,21 @@ package mage.cards.o; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.YouControlTwoOrMoreGatesCondition; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.common.GatesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.filter.common.FilterControlledPermanent; import java.util.UUID; /** * @author LevelX2 */ - - public final class OpalLakeGatekeepers extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent(); - - static { - filter.add(SubType.GATE.getPredicate()); - } - - private static final Condition gatesCondition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); - public OpalLakeGatekeepers(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); this.subtype.add(SubType.VEDALKEN); @@ -40,11 +26,8 @@ public final class OpalLakeGatekeepers extends CardImpl { this.toughness = new MageInt(4); // When Opal Lake Gatekeepers enters the battlefield, if you control two or more Gates, you may draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1), true), - gatesCondition, - "When Opal Lake Gatekeepers enters the battlefield, if you control two or more Gates, you may draw a card.") - .addHint(new ConditionHint(gatesCondition, "You control two or more Gates"))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1), true) + .withInterveningIf(YouControlTwoOrMoreGatesCondition.instance).addHint(GatesYouControlHint.instance)); } private OpalLakeGatekeepers(final OpalLakeGatekeepers card) { diff --git a/Mage.Sets/src/mage/cards/o/OpalTitan.java b/Mage.Sets/src/mage/cards/o/OpalTitan.java index 2f7e0167e9d..c8f00d4bd72 100644 --- a/Mage.Sets/src/mage/cards/o/OpalTitan.java +++ b/Mage.Sets/src/mage/cards/o/OpalTitan.java @@ -3,10 +3,8 @@ package mage.cards.o; import mage.MageObjectReference; import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; import mage.abilities.common.SpellCastOpponentTriggeredAbility; -import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.keyword.ProtectionAbility; import mage.cards.CardImpl; @@ -28,11 +26,11 @@ public final class OpalTitan extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); // When an opponent casts a creature spell, if Opal Titan is an enchantment, Opal Titan becomes a 4/4 Giant creature with protection from each of that spell's colors. - TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(Zone.BATTLEFIELD, new OpalTitanBecomesCreatureEffect(), - StaticFilters.FILTER_SPELL_A_CREATURE, false, SetTargetPointer.SPELL); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), - "When an opponent casts a creature spell, if Opal Titan is an enchantment, Opal Titan becomes a 4/4 Giant creature with protection from each of that spell's colors.")); - + this.addAbility(new SpellCastOpponentTriggeredAbility( + Zone.BATTLEFIELD, new OpalTitanBecomesCreatureEffect(), + StaticFilters.FILTER_SPELL_A_CREATURE, false, SetTargetPointer.SPELL + ).withInterveningIf(SourceIsEnchantmentCondition.instance) + .setTriggerPhrase("When an opponent casts a creature spell, ")); } private OpalTitan(final OpalTitan card) { @@ -49,7 +47,7 @@ class OpalTitanBecomesCreatureEffect extends ContinuousEffectImpl { OpalTitanBecomesCreatureEffect() { super(Duration.WhileOnBattlefield, Outcome.BecomeCreature); - staticText = "{this} becomes a 4/4 Giant creature with protection from each of that spell's colors."; + staticText = "it becomes a 4/4 Giant creature with protection from each of that spell's colors."; this.addDependencyType(DependencyType.BecomeCreature); } @@ -117,5 +115,4 @@ class OpalTitanBecomesCreatureEffect extends ContinuousEffectImpl { || layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.TypeChangingEffects_4; } - } diff --git a/Mage.Sets/src/mage/cards/o/Ophiomancer.java b/Mage.Sets/src/mage/cards/o/Ophiomancer.java index 4427d99cd68..ec9e127a3c1 100644 --- a/Mage.Sets/src/mage/cards/o/Ophiomancer.java +++ b/Mage.Sets/src/mage/cards/o/Ophiomancer.java @@ -1,24 +1,30 @@ - package mage.cards.o; -import java.util.UUID; import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.game.permanent.token.OphiomancerSnakeToken; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Ophiomancer extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterCreaturePermanent(SubType.SNAKE, "you control no Snakes"), ComparisonType.EQUAL_TO, 0 + ); + public Ophiomancer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.HUMAN); @@ -28,10 +34,9 @@ public final class Ophiomancer extends CardImpl { this.toughness = new MageInt(2); // At the beginning of each upkeep, if you control no Snakes, create a 1/1 black Snake creature token with deathtouch. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(TargetController.ANY, new CreateTokenEffect(new OphiomancerSnakeToken()), false), - new PermanentsOnTheBattlefieldCondition(new FilterCreaturePermanent(SubType.SNAKE, "no Snakes"), ComparisonType.EQUAL_TO, 0), - "At the beginning of each upkeep, if you control no Snakes, create a 1/1 black Snake creature token with deathtouch.")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.ANY, new CreateTokenEffect(new OphiomancerSnakeToken()), false + ).withInterveningIf(condition)); } private Ophiomancer(final Ophiomancer card) { diff --git a/Mage.Sets/src/mage/cards/o/OracleEnVec.java b/Mage.Sets/src/mage/cards/o/OracleEnVec.java index 042c879eed7..7a7802eb45d 100644 --- a/Mage.Sets/src/mage/cards/o/OracleEnVec.java +++ b/Mage.Sets/src/mage/cards/o/OracleEnVec.java @@ -13,7 +13,6 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.common.DestroyTargetEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -46,9 +45,10 @@ public final class OracleEnVec extends CardImpl { // {T}: Target opponent chooses any number of creatures they control. During that player’s next turn, the chosen // creatures attack if able, and other creatures can’t attack. At the beginning of that turn’s end step, // destroy each of the chosen creatures that didn’t attack this turn. Activate this ability only during your turn. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new OracleEnVecEffect(), new TapSourceCost(), MyTurnCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new OracleEnVecEffect(), new TapSourceCost(), MyTurnCondition.instance + ); ability.addTarget(new TargetOpponent()); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); } @@ -83,25 +83,27 @@ class OracleEnVecEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player opponent = game.getPlayer(this.getTargetPointer().getFirst(game, source)); - if (opponent != null) { - Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, new FilterControlledCreaturePermanent(), true); - if (target.choose(Outcome.Neutral, opponent.getId(), source.getSourceId(), source, game)) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), opponent.getId(), source, game)) { - if (target.getTargets().contains(permanent.getId())) { - RequirementEffect effect = new OracleEnVecMustAttackRequirementEffect(); - effect.setTargetPointer(new FixedTarget(permanent, game)); - game.addEffect(effect, source); - } else { - RestrictionEffect effect = new OracleEnVecCantAttackRestrictionEffect(); - effect.setTargetPointer(new FixedTarget(permanent, game)); - game.addEffect(effect, source); - } - } - game.addDelayedTriggeredAbility(new OracleEnVecDelayedTriggeredAbility(game.getTurnNum(), target.getTargets()), source); - return true; + if (opponent == null) { + return false; + } + Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE); + target.withNotTarget(true); + if (!target.choose(Outcome.Neutral, opponent.getId(), source.getSourceId(), source, game)) { + return false; + } + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), opponent.getId(), source, game)) { + if (target.getTargets().contains(permanent.getId())) { + RequirementEffect effect = new OracleEnVecMustAttackRequirementEffect(); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + } else { + RestrictionEffect effect = new OracleEnVecCantAttackRestrictionEffect(); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); } } - return false; + game.addDelayedTriggeredAbility(new OracleEnVecDelayedTriggeredAbility(game.getTurnNum(), target.getTargets()), source); + return true; } } diff --git a/Mage.Sets/src/mage/cards/o/OracleOfBones.java b/Mage.Sets/src/mage/cards/o/OracleOfBones.java index 67235fda3fb..37e594aae44 100644 --- a/Mage.Sets/src/mage/cards/o/OracleOfBones.java +++ b/Mage.Sets/src/mage/cards/o/OracleOfBones.java @@ -3,7 +3,6 @@ package mage.cards.o; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.TributeNotPaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.cost.CastFromHandForFreeEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.TributeAbility; @@ -11,7 +10,8 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.StaticFilters; +import mage.filter.FilterCard; +import mage.filter.common.FilterInstantOrSorceryCard; import java.util.UUID; @@ -20,6 +20,8 @@ import java.util.UUID; */ public final class OracleOfBones extends CardImpl { + private static final FilterCard filter = new FilterInstantOrSorceryCard("an instant or sorcery spell"); + public OracleOfBones(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); this.subtype.add(SubType.MINOTAUR); @@ -30,18 +32,14 @@ public final class OracleOfBones extends CardImpl { // Haste this.addAbility(HasteAbility.getInstance()); + // Tribute 2 this.addAbility(new TributeAbility(2)); + // When Oracle of Bones enters the battlefield, if tribute wasn't paid, // you may cast an instant or sorcery card from your hand without paying its mana cost. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CastFromHandForFreeEffect( - StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY - ), false), - TributeNotPaidCondition.instance, "When {this} enters, " + - "if tribute wasn't paid, you may cast an instant or " + - "sorcery spell from your hand without paying its mana cost." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CastFromHandForFreeEffect(filter)) + .withInterveningIf(TributeNotPaidCondition.instance)); } private OracleOfBones(final OracleOfBones card) { diff --git a/Mage.Sets/src/mage/cards/o/OraclesVault.java b/Mage.Sets/src/mage/cards/o/OraclesVault.java index 9ddbc215f7c..bdaf943dd52 100644 --- a/Mage.Sets/src/mage/cards/o/OraclesVault.java +++ b/Mage.Sets/src/mage/cards/o/OraclesVault.java @@ -6,7 +6,7 @@ import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; @@ -42,7 +42,7 @@ public final class OraclesVault extends CardImpl { // {T}: Exile the top card of your library. Until end of turn, you may play that card without paying its mana cost. // Activate this ability only if there are three or more brick counters on Oracle's Vault. - this.addAbility(new ConditionalActivatedAbility(new OraclesVaultFreeEffect(), new TapSourceCost(), condition)); + this.addAbility(new ActivateIfConditionActivatedAbility(new OraclesVaultFreeEffect(), new TapSourceCost(), condition)); } private OraclesVault(final OraclesVault card) { diff --git a/Mage.Sets/src/mage/cards/o/OrahSkyclaveHierophant.java b/Mage.Sets/src/mage/cards/o/OrahSkyclaveHierophant.java index 96a82a5c3e8..4cf1149e302 100644 --- a/Mage.Sets/src/mage/cards/o/OrahSkyclaveHierophant.java +++ b/Mage.Sets/src/mage/cards/o/OrahSkyclaveHierophant.java @@ -1,19 +1,25 @@ package mage.cards.o; import mage.MageInt; -import mage.MageObject; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.common.DiesThisOrAnotherTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.keyword.LifelinkAbility; +import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; import java.util.UUID; @@ -22,6 +28,14 @@ import java.util.UUID; */ public final class OrahSkyclaveHierophant extends CardImpl { + private static final FilterPermanent filterTrigger = new FilterControlledPermanent("Cleric you control"); + private static final FilterCard filterTarget = new FilterCard("Cleric card with lesser mana value"); + static { + filterTrigger.add(SubType.CLERIC.getPredicate()); + filterTarget.add(SubType.CLERIC.getPredicate()); + filterTarget.add(OrahSkyclaveHierophantPredicate.instance); + } + public OrahSkyclaveHierophant(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{B}"); @@ -35,7 +49,9 @@ public final class OrahSkyclaveHierophant extends CardImpl { this.addAbility(LifelinkAbility.getInstance()); // Whenever Orah, Skyclave Hierophant or another Cleric you control dies, return target Cleric card with lesser converted mana cost from your graveyard to the battlefield. - this.addAbility(new OrahSkyclaveHierophantTriggeredAbility()); + Ability ability = new DiesThisOrAnotherTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), false, filterTrigger); + ability.addTarget(new TargetCardInYourGraveyard(filterTarget)); + this.addAbility(ability); } private OrahSkyclaveHierophant(final OrahSkyclaveHierophant card) { @@ -48,57 +64,15 @@ public final class OrahSkyclaveHierophant extends CardImpl { } } -class OrahSkyclaveHierophantTriggeredAbility extends TriggeredAbilityImpl { - - OrahSkyclaveHierophantTriggeredAbility() { - super(Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect()); - setLeavesTheBattlefieldTrigger(true); - } - - private OrahSkyclaveHierophantTriggeredAbility(final OrahSkyclaveHierophantTriggeredAbility ability) { - super(ability); - } +enum OrahSkyclaveHierophantPredicate implements ObjectSourcePlayerPredicate { + instance; @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ZONE_CHANGE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (!zEvent.isDiesEvent() - || !zEvent.getTarget().isControlledBy(getControllerId()) - || (!zEvent.getTarget().hasSubtype(SubType.CLERIC, game) - && !zEvent.getTarget().getId().equals(getSourceId())) - ) { - return false; - } - FilterCard filterCard = new FilterCard( - "Cleric card with mana value less than " + (zEvent.getTarget().getManaValue()) - ); - filterCard.add(SubType.CLERIC.getPredicate()); - filterCard.add(new ManaValuePredicate( - ComparisonType.FEWER_THAN, zEvent.getTarget().getManaValue() - )); - this.getTargets().clear(); - this.addTarget(new TargetCardInYourGraveyard(filterCard)); - return true; - } - - @Override - public OrahSkyclaveHierophantTriggeredAbility copy() { - return new OrahSkyclaveHierophantTriggeredAbility(this); - } - - @Override - public String getRule() { - return "Whenever {this} or another Cleric you control dies, return target Cleric card " + - "with lesser mana value from your graveyard to the battlefield."; - } - - @Override - public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) { - return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game); + public boolean apply(ObjectSourcePlayer input, Game game) { + return CardUtil.getEffectValueFromAbility( + input.getSource(), "creatureDied", Permanent.class + ) + .filter(permanent -> input.getObject().getManaValue() < permanent.getManaValue()) + .isPresent(); } } diff --git a/Mage.Sets/src/mage/cards/o/OranRiefRecluse.java b/Mage.Sets/src/mage/cards/o/OranRiefRecluse.java index 526f453eafd..4a3bf001199 100644 --- a/Mage.Sets/src/mage/cards/o/OranRiefRecluse.java +++ b/Mage.Sets/src/mage/cards/o/OranRiefRecluse.java @@ -1,11 +1,9 @@ - package mage.cards.o; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.KickerAbility; @@ -14,24 +12,26 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author North */ public final class OranRiefRecluse extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying"); + private static final FilterPermanent filter = new FilterCreaturePermanent("creature with flying"); static { filter.add(new AbilityPredicate(FlyingAbility.class)); } public OranRiefRecluse(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.subtype.add(SubType.SPIDER); this.power = new MageInt(1); @@ -44,9 +44,9 @@ public final class OranRiefRecluse extends CardImpl { this.addAbility(ReachAbility.getInstance()); // When Oran-Rief Recluse enters the battlefield, if it was kicked, destroy target creature with flying. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), false); - ability.addTarget(new TargetCreaturePermanent(filter)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.ONCE, "When {this} enters, if it was kicked, destroy target creature with flying.")); + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()).withInterveningIf(KickedCondition.ONCE); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); } private OranRiefRecluse(final OranRiefRecluse card) { diff --git a/Mage.Sets/src/mage/cards/o/OratorOfOjutai.java b/Mage.Sets/src/mage/cards/o/OratorOfOjutai.java index 4b85e8d5274..e142e06615b 100644 --- a/Mage.Sets/src/mage/cards/o/OratorOfOjutai.java +++ b/Mage.Sets/src/mage/cards/o/OratorOfOjutai.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RevealedOrControlledDragonCondition; import mage.abilities.costs.common.RevealDragonFromHandCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.DefenderAbility; import mage.abilities.keyword.FlyingAbility; @@ -36,11 +35,8 @@ public final class OratorOfOjutai extends CardImpl { this.getSpellAbility().addCost(new RevealDragonFromHandCost()); // When Orator of Ojutai enters the battlefield, if you revealed a Dragon card or controlled a Dragon as you cast Orator of Ojutai, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)), - RevealedOrControlledDragonCondition.instance, "When {this} enters, " + - "if you revealed a Dragon card or controlled a Dragon as you cast this spell, draw a card." - ), new DragonOnTheBattlefieldWhileSpellWasCastWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .withInterveningIf(RevealedOrControlledDragonCondition.instance), new DragonOnTheBattlefieldWhileSpellWasCastWatcher()); } private OratorOfOjutai(final OratorOfOjutai card) { diff --git a/Mage.Sets/src/mage/cards/o/OrazcaRelic.java b/Mage.Sets/src/mage/cards/o/OrazcaRelic.java index 693775012da..06573ddbb5e 100644 --- a/Mage.Sets/src/mage/cards/o/OrazcaRelic.java +++ b/Mage.Sets/src/mage/cards/o/OrazcaRelic.java @@ -4,7 +4,7 @@ import mage.abilities.Ability; import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.hint.common.CitysBlessingHint; @@ -13,7 +13,6 @@ import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import java.util.UUID; @@ -32,14 +31,12 @@ public final class OrazcaRelic extends CardImpl { this.addAbility(new ColorlessManaAbility()); // {T}, Sacrifice Orazca Relic: You gain 3 life and draw a card. Activate this ability only if you have the city's blessing. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new GainLifeEffect(3), - new TapSourceCost(), - CitysBlessingCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new GainLifeEffect(3), new TapSourceCost(), CitysBlessingCondition.instance + ); ability.addCost(new SacrificeSourceCost()); ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); - ability.addHint(CitysBlessingHint.instance); - this.addAbility(ability); + this.addAbility(ability.addHint(CitysBlessingHint.instance)); } private OrazcaRelic(final OrazcaRelic card) { diff --git a/Mage.Sets/src/mage/cards/o/OrcSureshot.java b/Mage.Sets/src/mage/cards/o/OrcSureshot.java index 2775f54e368..a3b18451bac 100644 --- a/Mage.Sets/src/mage/cards/o/OrcSureshot.java +++ b/Mage.Sets/src/mage/cards/o/OrcSureshot.java @@ -10,10 +10,13 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -31,7 +34,7 @@ public final class OrcSureshot extends CardImpl { Ability ability = new EntersBattlefieldControlledTriggeredAbility( new BoostTargetEffect(-1,-1, Duration.EndOfTurn), StaticFilters.FILTER_ANOTHER_CREATURE); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/o/OrcishCaptain.java b/Mage.Sets/src/mage/cards/o/OrcishCaptain.java index 7babdaf7515..5ae5a5337ed 100644 --- a/Mage.Sets/src/mage/cards/o/OrcishCaptain.java +++ b/Mage.Sets/src/mage/cards/o/OrcishCaptain.java @@ -15,6 +15,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class OrcishCaptain extends CardImpl { // {1}: Flip a coin. If you win the flip, target Orc creature gets +2/+0 until end of turn. If you lose the flip, it gets -0/-2 until end of turn. Ability ability = new SimpleActivatedAbility(new OrcishCaptainEffect(), new GenericManaCost(1)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/o/OrcishHealer.java b/Mage.Sets/src/mage/cards/o/OrcishHealer.java index f3628345b66..330e5e64b03 100644 --- a/Mage.Sets/src/mage/cards/o/OrcishHealer.java +++ b/Mage.Sets/src/mage/cards/o/OrcishHealer.java @@ -19,6 +19,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -51,13 +52,13 @@ public final class OrcishHealer extends CardImpl { // {B}{B}{R}, {tap}: Regenerate target black or green creature. ability = new SimpleActivatedAbility(new RegenerateTargetEffect(), new ManaCostsImpl<>("{B}{B}{R}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // {R}{G}{G}, {tap}: Regenerate target black or green creature. ability = new SimpleActivatedAbility(new RegenerateTargetEffect(), new ManaCostsImpl<>("{R}{G}{G}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/o/OrcishSettlers.java b/Mage.Sets/src/mage/cards/o/OrcishSettlers.java index 2d33e36f563..2570380a90e 100644 --- a/Mage.Sets/src/mage/cards/o/OrcishSettlers.java +++ b/Mage.Sets/src/mage/cards/o/OrcishSettlers.java @@ -7,20 +7,14 @@ 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.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetLandPermanent; -import mage.util.CardUtil; +import mage.target.targetadjustment.XTargetsCountAdjuster; -import java.util.List; import java.util.UUID; /** @@ -38,9 +32,12 @@ public final class OrcishSettlers extends CardImpl { this.toughness = new MageInt(1); // {X}{X}{R}, {tap}, Sacrifice Orcish Settlers: Destroy X target lands. - Ability ability = new SimpleActivatedAbility(new OrcishSettlersEffect(), new ManaCostsImpl<>("{X}{X}{R}")); + Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect().setText("Destroy X target lands"), + new ManaCostsImpl<>("{X}{X}{R}")); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetLandPermanent()); + ability.setTargetAdjuster(new XTargetsCountAdjuster()); this.addAbility(ability); } @@ -53,43 +50,3 @@ public final class OrcishSettlers extends CardImpl { return new OrcishSettlers(this); } } - -class OrcishSettlersEffect extends OneShotEffect { - - OrcishSettlersEffect() { - super(Outcome.DestroyPermanent); - this.staticText = "Destroy X target lands"; - } - - private OrcishSettlersEffect(final OrcishSettlersEffect effect) { - super(effect); - } - - @Override - public OrcishSettlersEffect copy() { - return new OrcishSettlersEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - int amount = CardUtil.getSourceCostsTag(game, source, "X", 0); - if (amount == 0) { - return false; - } - TargetLandPermanent target = new TargetLandPermanent(amount); - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null - && target.canChoose(controller.getId(), source, game) - && controller.choose(Outcome.DestroyPermanent, target, source, game)) { - List targets = target.getTargets(); - targets.forEach((landId) -> { - Permanent land = game.getPermanent(landId); - if (land != null) { - land.destroy(source, game, false); - } - }); - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/o/OrderOfSuccession.java b/Mage.Sets/src/mage/cards/o/OrderOfSuccession.java index 9563f5df456..13901ce9c57 100644 --- a/Mage.Sets/src/mage/cards/o/OrderOfSuccession.java +++ b/Mage.Sets/src/mage/cards/o/OrderOfSuccession.java @@ -21,6 +21,7 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.players.PlayerList; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -98,7 +99,7 @@ class OrderOfSuccessionEffect extends OneShotEffect { if (currentPlayer != null && game.getState().getPlayersInRange(controller.getId(), game).contains(currentPlayer.getId())) { FilterCreaturePermanent filter = new FilterCreaturePermanent("creature controlled by " + nextPlayer.getLogName()); filter.add(new ControllerIdPredicate(nextPlayer.getId())); - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); target.withNotTarget(true); if (target.canChoose(currentPlayer.getId(), source, game)) { if (currentPlayer.chooseTarget(outcome, target, source, game)) { diff --git a/Mage.Sets/src/mage/cards/o/OrdruunMentor.java b/Mage.Sets/src/mage/cards/o/OrdruunMentor.java index a42c25b507a..6e6a8b680bd 100644 --- a/Mage.Sets/src/mage/cards/o/OrdruunMentor.java +++ b/Mage.Sets/src/mage/cards/o/OrdruunMentor.java @@ -1,21 +1,21 @@ package mage.cards.o; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.common.AttacksPlayerWithCreaturesTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.MentorAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SetTargetPointer; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.util.CardUtil; @@ -27,6 +27,12 @@ import java.util.UUID; */ public final class OrdruunMentor extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("creature that's attacking that player"); + + static { + filter.add(OrdruunMentorPredicate.instance); + } + public OrdruunMentor(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R/W}"); @@ -39,7 +45,10 @@ public final class OrdruunMentor extends CardImpl { this.addAbility(new MentorAbility()); // Whenever you attack a player, target creature that's attacking that player gains first strike until end of turn. - this.addAbility(new OrdruunMentorTriggeredAbility()); + Ability ability = new AttacksPlayerWithCreaturesTriggeredAbility( + new GainAbilityTargetEffect(FirstStrikeAbility.getInstance()), SetTargetPointer.NONE); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); } private OrdruunMentor(final OrdruunMentor card) { @@ -51,54 +60,13 @@ public final class OrdruunMentor extends CardImpl { return new OrdruunMentor(this); } } - -class OrdruunMentorTriggeredAbility extends TriggeredAbilityImpl { - - private enum OrdruunMentorPredicate implements ObjectSourcePlayerPredicate { - instance; - - @Override - public boolean apply(ObjectSourcePlayer input, Game game) { - return CardUtil.getEffectValueFromAbility( - input.getSource(), "playerAttacked", UUID.class - ) - .filter(uuid -> uuid.equals(game.getCombat().getDefenderId(input.getObject().getId()))) - .isPresent(); - } - } - - private static final FilterPermanent filter = new FilterCreaturePermanent("creature that's attacking that player"); - - static { - filter.add(OrdruunMentorPredicate.instance); - } - - OrdruunMentorTriggeredAbility() { - super(Zone.BATTLEFIELD, new GainAbilityTargetEffect(FirstStrikeAbility.getInstance()).setText("")); - this.setTriggerPhrase("Whenever you attack a player, "); - this.addTarget(new TargetPermanent(filter)); - } - - private OrdruunMentorTriggeredAbility(final OrdruunMentorTriggeredAbility ability) { - super(ability); - } +enum OrdruunMentorPredicate implements ObjectSourcePlayerPredicate { + instance; @Override - public OrdruunMentorTriggeredAbility copy() { - return new OrdruunMentorTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DEFENDER_ATTACKED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (!isControlledBy(event.getPlayerId()) || game.getPlayer(event.getTargetId()) == null) { - return false; - } - this.getEffects().setValue("playerAttacked", event.getTargetId()); - return true; + public boolean apply(ObjectSourcePlayer input, Game game) { + return CardUtil.getEffectValueFromAbility(input.getSource(), "playerAttacked", UUID.class) + .filter(uuid -> uuid.equals(game.getCombat().getDefenderId(input.getObject().getId()))) + .isPresent(); } } diff --git a/Mage.Sets/src/mage/cards/o/OrimsTouch.java b/Mage.Sets/src/mage/cards/o/OrimsTouch.java index bdfcd3eb30d..7f93fa5780d 100644 --- a/Mage.Sets/src/mage/cards/o/OrimsTouch.java +++ b/Mage.Sets/src/mage/cards/o/OrimsTouch.java @@ -1,7 +1,6 @@ package mage.cards.o; -import java.util.UUID; import mage.abilities.condition.LockedInCondition; import mage.abilities.condition.common.KickedCondition; import mage.abilities.decorator.ConditionalReplacementEffect; @@ -14,6 +13,8 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** * * @author fireshoes @@ -31,7 +32,7 @@ public final class OrimsTouch extends CardImpl { new PreventDamageToTargetEffect(Duration.EndOfTurn, 4), new LockedInCondition(KickedCondition.ONCE), new PreventDamageToTargetEffect(Duration.EndOfTurn, 2)); - effect.setText("Prevent the next 2 damage that would be dealt to any target this turn. If Orim's Touch was kicked, prevent the next 4 damage that would be dealt to that permanent or player this turn instead"); + effect.setText("Prevent the next 2 damage that would be dealt to any target this turn. If {this} was kicked, prevent the next 4 damage that would be dealt to that permanent or player this turn instead"); this.getSpellAbility().addTarget(new TargetAnyTarget()); this.getSpellAbility().addEffect(effect); } diff --git a/Mage.Sets/src/mage/cards/o/OrneryDilophosaur.java b/Mage.Sets/src/mage/cards/o/OrneryDilophosaur.java index fce5c2b72cf..f56f5f3f092 100644 --- a/Mage.Sets/src/mage/cards/o/OrneryDilophosaur.java +++ b/Mage.Sets/src/mage/cards/o/OrneryDilophosaur.java @@ -3,7 +3,6 @@ package mage.cards.o; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.FerociousCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.hint.common.FerociousHint; import mage.abilities.keyword.DeathtouchAbility; @@ -31,12 +30,8 @@ public final class OrneryDilophosaur extends CardImpl { this.addAbility(DeathtouchAbility.getInstance()); // Whenever Ornery Dilophosaur attacks, if you control a creature with power 4 or greater, Ornery Dilophosaur gets +2/+2 until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility( - new BoostSourceEffect(2, 2, Duration.EndOfTurn), false - ), FerociousCondition.instance, "Whenever {this} attacks, " + - "if you control a creature with power 4 or greater, {this} gets +2/+2 until end of turn." - ).addHint(FerociousHint.instance)); + this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(2, 2, Duration.EndOfTurn)) + .withInterveningIf(FerociousCondition.instance).addHint(FerociousHint.instance)); } private OrneryDilophosaur(final OrneryDilophosaur card) { diff --git a/Mage.Sets/src/mage/cards/o/Ornitharch.java b/Mage.Sets/src/mage/cards/o/Ornitharch.java index b23b8a2f31a..f620a3def22 100644 --- a/Mage.Sets/src/mage/cards/o/Ornitharch.java +++ b/Mage.Sets/src/mage/cards/o/Ornitharch.java @@ -1,12 +1,8 @@ - package mage.cards.o; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.TributeNotPaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.TributeAbility; @@ -16,14 +12,15 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.game.permanent.token.BirdToken; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Ornitharch extends CardImpl { public Ornitharch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); this.subtype.add(SubType.ARCHON); this.power = new MageInt(3); @@ -31,12 +28,13 @@ public final class Ornitharch extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); + // Tribute 2 this.addAbility(new TributeAbility(2)); + // When Ornitharch enters the battlefield, if tribute wasn't paid, create two 1/1 white Bird creature tokens with flying. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new BirdToken(), 2), false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, TributeNotPaidCondition.instance, - "When {this} enters, if tribute wasn't paid, create two 1/1 white Bird creature tokens with flying.")); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new BirdToken(), 2)) + .withInterveningIf(TributeNotPaidCondition.instance)); } private Ornitharch(final Ornitharch card) { diff --git a/Mage.Sets/src/mage/cards/o/OrvarTheAllForm.java b/Mage.Sets/src/mage/cards/o/OrvarTheAllForm.java index 607d71b74cc..160f051cb85 100644 --- a/Mage.Sets/src/mage/cards/o/OrvarTheAllForm.java +++ b/Mage.Sets/src/mage/cards/o/OrvarTheAllForm.java @@ -8,7 +8,6 @@ import mage.abilities.Mode; import mage.abilities.common.DiscardedByOpponentTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.abilities.keyword.ChangelingAbility; @@ -54,17 +53,11 @@ public final class OrvarTheAllForm extends CardImpl { this.addAbility(new ChangelingAbility()); // Whenever you cast an instant or sorcery spell, if it targets one or more other permanents you control, create a token that's a copy of one of those permanents. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new SpellCastControllerTriggeredAbility( - new OrvarTheAllFormEffect(), - StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY, - false, SetTargetPointer.SPELL - ), - OrvarTheAllFormCondition.instance, - "Whenever you cast an instant or sorcery spell, " - + "if it targets one or more other permanents you control, " - + "create a token that's a copy of one of those permanents." - )); + this.addAbility(new SpellCastControllerTriggeredAbility( + new OrvarTheAllFormEffect(), + StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, + false, SetTargetPointer.SPELL + ).withInterveningIf(OrvarTheAllFormCondition.instance)); // When a spell or ability an opponent controls causes you to discard this card, create a token that's a copy of target permanent. Ability ability = new DiscardedByOpponentTriggeredAbility(new CreateTokenCopyTargetEffect()); @@ -109,12 +102,18 @@ enum OrvarTheAllFormCondition implements Condition { .map(Controllable::getControllerId) .anyMatch(source::isControlledBy); } + + @Override + public String toString() { + return "it targets one or more other permanents you control"; + } } class OrvarTheAllFormEffect extends OneShotEffect { OrvarTheAllFormEffect() { super(Outcome.Benefit); + staticText = "create a token that's a copy of one of those permanents."; } private OrvarTheAllFormEffect(final OrvarTheAllFormEffect effect) { diff --git a/Mage.Sets/src/mage/cards/o/OrzhovAdvokist.java b/Mage.Sets/src/mage/cards/o/OrzhovAdvokist.java index 378703e74f0..b971ad23eed 100644 --- a/Mage.Sets/src/mage/cards/o/OrzhovAdvokist.java +++ b/Mage.Sets/src/mage/cards/o/OrzhovAdvokist.java @@ -3,17 +3,16 @@ package mage.cards.o; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.combat.CantAttackYouAllEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; @@ -24,11 +23,10 @@ import mage.target.common.TargetControlledCreaturePermanent; import java.util.ArrayList; import java.util.List; -import java.util.Objects; +import java.util.Optional; import java.util.UUID; /** - * * @author LevelX2 */ public final class OrzhovAdvokist extends CardImpl { @@ -75,37 +73,42 @@ class OrzhovAdvokistEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - List players = new ArrayList<>(); - List creatures = new ArrayList<>(); - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - if (player.chooseUse(outcome, "Put two +1/+1 counters on a creature you control?", source, game)) { - Target target = new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("a creature you control (to add two +1/+1 counters on it)")); - if (player.choose(outcome, target, source, game)) { - creatures.add(target.getFirstTarget()); - players.add(player.getId()); - } - - } - } - } - for (UUID creatureId : creatures) { - Permanent creature = game.getPermanent(creatureId); - if (creature != null) { - creature.addCounters(CounterType.P1P1.createInstance(2), creature.getControllerId(), source, game); - } - } - for (UUID playerId : players) { - if (!Objects.equals(playerId, source.getControllerId())) { - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - filter.add(new ControllerIdPredicate(playerId)); - game.addEffect(new CantAttackYouAllEffect(Duration.UntilYourNextTurn, filter, true), source); - } - } - return true; + if (controller == null) { + return false; } - return false; + List players = new ArrayList<>(); + List creatures = new ArrayList<>(); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player == null || !player.chooseUse(outcome, "Put two +1/+1 counters on a creature you control?", source, game)) { + continue; + } + Target target = new TargetControlledCreaturePermanent(0, 1); + target.withNotTarget(true); + target.withChooseHint("to add counters to"); + player.choose(outcome, target, source, game); + Optional.ofNullable(target) + .map(Target::getFirstTarget) + .map(game::getPermanent) + .ifPresent(permanent -> { + creatures.add(permanent.getId()); + players.add(player.getId()); + }); + } + for (UUID creatureId : creatures) { + Permanent creature = game.getPermanent(creatureId); + if (creature != null) { + creature.addCounters(CounterType.P1P1.createInstance(2), creature.getControllerId(), source, game); + } + } + for (UUID playerId : players) { + if (source.isControlledBy(playerId)) { + continue; + } + FilterCreaturePermanent filter = new FilterCreaturePermanent(); + filter.add(new ControllerIdPredicate(playerId)); + game.addEffect(new CantAttackYouAllEffect(Duration.UntilYourNextTurn, filter, true), source); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/o/OsaiVultures.java b/Mage.Sets/src/mage/cards/o/OsaiVultures.java index 878f35c85c8..4a43fe7f757 100644 --- a/Mage.Sets/src/mage/cards/o/OsaiVultures.java +++ b/Mage.Sets/src/mage/cards/o/OsaiVultures.java @@ -1,47 +1,48 @@ - package mage.cards.o; -import java.util.UUID; import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.MorbidCondition; import mage.abilities.costs.common.RemoveCountersSourceCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.hint.common.MorbidHint; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.TargetController; -import mage.constants.Zone; import mage.counters.CounterType; +import java.util.UUID; + /** - * * @author LoneFox */ public final class OsaiVultures extends CardImpl { public OsaiVultures(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.subtype.add(SubType.BIRD); this.power = new MageInt(1); this.toughness = new MageInt(1); // Flying this.addAbility(FlyingAbility.getInstance()); + // At the beginning of each end step, if a creature died this turn, put a carrion counter on Osai Vultures. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new BeginningOfEndStepTriggeredAbility( - TargetController.ANY, new AddCountersSourceEffect(CounterType.CARRION.createInstance()), false), MorbidCondition.instance, - "At the beginning of each end step, if a creature died this turn, put a carrion counter on {this}.").addHint(MorbidHint.instance)); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.ANY, new AddCountersSourceEffect(CounterType.CARRION.createInstance()), false + ).withInterveningIf(MorbidCondition.instance).addHint(MorbidHint.instance)); + // Remove two carrion counters from Osai Vultures: Osai Vultures gets +1/+1 until end of turn. - this.addAbility(new SimpleActivatedAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn), - new RemoveCountersSourceCost(CounterType.CARRION.createInstance(2)))); + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(1, 1, Duration.EndOfTurn), + new RemoveCountersSourceCost(CounterType.CARRION.createInstance(2)) + )); } private OsaiVultures(final OsaiVultures card) { diff --git a/Mage.Sets/src/mage/cards/o/OtepecHuntmaster.java b/Mage.Sets/src/mage/cards/o/OtepecHuntmaster.java index 88824db9976..ce862ee9d13 100644 --- a/Mage.Sets/src/mage/cards/o/OtepecHuntmaster.java +++ b/Mage.Sets/src/mage/cards/o/OtepecHuntmaster.java @@ -18,6 +18,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -47,7 +48,7 @@ public final class OtepecHuntmaster extends CardImpl { // {T}: Target Dinosaur gains haste until end of turn. Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter2)); + ability.addTarget(new TargetPermanent(filter2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/o/Ouroboroid.java b/Mage.Sets/src/mage/cards/o/Ouroboroid.java new file mode 100644 index 00000000000..91728108fcd --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/Ouroboroid.java @@ -0,0 +1,44 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerValue; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Ouroboroid extends CardImpl { + + public Ouroboroid(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}"); + + this.subtype.add(SubType.PLANT); + this.subtype.add(SubType.WURM); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // At the beginning of combat on your turn, put X +1/+1 counters on each creature you control, where X is this creature's power. + this.addAbility(new BeginningOfCombatTriggeredAbility(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), SourcePermanentPowerValue.NOT_NEGATIVE, + StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("put X +1/+1 counters on each creature you control, where X is {this}'s power"))); + } + + private Ouroboroid(final Ouroboroid card) { + super(card); + } + + @Override + public Ouroboroid copy() { + return new Ouroboroid(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OutcasterTrailblazer.java b/Mage.Sets/src/mage/cards/o/OutcasterTrailblazer.java index a845a601fdb..8aadce60736 100644 --- a/Mage.Sets/src/mage/cards/o/OutcasterTrailblazer.java +++ b/Mage.Sets/src/mage/cards/o/OutcasterTrailblazer.java @@ -1,7 +1,7 @@ package mage.cards.o; import mage.MageInt; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.mana.AddManaOfAnyColorEffect; @@ -24,7 +24,7 @@ import java.util.UUID; public final class OutcasterTrailblazer extends CardImpl { private static final FilterPermanent filter - = new FilterControlledCreaturePermanent("another creature with power 4 or greater"); + = new FilterControlledCreaturePermanent("another creature you control with power 4 or greater"); static { filter.add(AnotherPredicate.instance); @@ -43,7 +43,7 @@ public final class OutcasterTrailblazer extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new AddManaOfAnyColorEffect())); // Whenever another creature with power 4 or greater you control enters, draw a card. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new DrawCardSourceControllerEffect(1), filter)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility(new DrawCardSourceControllerEffect(1), filter)); // Plot {2}{G} this.addAbility(new PlotAbility("{2}{G}")); diff --git a/Mage.Sets/src/mage/cards/o/OuterRimSlaver.java b/Mage.Sets/src/mage/cards/o/OuterRimSlaver.java index 9e71e43fb55..167b552eac6 100644 --- a/Mage.Sets/src/mage/cards/o/OuterRimSlaver.java +++ b/Mage.Sets/src/mage/cards/o/OuterRimSlaver.java @@ -1,6 +1,5 @@ package mage.cards.o; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -13,10 +12,11 @@ import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.other.AnotherTargetPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author Styxo */ public final class OuterRimSlaver extends CardImpl { @@ -32,14 +32,10 @@ public final class OuterRimSlaver extends CardImpl { Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.BOUNTY.createInstance()) .setText("you may put a bounty counter on target creature"), true); ability.addEffect(new FightTargetsEffect().setText("If you do, another target creature fights that creature")); - TargetCreaturePermanent target = new TargetCreaturePermanent(new FilterCreaturePermanent("creature to put a bounty counter on it")); - target.setTargetTag(1); - ability.addTarget(target); + ability.addTarget(new TargetPermanent(new FilterCreaturePermanent("creature to put a bounty counter on it")).setTargetTag(1)); FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature to fight that creature that gets the bounty counter"); filter.add(new AnotherTargetPredicate(2)); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter); - target2.setTargetTag(2); - ability.addTarget(target2); + ability.addTarget(new TargetPermanent(filter).setTargetTag(2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/o/Outmaneuver.java b/Mage.Sets/src/mage/cards/o/Outmaneuver.java index d08a604e652..8278746a83b 100644 --- a/Mage.Sets/src/mage/cards/o/Outmaneuver.java +++ b/Mage.Sets/src/mage/cards/o/Outmaneuver.java @@ -11,6 +11,7 @@ import mage.constants.Outcome; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.BlockedPredicate; import mage.game.Game; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.XTargetsCountAdjuster; @@ -31,7 +32,7 @@ public final class Outmaneuver extends CardImpl { // X target blocked creatures assign their combat damage this turn as though they weren't blocked. this.getSpellAbility().addEffect(new OutmaneuverEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().setTargetAdjuster(new XTargetsCountAdjuster()); } diff --git a/Mage.Sets/src/mage/cards/o/OversoldCemetery.java b/Mage.Sets/src/mage/cards/o/OversoldCemetery.java index e913ac234ab..b3af14b9f83 100644 --- a/Mage.Sets/src/mage/cards/o/OversoldCemetery.java +++ b/Mage.Sets/src/mage/cards/o/OversoldCemetery.java @@ -1,31 +1,34 @@ package mage.cards.o; -import java.util.UUID; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.Ability; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; import mage.target.common.TargetCardInGraveyard; +import java.util.UUID; + /** - * * @author fireshoes */ public final class OversoldCemetery extends CardImpl { + private static final Condition condition = new CardsInControllerGraveyardCondition(4, StaticFilters.FILTER_CARD_CREATURES); + public OversoldCemetery(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); // At the beginning of your upkeep, if you have four or more creature cards in your graveyard, you may return target creature card from your graveyard to your hand. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), true); + Ability ability = new BeginningOfUpkeepTriggeredAbility( + new ReturnFromGraveyardToHandTargetEffect(), true + ).withInterveningIf(condition); ability.addTarget(new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURE)); - CardsInControllerGraveyardCondition condition = new CardsInControllerGraveyardCondition(4, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, condition, "At the beginning of your upkeep, if you have four or more creature cards in your graveyard, you may return target creature card from your graveyard to your hand.")); + this.addAbility(ability); } private OversoldCemetery(final OversoldCemetery card) { diff --git a/Mage.Sets/src/mage/cards/o/OwlbearCub.java b/Mage.Sets/src/mage/cards/o/OwlbearCub.java index 10f8af835bd..c3f57105b5a 100644 --- a/Mage.Sets/src/mage/cards/o/OwlbearCub.java +++ b/Mage.Sets/src/mage/cards/o/OwlbearCub.java @@ -53,7 +53,7 @@ class OwlbearCubTriggeredAbility extends TriggeredAbilityImpl { OwlbearCubTriggeredAbility() { super(Zone.BATTLEFIELD, new OwlbearCubEffect()); this.withFlavorWord("Mama's Coming"); - setTriggerPhrase("Whenever Owlbear Cub attacks a player who controls eight or more lands, "); + setTriggerPhrase("Whenever {this} attacks a player who controls eight or more lands, "); } private OwlbearCubTriggeredAbility(final OwlbearCubTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/p/PackHunt.java b/Mage.Sets/src/mage/cards/p/PackHunt.java index f4622fc58ee..020e8a3ad73 100644 --- a/Mage.Sets/src/mage/cards/p/PackHunt.java +++ b/Mage.Sets/src/mage/cards/p/PackHunt.java @@ -45,7 +45,8 @@ class PackHuntEffect extends OneShotEffect { PackHuntEffect() { super(Outcome.Benefit); - this.staticText = "Search your library for up to three cards with the same name as target creature, reveal them, and put them into your hand. Then shuffle"; + this.staticText = "Search your library for up to three cards with the same name as target creature, " + + "reveal them, put them into your hand, then shuffle"; } private PackHuntEffect(final PackHuntEffect effect) { @@ -60,6 +61,9 @@ class PackHuntEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } FilterCard filter = new FilterPermanentCard(); filter.add(new NamePredicate(permanent.getName())); return new SearchLibraryPutInHandEffect(new TargetCardInLibrary(0,3, filter), true).apply(game, source); diff --git a/Mage.Sets/src/mage/cards/p/PacksongPup.java b/Mage.Sets/src/mage/cards/p/PacksongPup.java index cdb22dbfbfd..81e5d8ab0db 100644 --- a/Mage.Sets/src/mage/cards/p/PacksongPup.java +++ b/Mage.Sets/src/mage/cards/p/PacksongPup.java @@ -1,16 +1,15 @@ package mage.cards.p; import mage.MageInt; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.SourcePermanentPowerValue; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -28,7 +27,7 @@ import java.util.UUID; */ public final class PacksongPup extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent(); + private static final FilterPermanent filter = new FilterControlledPermanent("you control another Wolf or Werewolf"); static { filter.add(AnotherPredicate.instance); @@ -39,7 +38,7 @@ public final class PacksongPup extends CardImpl { } private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); - private static final Hint hint = new ConditionHint(condition, "You control another Wolf or Werewolf"); + private static final Hint hint = new ConditionHint(condition); public PacksongPup(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); @@ -49,15 +48,14 @@ public final class PacksongPup extends CardImpl { this.toughness = new MageInt(1); // At the beginning of combat on your turn, if you control another Wolf or Werewolf, put a +1/+1 counter on Packsong Pup. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance()) - ), condition, "At the beginning of combat on your turn," + - " if you control another Wolf or Werewolf, put a +1/+1 counter on {this}" - ).addHint(hint)); + this.addAbility(new BeginningOfCombatTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()) + ).withInterveningIf(condition).addHint(hint)); // When Packsong Pup dies, you gain life equal to its power. - this.addAbility(new DiesSourceTriggeredAbility(new GainLifeEffect(SourcePermanentPowerValue.NOT_NEGATIVE).setText("you gain life equal to its power"))); + this.addAbility(new DiesSourceTriggeredAbility( + new GainLifeEffect(SourcePermanentPowerValue.NOT_NEGATIVE).setText("you gain life equal to its power") + )); } private PacksongPup(final PacksongPup card) { diff --git a/Mage.Sets/src/mage/cards/p/PalaceJailer.java b/Mage.Sets/src/mage/cards/p/PalaceJailer.java index 22d324f9f2f..541d407572a 100644 --- a/Mage.Sets/src/mage/cards/p/PalaceJailer.java +++ b/Mage.Sets/src/mage/cards/p/PalaceJailer.java @@ -25,9 +25,12 @@ import mage.game.ExileZone; import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.util.CardUtil; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -47,7 +50,7 @@ public final class PalaceJailer extends CardImpl { // When Palace Jailer enters the battlefield, exile target creature an opponent controls until an opponent becomes the monarch. (That creature returns under its owner's control.) Ability ability = new EntersBattlefieldTriggeredAbility(new PalaceJailerExileEffect()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new OnOpponentBecomesMonarchReturnExiledToBattlefieldAbility())); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/PaladinOfAtonement.java b/Mage.Sets/src/mage/cards/p/PaladinOfAtonement.java index c28eb82f0cc..df6715b1f03 100644 --- a/Mage.Sets/src/mage/cards/p/PaladinOfAtonement.java +++ b/Mage.Sets/src/mage/cards/p/PaladinOfAtonement.java @@ -1,15 +1,12 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.condition.common.LiveLostLastTurnCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.SourcePermanentToughnessValue; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -17,8 +14,9 @@ import mage.constants.SubType; import mage.constants.TargetController; import mage.counters.CounterType; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class PaladinOfAtonement extends CardImpl { @@ -32,14 +30,14 @@ public final class PaladinOfAtonement extends CardImpl { this.toughness = new MageInt(1); // At the beginning of each upkeep, if you lost life last turn, put a +1/+1 counter on Paladin of Atonement. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(TargetController.ANY, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false), - LiveLostLastTurnCondition.instance, - "At the beginning of each upkeep, if you lost life last turn, put a +1/+1 counter on {this}")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.ANY, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false + ).withInterveningIf(LiveLostLastTurnCondition.instance)); // When Paladin of Atonement dies, you gain life equal to it's toughness. - this.addAbility(new DiesSourceTriggeredAbility(new GainLifeEffect(SourcePermanentToughnessValue.instance, - "you gain life equal to its toughness"))); + this.addAbility(new DiesSourceTriggeredAbility(new GainLifeEffect( + SourcePermanentToughnessValue.instance, "you gain life equal to its toughness" + ))); } private PaladinOfAtonement(final PaladinOfAtonement card) { diff --git a/Mage.Sets/src/mage/cards/p/PalanisHatcher.java b/Mage.Sets/src/mage/cards/p/PalanisHatcher.java index cd85c033cd5..f454171794c 100644 --- a/Mage.Sets/src/mage/cards/p/PalanisHatcher.java +++ b/Mage.Sets/src/mage/cards/p/PalanisHatcher.java @@ -2,15 +2,15 @@ package mage.cards.p; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.SacrificeControllerEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.HasteAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -29,7 +29,10 @@ import java.util.UUID; public final class PalanisHatcher extends CardImpl { private static final FilterPermanent filter = new FilterPermanent(SubType.DINOSAUR, "Dinosaurs"); - private static final FilterControlledPermanent filterEgg = new FilterControlledPermanent(SubType.EGG, "egg"); + private static final FilterPermanent filterEgg = new FilterControlledPermanent(SubType.EGG, "an Egg"); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.EGG, "you control one or more Eggs") + ); public PalanisHatcher(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{G}"); @@ -39,26 +42,18 @@ public final class PalanisHatcher extends CardImpl { this.toughness = new MageInt(3); // Other Dinosaurs you control have haste. - this.addAbility(new SimpleStaticAbility( - new GainAbilityControlledEffect( - HasteAbility.getInstance(), - Duration.WhileOnBattlefield, - filter, true - ) - )); + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + HasteAbility.getInstance(), Duration.WhileOnBattlefield, filter, true + ))); // When Palani's Hatcher enters the battlefield, create two 0/1 green Dinosaur Egg creature tokens. this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new DinosaurEggToken(), 2))); // At the beginning of combat on your turn, if you control one or more Eggs, sacrifice an Egg, then create a 3/3 green Dinosaur creature token. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - new SacrificeControllerEffect(filterEgg, 1, "") - ), new PermanentsOnTheBattlefieldCondition(filterEgg), - "At the beginning of combat on your turn, if you control one or more Eggs, " - + "sacrifice an Egg, then create a 3/3 green Dinosaur creature token." - ); - ability.addEffect(new CreateTokenEffect(new DinosaurVanillaToken())); + Ability ability = new BeginningOfCombatTriggeredAbility( + new SacrificeControllerEffect(filterEgg, 1, "") + ).withInterveningIf(condition); + ability.addEffect(new CreateTokenEffect(new DinosaurVanillaToken()).concatBy(", then")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/Paleoloth.java b/Mage.Sets/src/mage/cards/p/Paleoloth.java index e184868b234..891fbd05b65 100644 --- a/Mage.Sets/src/mage/cards/p/Paleoloth.java +++ b/Mage.Sets/src/mage/cards/p/Paleoloth.java @@ -1,37 +1,35 @@ package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.PowerPredicate; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class Paleoloth extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature with power 5 or greater"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("another creature you control with power 5 or greater"); static { filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 4)); filter.add(AnotherPredicate.instance); } - private static final String rule = "Whenever another creature with power 5 or greater you control enters, you may return target creature card from your graveyard to your hand."; - public Paleoloth(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); this.subtype.add(SubType.BEAST); @@ -40,10 +38,11 @@ public final class Paleoloth extends CardImpl { this.toughness = new MageInt(5); // Whenever another creature with power 5 or greater you control enters, you may return target creature card from your graveyard to your hand. - Ability ability = new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToHandTargetEffect(), filter, true); + Ability ability = new EntersBattlefieldAllTriggeredAbility( + new ReturnFromGraveyardToHandTargetEffect(), filter, true + ); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE)); this.addAbility(ability); - } private Paleoloth(final Paleoloth card) { diff --git a/Mage.Sets/src/mage/cards/p/PangTongYoungPhoenix.java b/Mage.Sets/src/mage/cards/p/PangTongYoungPhoenix.java index 608693b2ec4..4fa4d5274ee 100644 --- a/Mage.Sets/src/mage/cards/p/PangTongYoungPhoenix.java +++ b/Mage.Sets/src/mage/cards/p/PangTongYoungPhoenix.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -12,19 +10,18 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Duration; import mage.constants.SuperType; -import mage.constants.Zone; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class PangTongYoungPhoenix extends CardImpl { public PangTongYoungPhoenix(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ADVISOR); @@ -32,8 +29,10 @@ public final class PangTongYoungPhoenix extends CardImpl { this.toughness = new MageInt(2); // {tap}: Target creature gets +0/+2 until end of turn. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new BoostTargetEffect(0, 2, Duration.EndOfTurn), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new BoostTargetEffect(0, 2), new TapSourceCost(), + MyTurnBeforeAttackersDeclaredCondition.instance + ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/ParagonOfEternalWilds.java b/Mage.Sets/src/mage/cards/p/ParagonOfEternalWilds.java index f7f6694dad8..a049ed9bf0d 100644 --- a/Mage.Sets/src/mage/cards/p/ParagonOfEternalWilds.java +++ b/Mage.Sets/src/mage/cards/p/ParagonOfEternalWilds.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -15,34 +13,34 @@ import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.TargetController; -import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class ParagonOfEternalWilds extends CardImpl { - + private static final FilterCreaturePermanent filterGreen = new FilterCreaturePermanent("green creatures you control"); private static final FilterControlledCreaturePermanent filterGreen2 = new FilterControlledCreaturePermanent("another target green creature you control"); static { filterGreen.add(new ColorPredicate(ObjectColor.GREEN)); filterGreen.add(TargetController.YOU.getControllerPredicate()); - filterGreen2.add(new ColorPredicate(ObjectColor.GREEN)); + filterGreen2.add(new ColorPredicate(ObjectColor.GREEN)); filterGreen2.add(AnotherPredicate.instance); } - + public ParagonOfEternalWilds(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.DRUID); @@ -51,10 +49,11 @@ public final class ParagonOfEternalWilds extends CardImpl { // Other green creatures you control get +1/+1. this.addAbility(new SimpleStaticAbility(new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filterGreen, true))); + // {G}, {t}: Another target green creature you control gains trample until end of turn. - Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(TrampleAbility.getInstance(),Duration.EndOfTurn), new ManaCostsImpl<>("{G}")); + Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{G}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetControlledCreaturePermanent(filterGreen2)); + ability.addTarget(new TargetPermanent(filterGreen2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/ParagonOfFierceDefiance.java b/Mage.Sets/src/mage/cards/p/ParagonOfFierceDefiance.java index cae821f9fbc..51adc82758a 100644 --- a/Mage.Sets/src/mage/cards/p/ParagonOfFierceDefiance.java +++ b/Mage.Sets/src/mage/cards/p/ParagonOfFierceDefiance.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -15,32 +13,32 @@ import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author Quercitron */ public final class ParagonOfFierceDefiance extends CardImpl { private static final FilterCreaturePermanent filterCreatures = new FilterCreaturePermanent("red creatures"); private static final FilterControlledCreaturePermanent filterCreature = new FilterControlledCreaturePermanent("another target red creature you control"); - + static { filterCreatures.add(new ColorPredicate(ObjectColor.RED)); filterCreature.add(AnotherPredicate.instance); filterCreature.add(new ColorPredicate(ObjectColor.RED)); } - + public ParagonOfFierceDefiance(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WARRIOR); @@ -49,11 +47,11 @@ public final class ParagonOfFierceDefiance extends CardImpl { // Other red creatures you control get +1/+1. this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, filterCreatures, true))); - + // {R}, {T}: Another target red creature you control gains haste until end of turn. Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{R}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetControlledCreaturePermanent(filterCreature)); + ability.addTarget(new TargetPermanent(filterCreature)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/ParagonOfGatheringMists.java b/Mage.Sets/src/mage/cards/p/ParagonOfGatheringMists.java index 24f337a3faa..1a45a3ca9ac 100644 --- a/Mage.Sets/src/mage/cards/p/ParagonOfGatheringMists.java +++ b/Mage.Sets/src/mage/cards/p/ParagonOfGatheringMists.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -9,40 +7,39 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class ParagonOfGatheringMists extends CardImpl { - private static final FilterCreaturePermanent filterBlue = new FilterCreaturePermanent("blue creatures you control"); + private static final FilterPermanent filterBlue = new FilterCreaturePermanent("blue creatures"); private static final FilterControlledCreaturePermanent filterBlue2 = new FilterControlledCreaturePermanent("another target blue creature you control"); static { filterBlue.add(new ColorPredicate(ObjectColor.BLUE)); - filterBlue.add(TargetController.YOU.getControllerPredicate()); filterBlue2.add(new ColorPredicate(ObjectColor.BLUE)); filterBlue2.add(AnotherPredicate.instance); } public ParagonOfGatheringMists(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); @@ -50,12 +47,16 @@ public final class ParagonOfGatheringMists extends CardImpl { this.toughness = new MageInt(2); // Other blue creatures you control get +1/+1. - this.addAbility(new SimpleStaticAbility(new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filterBlue, true))); + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 1, 1, Duration.WhileOnBattlefield, filterBlue, true + ))); // {U}, {T}: Another target blue creature you control gains flying until end of turn. - Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(FlyingAbility.getInstance(),Duration.EndOfTurn), new ManaCostsImpl<>("{U}")); + Ability ability = new SimpleActivatedAbility( + new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{U}") + ); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetControlledCreaturePermanent(filterBlue2)); + ability.addTarget(new TargetPermanent(filterBlue2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/ParagonOfNewDawns.java b/Mage.Sets/src/mage/cards/p/ParagonOfNewDawns.java index 388b30f9e13..06fac2cd3a1 100644 --- a/Mage.Sets/src/mage/cards/p/ParagonOfNewDawns.java +++ b/Mage.Sets/src/mage/cards/p/ParagonOfNewDawns.java @@ -22,6 +22,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -54,7 +55,7 @@ public final class ParagonOfNewDawns extends CardImpl { // {W}, {T}: Another target white creature you control gains vigilance until end of turn. Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{W}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter2)); + ability.addTarget(new TargetPermanent(filter2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/ParagonOfOpenGraves.java b/Mage.Sets/src/mage/cards/p/ParagonOfOpenGraves.java index 6be69435b21..1be1d60379b 100644 --- a/Mage.Sets/src/mage/cards/p/ParagonOfOpenGraves.java +++ b/Mage.Sets/src/mage/cards/p/ParagonOfOpenGraves.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -15,22 +13,23 @@ import mage.abilities.keyword.DeathtouchAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class ParagonOfOpenGraves extends CardImpl { - private static final FilterCreaturePermanent filterCreatures = new FilterCreaturePermanent("black creatures"); + private static final FilterPermanent filterCreatures = new FilterCreaturePermanent("black creatures"); private static final FilterControlledCreaturePermanent filterCreature = new FilterControlledCreaturePermanent("another target black creature you control"); static { @@ -40,7 +39,7 @@ public final class ParagonOfOpenGraves extends CardImpl { } public ParagonOfOpenGraves(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.subtype.add(SubType.SKELETON); this.subtype.add(SubType.WARRIOR); @@ -48,12 +47,16 @@ public final class ParagonOfOpenGraves extends CardImpl { this.toughness = new MageInt(2); // Other black creatures you control get +1/+1. - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, filterCreatures, true))); + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 1, 1, Duration.WhileOnBattlefield, filterCreatures, true + ))); // {2}{B}, {T}: Another target black creature you control gains deathtouch until end of turn. - Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(DeathtouchAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{2}{B}")); + Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect( + DeathtouchAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl<>("{2}{B}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetControlledCreaturePermanent(filterCreature)); + ability.addTarget(new TargetPermanent(filterCreature)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/ParasiticStrix.java b/Mage.Sets/src/mage/cards/p/ParasiticStrix.java index 10bae477a59..80bad60a6d6 100644 --- a/Mage.Sets/src/mage/cards/p/ParasiticStrix.java +++ b/Mage.Sets/src/mage/cards/p/ParasiticStrix.java @@ -1,10 +1,11 @@ package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.YouControlPermanentCondition; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.keyword.FlyingAbility; @@ -12,21 +13,24 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.ColorPredicate; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.target.TargetPlayer; +import java.util.UUID; + /** * @author mluds */ public final class ParasiticStrix extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent("black permanent"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + } public ParasiticStrix(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{U}"); this.subtype.add(SubType.BIRD); this.power = new MageInt(2); @@ -34,9 +38,13 @@ public final class ParasiticStrix extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // When Parasitic Strix enters the battlefield, if you control a black permanent, target player loses 2 life and you gain 2 life. - this.addAbility(new ParasiticStrixTriggeredAbility()); + TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new LoseLifeTargetEffect(2)); + ability.addEffect(new GainLifeEffect(2).concatBy("and")); + ability.withInterveningIf(new YouControlPermanentCondition(filter)); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); } private ParasiticStrix(final ParasiticStrix card) { @@ -48,46 +56,3 @@ public final class ParasiticStrix extends CardImpl { return new ParasiticStrix(this); } } - -class ParasiticStrixTriggeredAbility extends TriggeredAbilityImpl { - - public ParasiticStrixTriggeredAbility() { - super(Zone.BATTLEFIELD, new LoseLifeTargetEffect(2)); - this.addEffect(new GainLifeEffect(2)); - this.addTarget(new TargetPlayer()); - } - - private ParasiticStrixTriggeredAbility(final ParasiticStrixTriggeredAbility ability) { - super(ability); - } - - @Override - public ParasiticStrixTriggeredAbility copy() { - return new ParasiticStrixTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - return event.getTargetId().equals(this.getSourceId()); - } - - @Override - public boolean checkInterveningIfClause(Game game) { - FilterPermanent filter = new FilterPermanent(); - filter.add(new ColorPredicate(ObjectColor.BLACK)); - if (game.getBattlefield().countAll(filter, this.controllerId, game) >= 1) { - return true; - } - return false; - } - - @Override - public String getRule() { - return "When Parasitic Strix enters the battlefield, if you control a black permanent, target player loses 2 life and you gain 2 life."; - } -} diff --git a/Mage.Sets/src/mage/cards/p/Parch.java b/Mage.Sets/src/mage/cards/p/Parch.java index ce4752cb4e9..5e71aa7ebcb 100644 --- a/Mage.Sets/src/mage/cards/p/Parch.java +++ b/Mage.Sets/src/mage/cards/p/Parch.java @@ -10,6 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetAnyTarget; import mage.target.common.TargetCreaturePermanent; @@ -33,7 +34,7 @@ public final class Parch extends CardImpl { this.getSpellAbility().addEffect(new DamageTargetEffect(2)); this.getSpellAbility().addTarget(new TargetAnyTarget()); Mode mode = new Mode(new DamageTargetEffect(4)); - mode.addTarget(new TargetCreaturePermanent(filter)); + mode.addTarget(new TargetPermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/p/PardicDragon.java b/Mage.Sets/src/mage/cards/p/PardicDragon.java index 111136610b6..c8ebc65bd9f 100644 --- a/Mage.Sets/src/mage/cards/p/PardicDragon.java +++ b/Mage.Sets/src/mage/cards/p/PardicDragon.java @@ -65,7 +65,7 @@ class PardicDragonEffect extends OneShotEffect { PardicDragonEffect() { super(Outcome.Benefit); - this.staticText = "that player may put a time counter on {this}"; + this.staticText = "that player may put a time counter on this card"; } private PardicDragonEffect(final PardicDragonEffect effect) { diff --git a/Mage.Sets/src/mage/cards/p/Paroxysm.java b/Mage.Sets/src/mage/cards/p/Paroxysm.java index 970b2ea0334..d646d2186b6 100644 --- a/Mage.Sets/src/mage/cards/p/Paroxysm.java +++ b/Mage.Sets/src/mage/cards/p/Paroxysm.java @@ -55,9 +55,8 @@ class ParoxysmEffect extends OneShotEffect { ParoxysmEffect() { super(Outcome.BoostCreature); - this.staticText = "that player reveals the top card of their library. \n" - + "If that card is a land card, destroy that creature. \n" - + "Otherwise, it gets +3/+3 until end of turn."; + this.staticText = "that player reveals the top card of their library. If that card is a land card, "+ + "destroy that creature. Otherwise, it gets +3/+3 until end of turn."; } private ParoxysmEffect(final ParoxysmEffect effect) { diff --git a/Mage.Sets/src/mage/cards/p/PathmakerInitiate.java b/Mage.Sets/src/mage/cards/p/PathmakerInitiate.java index 83df1f90516..717473702cb 100644 --- a/Mage.Sets/src/mage/cards/p/PathmakerInitiate.java +++ b/Mage.Sets/src/mage/cards/p/PathmakerInitiate.java @@ -16,6 +16,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class PathmakerInitiate extends CardImpl { // {T}: Target creature with power 2 or less can't be blocked this turn. Ability ability = new SimpleActivatedAbility(new CantBeBlockedTargetEffect(Duration.EndOfTurn), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/PatronOfTheVein.java b/Mage.Sets/src/mage/cards/p/PatronOfTheVein.java index 7460ec51914..6c7cf6cdf17 100644 --- a/Mage.Sets/src/mage/cards/p/PatronOfTheVein.java +++ b/Mage.Sets/src/mage/cards/p/PatronOfTheVein.java @@ -26,9 +26,12 @@ import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author spjspj @@ -48,7 +51,7 @@ public final class PatronOfTheVein extends CardImpl { // When Patron of the Vein enters the battlefield, destroy target creature an opponent controls. Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), false); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); // Whenever a creature an opponent controls dies, exile it and put a +1/+1 counter on each Vampire you control. diff --git a/Mage.Sets/src/mage/cards/p/PaupersCage.java b/Mage.Sets/src/mage/cards/p/PaupersCage.java index 6995e5364bd..2c976f03dca 100644 --- a/Mage.Sets/src/mage/cards/p/PaupersCage.java +++ b/Mage.Sets/src/mage/cards/p/PaupersCage.java @@ -1,33 +1,31 @@ - package mage.cards.p; -import java.util.UUID; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInHandCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.TargetController; +import java.util.UUID; + /** - * * @author fireshoes */ public final class PaupersCage extends CardImpl { + private static final Condition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 3, TargetController.ACTIVE); + public PaupersCage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, Paupers' Cage deals 2 damage to that player. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility( - TargetController.OPPONENT, new DamageTargetEffect(2), false); - CardsInHandCondition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 3, TargetController.ACTIVE); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, condition, - "At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, {this} deals 2 damage to that player.")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.OPPONENT, new DamageTargetEffect(2, true, "that player"), false + ).withInterveningIf(condition)); } private PaupersCage(final PaupersCage card) { diff --git a/Mage.Sets/src/mage/cards/p/PawpatchRecruit.java b/Mage.Sets/src/mage/cards/p/PawpatchRecruit.java index 68b1b9ac44e..b2ade10d334 100644 --- a/Mage.Sets/src/mage/cards/p/PawpatchRecruit.java +++ b/Mage.Sets/src/mage/cards/p/PawpatchRecruit.java @@ -1,18 +1,17 @@ package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.constants.*; import mage.abilities.keyword.OffspringAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; import mage.counters.CounterType; -import mage.filter.FilterPermanent; -import mage.filter.FilterStackObject; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledPermanent; @@ -23,7 +22,9 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.stack.StackObject; import mage.target.TargetPermanent; -import mage.util.CardUtil; +import mage.target.targetadjustment.DefineByTriggerTargetAdjuster; + +import java.util.UUID; /** * @@ -63,11 +64,9 @@ public final class PawpatchRecruit extends CardImpl { class PawpatchRecruitTriggeredAbility extends TriggeredAbilityImpl { - private final FilterPermanent filterTarget = StaticFilters.FILTER_CONTROLLED_A_CREATURE; - private final FilterStackObject filterStack = StaticFilters.FILTER_SPELL_OR_ABILITY_OPPONENTS; - public PawpatchRecruitTriggeredAbility() { super(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false); + this.setTargetAdjuster(DefineByTriggerTargetAdjuster.instance); } private PawpatchRecruitTriggeredAbility(final PawpatchRecruitTriggeredAbility ability) { @@ -93,11 +92,11 @@ class PawpatchRecruitTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId()); - if (permanent == null || !filterTarget.match(permanent, getControllerId(), this, game)) { + if (permanent == null || !StaticFilters.FILTER_CONTROLLED_A_CREATURE.match(permanent, getControllerId(), this, game)) { return false; } - StackObject targetingObject = CardUtil.findTargetingStackObject(this.getId().toString(), event, game); - if (targetingObject == null || !filterStack.match(targetingObject, getControllerId(), this, game)) { + StackObject targetingObject = game.findTargetingStackObject(this.getId().toString(), event); + if (targetingObject == null || !StaticFilters.FILTER_SPELL_OR_ABILITY_OPPONENTS.match(targetingObject, getControllerId(), this, game)) { return false; } this.getTargets().clear(); diff --git a/Mage.Sets/src/mage/cards/p/PearlspearCourier.java b/Mage.Sets/src/mage/cards/p/PearlspearCourier.java index 5936dee1d0f..b8a75b41b3e 100644 --- a/Mage.Sets/src/mage/cards/p/PearlspearCourier.java +++ b/Mage.Sets/src/mage/cards/p/PearlspearCourier.java @@ -20,6 +20,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -50,7 +51,7 @@ public final class PearlspearCourier extends CardImpl { ability.addEffect(new ConditionalContinuousEffect(new GainAbilityTargetEffect(VigilanceAbility.getInstance(), Duration.Custom), SourceTappedCondition.TAPPED,"and has vigilance for as long as {this} remains tapped")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/PeelFromReality.java b/Mage.Sets/src/mage/cards/p/PeelFromReality.java index 7d66b23ba79..075dab4e7f6 100644 --- a/Mage.Sets/src/mage/cards/p/PeelFromReality.java +++ b/Mage.Sets/src/mage/cards/p/PeelFromReality.java @@ -5,12 +5,15 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.EachTargetPointer; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author North */ @@ -22,7 +25,7 @@ public final class PeelFromReality extends CardImpl { // Return target creature you control and target creature you don't control to their owners' hands. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect().setTargetPointer(new EachTargetPointer())); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); } private PeelFromReality(final PeelFromReality card) { diff --git a/Mage.Sets/src/mage/cards/p/Pendelhaven.java b/Mage.Sets/src/mage/cards/p/Pendelhaven.java index cd9b63cdcbe..0975b511791 100644 --- a/Mage.Sets/src/mage/cards/p/Pendelhaven.java +++ b/Mage.Sets/src/mage/cards/p/Pendelhaven.java @@ -17,6 +17,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.filter.predicate.mageobject.ToughnessPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class Pendelhaven extends CardImpl { this.addAbility(new GreenManaAbility()); // {tap}: Target 1/1 creature gets +1/+2 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(1, 2, Duration.EndOfTurn), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/Pestilence.java b/Mage.Sets/src/mage/cards/p/Pestilence.java index 4ebedff43af..90adfe9ea6a 100644 --- a/Mage.Sets/src/mage/cards/p/Pestilence.java +++ b/Mage.Sets/src/mage/cards/p/Pestilence.java @@ -1,36 +1,37 @@ - package mage.cards.p; -import java.util.UUID; -import mage.abilities.TriggeredAbility; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.condition.common.CreatureCountCondition; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageEverythingEffect; import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.TargetController; -import mage.constants.Zone; -import mage.game.events.GameEvent; +import mage.filter.common.FilterCreaturePermanent; + +import java.util.UUID; /** - * * @author Backfir3 */ public final class Pestilence extends CardImpl { - private static final String ruleText = "At the beginning of the end step, if no creatures are on the battlefield, sacrifice {this}."; + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterCreaturePermanent("no creatures are on the battlefield"), ComparisonType.EQUAL_TO, 0 + ); public Pestilence(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); // 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 ConditionalInterveningIfTriggeredAbility(triggered, new CreatureCountCondition(0, TargetController.ANY), ruleText)); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.NEXT, new SacrificeSourceEffect(), false, condition + )); // {B}: Pestilence deals 1 damage to each creature and each player. this.addAbility(new SimpleActivatedAbility(new DamageEverythingEffect(1), new ManaCostsImpl<>("{B}"))); diff --git a/Mage.Sets/src/mage/cards/p/PestilentCauldron.java b/Mage.Sets/src/mage/cards/p/PestilentCauldron.java index f5b6b65462b..1df624ed426 100644 --- a/Mage.Sets/src/mage/cards/p/PestilentCauldron.java +++ b/Mage.Sets/src/mage/cards/p/PestilentCauldron.java @@ -6,20 +6,16 @@ import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.dynamicvalue.common.ControllerGainedLifeCount; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.*; import mage.cards.CardSetInfo; import mage.cards.ModalDoubleFacedCard; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.TargetController; import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.predicate.Predicates; -import mage.game.Game; import mage.game.permanent.token.Pest11GainLifeToken; -import mage.players.Player; import mage.target.common.TargetCardInASingleGraveyard; import mage.target.common.TargetCardInYourGraveyard; import mage.watchers.common.PlayerGainedLifeWatcher; @@ -82,7 +78,7 @@ public final class PestilentCauldron extends ModalDoubleFacedCard { // Sorcery // Return up to two target creature, land, and/or planeswalker cards from your graveyard to your hand. Each player gains 4 life. Exile Restorative Burst. this.getRightHalfCard().getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); - this.getRightHalfCard().getSpellAbility().addEffect(new RestorativeBurstEffect()); + this.getRightHalfCard().getSpellAbility().addEffect(new GainLifeAllEffect(4)); this.getRightHalfCard().getSpellAbility().addEffect(new ExileSpellEffect()); this.getRightHalfCard().getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 2, filter)); } @@ -96,31 +92,3 @@ public final class PestilentCauldron extends ModalDoubleFacedCard { return new PestilentCauldron(this); } } - -class RestorativeBurstEffect extends OneShotEffect { - - RestorativeBurstEffect() { - super(Outcome.GainLife); - staticText = "Each player gains 4 life."; - } - - private RestorativeBurstEffect(final RestorativeBurstEffect effect) { - super(effect); - } - - @Override - public RestorativeBurstEffect copy() { - return new RestorativeBurstEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - player.gainLife(4, game, source); - } - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/p/PestsOfHonor.java b/Mage.Sets/src/mage/cards/p/PestsOfHonor.java index 9bc6f9bf106..f92da8d3c0c 100644 --- a/Mage.Sets/src/mage/cards/p/PestsOfHonor.java +++ b/Mage.Sets/src/mage/cards/p/PestsOfHonor.java @@ -1,10 +1,9 @@ package mage.cards.p; import mage.MageInt; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.common.CelebrationCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; @@ -28,12 +27,11 @@ public final class PestsOfHonor extends CardImpl { this.toughness = new MageInt(2); // Celebration - At the beginning of combat on your turn, if two or more nonland permanents entered the battlefield under your control this turn, put a +1/+1 counter on Pests of Honor. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance()) - ), CelebrationCondition.instance, "At the beginning of combat on your turn, if two or more " + - "nonland permanents entered the battlefield under your control this turn, put a +1/+1 counter on {this}." - ).addHint(CelebrationCondition.getHint()).setAbilityWord(AbilityWord.CELEBRATION), new PermanentsEnteredBattlefieldWatcher()); + this.addAbility(new BeginningOfCombatTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())) + .withInterveningIf(CelebrationCondition.instance) + .addHint(CelebrationCondition.getHint()) + .setAbilityWord(AbilityWord.CELEBRATION), new PermanentsEnteredBattlefieldWatcher() + ); } private PestsOfHonor(final PestsOfHonor card) { diff --git a/Mage.Sets/src/mage/cards/p/PhageTheUntouchable.java b/Mage.Sets/src/mage/cards/p/PhageTheUntouchable.java index 25d3b5b1889..fe6bc438e97 100644 --- a/Mage.Sets/src/mage/cards/p/PhageTheUntouchable.java +++ b/Mage.Sets/src/mage/cards/p/PhageTheUntouchable.java @@ -1,14 +1,13 @@ package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.DealsCombatDamageToACreatureTriggeredAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.CastFromHandSourcePermanentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.LoseGameSourceControllerEffect; import mage.abilities.effects.common.LoseGameTargetPlayerEffect; @@ -19,14 +18,17 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.watchers.common.CastFromHandWatcher; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class PhageTheUntouchable extends CardImpl { + private static final Condition condition = new InvertCondition(CastFromHandSourcePermanentCondition.instance, "you didn't cast it from your hand"); + public PhageTheUntouchable(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}{B}{B}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.AVATAR); this.subtype.add(SubType.MINION); @@ -35,11 +37,8 @@ public final class PhageTheUntouchable extends CardImpl { this.toughness = new MageInt(4); // When Phage the Untouchable enters the battlefield, if you didn't cast it from your hand, you lose the game. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new LoseGameSourceControllerEffect(), false), - new InvertCondition(CastFromHandSourcePermanentCondition.instance), - "When {this} enters, if you didn't cast it from your hand, you lose the game" - ), new CastFromHandWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility(new LoseGameSourceControllerEffect()) + .withInterveningIf(condition), new CastFromHandWatcher()); // Whenever Phage deals combat damage to a creature, destroy that creature. It can't be regenerated. this.addAbility(new DealsCombatDamageToACreatureTriggeredAbility(new DestroyTargetEffect(true), false, true)); diff --git a/Mage.Sets/src/mage/cards/p/PhantasmalMount.java b/Mage.Sets/src/mage/cards/p/PhantasmalMount.java index 886bc73d5f7..b09f34d1df7 100644 --- a/Mage.Sets/src/mage/cards/p/PhantasmalMount.java +++ b/Mage.Sets/src/mage/cards/p/PhantasmalMount.java @@ -1,6 +1,5 @@ package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; @@ -12,25 +11,21 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.SacrificeTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.constants.SubType; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.ToughnessPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class PhantasmalMount extends CardImpl { @@ -54,9 +49,8 @@ public final class PhantasmalMount extends CardImpl { // {tap}: Target creature you control with toughness 2 or less gets +1/+1 and gains flying until end of turn. When Phantasmal Mount leaves the battlefield this turn, sacrifice that creature. When the creature leaves the battlefield this turn, sacrifice Phantasmal Mount. Ability activatedAbility = new SimpleActivatedAbility(new PhantasmalMountEffect(), new TapSourceCost()); - activatedAbility.addTarget(new TargetControlledCreaturePermanent(filter)); + activatedAbility.addTarget(new TargetPermanent(filter)); this.addAbility(activatedAbility); - } private PhantasmalMount(final PhantasmalMount card) { diff --git a/Mage.Sets/src/mage/cards/p/PhantomBlade.java b/Mage.Sets/src/mage/cards/p/PhantomBlade.java index 55f91727caa..1f79ccec1b5 100644 --- a/Mage.Sets/src/mage/cards/p/PhantomBlade.java +++ b/Mage.Sets/src/mage/cards/p/PhantomBlade.java @@ -16,8 +16,8 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.SecondTargetPointer; import java.util.UUID; @@ -37,7 +37,7 @@ public final class PhantomBlade extends CardImpl { ability.addTarget(new TargetControlledCreaturePermanent(0, 1).setTargetTag(1)); ability.addEffect(new DestroyTargetEffect().setTargetPointer(new SecondTargetPointer())); - ability.addTarget(new TargetCreaturePermanent(0, 1, StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2, false).setTargetTag(2)); + ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2).setTargetTag(2)); this.addAbility(ability); // Equipped creature gets +1/+1 and has menace. diff --git a/Mage.Sets/src/mage/cards/p/PharagaxGiant.java b/Mage.Sets/src/mage/cards/p/PharagaxGiant.java index 44f29cb312f..e92555a4cf1 100644 --- a/Mage.Sets/src/mage/cards/p/PharagaxGiant.java +++ b/Mage.Sets/src/mage/cards/p/PharagaxGiant.java @@ -1,12 +1,8 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.TributeNotPaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.keyword.TributeAbility; import mage.cards.CardImpl; @@ -15,14 +11,15 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class PharagaxGiant extends CardImpl { public PharagaxGiant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); this.subtype.add(SubType.GIANT); this.power = new MageInt(3); @@ -30,10 +27,11 @@ public final class PharagaxGiant extends CardImpl { // Tribute 2 (As this creature enters the battlefield, an opponent of your choice may place two +1/+1 counters on it.) this.addAbility(new TributeAbility(2)); + // When Pharagax Giant enters the battlefield, if tribute wasn't paid, Pharagax Giant deals 5 damage to each opponent. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DamagePlayersEffect(5, TargetController.OPPONENT), false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, TributeNotPaidCondition.instance, - "When {this} enters, if tribute wasn't paid, {this} deals 5 damage to each opponent.")); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new DamagePlayersEffect(5, TargetController.OPPONENT) + ).withInterveningIf(TributeNotPaidCondition.instance)); } private PharagaxGiant(final PharagaxGiant card) { diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianBloodstock.java b/Mage.Sets/src/mage/cards/p/PhyrexianBloodstock.java index 5b9fe000e32..60bcea585e6 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianBloodstock.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianBloodstock.java @@ -13,6 +13,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -36,7 +37,7 @@ public final class PhyrexianBloodstock extends CardImpl { // When Phyrexian Bloodstock leaves the battlefield, destroy target white creature. It can't be regenerated. Ability ability = new LeavesBattlefieldTriggeredAbility(new DestroyTargetEffect(true), false); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianDreadnought.java b/Mage.Sets/src/mage/cards/p/PhyrexianDreadnought.java index e82404b0646..e08c351495b 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianDreadnought.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianDreadnought.java @@ -1,7 +1,6 @@ package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -12,16 +11,17 @@ import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class PhyrexianDreadnought extends CardImpl { @@ -36,6 +36,7 @@ public final class PhyrexianDreadnought extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); + // When Phyrexian Dreadnought enters the battlefield, sacrifice it unless you sacrifice any number of creatures with total power 12 or greater. this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new PhyrexianDreadnoughtSacrificeCost()))); @@ -56,7 +57,7 @@ class PhyrexianDreadnoughtSacrificeCost extends CostImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("any number of creatures with total power 12 or greater"); public PhyrexianDreadnoughtSacrificeCost() { - this.addTarget(new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true)); + this.addTarget(new TargetPermanent(0, Integer.MAX_VALUE, filter, true)); this.text = "sacrifice any number of creatures with total power 12 or greater"; } diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianMissionary.java b/Mage.Sets/src/mage/cards/p/PhyrexianMissionary.java index 158258ae21b..2a44de0a472 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianMissionary.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianMissionary.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.KickerAbility; import mage.abilities.keyword.LifelinkAbility; @@ -38,11 +37,7 @@ public final class PhyrexianMissionary extends CardImpl { this.addAbility(LifelinkAbility.getInstance()); // When Phyrexian Missionary enters the battlefield, if it was kicked, return target creature card from your graveyard to your hand. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()), - KickedCondition.ONCE, "When {this} enters, if it was kicked, " + - "return target creature card from your graveyard to your hand." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()).withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianScuta.java b/Mage.Sets/src/mage/cards/p/PhyrexianScuta.java index e1e3e824edb..5b12ac6300c 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianScuta.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianScuta.java @@ -1,7 +1,6 @@ package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.common.KickedCondition; @@ -14,6 +13,8 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; +import java.util.UUID; + /** * * @author LoneFox @@ -31,7 +32,7 @@ public final class PhyrexianScuta extends CardImpl { // Kicker-Pay 3 life. this.addAbility(new KickerAbility(new PayLifeCost(3))); // If Phyrexian Scuta was kicked, it enters with two +1/+1 counters on it. - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), KickedCondition.ONCE, "If Phyrexian Scuta was kicked, it enters with two +1/+1 counters on it.", "")); + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), KickedCondition.ONCE, "If {this} was kicked, it enters with two +1/+1 counters on it.", "")); } private PhyrexianScuta(final PhyrexianScuta card) { diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianSwarmlord.java b/Mage.Sets/src/mage/cards/p/PhyrexianSwarmlord.java index 81cf6a32190..93c72f8c086 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianSwarmlord.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianSwarmlord.java @@ -1,27 +1,25 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.dynamicvalue.common.OpponentsPoisonCountersCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.InfectAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.token.InsectInfectToken; +import java.util.UUID; + /** - * * @author North */ public final class PhyrexianSwarmlord extends CardImpl { public PhyrexianSwarmlord(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.INSECT); this.subtype.add(SubType.HORROR); @@ -30,8 +28,9 @@ public final class PhyrexianSwarmlord extends CardImpl { this.toughness = new MageInt(4); this.addAbility(InfectAbility.getInstance()); - this.addAbility(new OnEventTriggeredAbility(EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", - new CreateTokenEffect(new InsectInfectToken(), OpponentsPoisonCountersCount.instance))); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new CreateTokenEffect(new InsectInfectToken(), OpponentsPoisonCountersCount.instance) + )); } private PhyrexianSwarmlord(final PhyrexianSwarmlord card) { @@ -43,4 +42,3 @@ public final class PhyrexianSwarmlord extends CardImpl { return new PhyrexianSwarmlord(this); } } - diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianTotem.java b/Mage.Sets/src/mage/cards/p/PhyrexianTotem.java index f03f6d65846..381635784cb 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianTotem.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianTotem.java @@ -41,7 +41,7 @@ public final class PhyrexianTotem extends CardImpl { // Whenever {this} is dealt damage, if it's a creature, sacrifice that many permanents. this.addAbility(new DealtDamageToSourceTriggeredAbility( new SacrificeControllerEffect(StaticFilters.FILTER_PERMANENTS, SavedDamageValue.MANY, ""), false - ).withInterveningIf(PhyrexianTotemCondition.instance)); + ).withInterveningIf(PhyrexianTotemCondition.instance).setTriggerPhrase("Whenever this permanent is dealt damage, ")); } private PhyrexianTotem(final PhyrexianTotem card) { diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianWarhorse.java b/Mage.Sets/src/mage/cards/p/PhyrexianWarhorse.java index 9f9ef0e0be4..d393a074bd8 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianWarhorse.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianWarhorse.java @@ -1,6 +1,5 @@ package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -8,20 +7,20 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.KickedCondition; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.constants.Duration; -import mage.constants.SubType; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; import mage.game.permanent.token.SoldierToken; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class PhyrexianWarhorse extends CardImpl { @@ -38,16 +37,12 @@ public final class PhyrexianWarhorse extends CardImpl { this.addAbility(new KickerAbility("{W}")); // When Phyrexian Warhorse enters the battlefield, if it was kicked, create a 1/1 white Soldier creature token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new SoldierToken())), - KickedCondition.ONCE, - "When {this} enters, if it was kicked, create a 1/1 white Soldier creature token." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new SoldierToken())) + .withInterveningIf(KickedCondition.ONCE)); // {1}, Sacrifice another creature: Phyrexian Warhorse gets +2/+1 until end of turn. Ability ability = new SimpleActivatedAbility( - new BoostSourceEffect(2, 1, Duration.EndOfTurn), - new GenericManaCost(1) + new BoostSourceEffect(2, 1, Duration.EndOfTurn), new GenericManaCost(1) ); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/p/PiaNalaar.java b/Mage.Sets/src/mage/cards/p/PiaNalaar.java index 80fcf8fee88..89fc86b0178 100644 --- a/Mage.Sets/src/mage/cards/p/PiaNalaar.java +++ b/Mage.Sets/src/mage/cards/p/PiaNalaar.java @@ -22,9 +22,12 @@ import mage.constants.Zone; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledArtifactPermanent; import mage.game.permanent.token.ThopterColorlessToken; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE; + /** * * @author LevelX2 @@ -44,7 +47,7 @@ public final class PiaNalaar extends CardImpl { // {1}{R}: Target artifact creature gets +1/+0 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl<>("{1}{R}")); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_PERMANENT_ARTIFACT_CREATURE)); this.addAbility(ability); // {1}, Sacrifice an artifact: Target creature can't block this turn. diff --git a/Mage.Sets/src/mage/cards/p/PierceTheSky.java b/Mage.Sets/src/mage/cards/p/PierceTheSky.java index acb6c5ab383..d2d3a4d0273 100644 --- a/Mage.Sets/src/mage/cards/p/PierceTheSky.java +++ b/Mage.Sets/src/mage/cards/p/PierceTheSky.java @@ -9,6 +9,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -28,7 +29,7 @@ public final class PierceTheSky extends CardImpl { // Pierce the Sky deals 7 damage to target creature with flying. this.getSpellAbility().addEffect(new DamageTargetEffect(7)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private PierceTheSky(final PierceTheSky card) { diff --git a/Mage.Sets/src/mage/cards/p/PietyCharm.java b/Mage.Sets/src/mage/cards/p/PietyCharm.java index 83478fd8b6a..9c7b36ebc2c 100644 --- a/Mage.Sets/src/mage/cards/p/PietyCharm.java +++ b/Mage.Sets/src/mage/cards/p/PietyCharm.java @@ -42,7 +42,7 @@ public final class PietyCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent(filter1)); // or target Soldier creature gets +2/+2 until end of turn Mode mode = new Mode(new BoostTargetEffect(2, 2, Duration.EndOfTurn)); - mode.addTarget(new TargetCreaturePermanent(filter2)); + mode.addTarget(new TargetPermanent(filter2)); this.getSpellAbility().addMode(mode); // or creatures you control gain vigilance until end of turn. mode = new Mode(new GainAbilityAllEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES)); diff --git a/Mage.Sets/src/mage/cards/p/PillarOfLight.java b/Mage.Sets/src/mage/cards/p/PillarOfLight.java index 343a9f80bb8..93cc7682274 100644 --- a/Mage.Sets/src/mage/cards/p/PillarOfLight.java +++ b/Mage.Sets/src/mage/cards/p/PillarOfLight.java @@ -9,6 +9,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ToughnessPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class PillarOfLight extends CardImpl { // Exile target creature with toughness 4 or greater. this.getSpellAbility().addEffect(new ExileTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private PillarOfLight(final PillarOfLight card) { diff --git a/Mage.Sets/src/mage/cards/p/PinionFeast.java b/Mage.Sets/src/mage/cards/p/PinionFeast.java index 599e8d5104c..42080cdd626 100644 --- a/Mage.Sets/src/mage/cards/p/PinionFeast.java +++ b/Mage.Sets/src/mage/cards/p/PinionFeast.java @@ -10,6 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class PinionFeast extends CardImpl { // Destroy target creature with flying. Bolster 2. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new BolsterEffect(2)); } diff --git a/Mage.Sets/src/mage/cards/p/PiousKitsune.java b/Mage.Sets/src/mage/cards/p/PiousKitsune.java index a7b3bab6af2..9f3bf795872 100644 --- a/Mage.Sets/src/mage/cards/p/PiousKitsune.java +++ b/Mage.Sets/src/mage/cards/p/PiousKitsune.java @@ -1,22 +1,20 @@ package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.RemoveCountersSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.NamePredicate; @@ -24,6 +22,8 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** * * @author LevelX2 @@ -66,7 +66,7 @@ class PiousKitsuneEffect extends OneShotEffect { public PiousKitsuneEffect() { super(Outcome.Benefit); - this.staticText = "put a devotion counter on Pious Kitsune. Then if a creature named Eight-and-a-Half-Tails is on the battlefield, you gain 1 life for each devotion counter on Pious Kitsune"; + this.staticText = "put a devotion counter on {this}. Then if a creature named Eight-and-a-Half-Tails is on the battlefield, you gain 1 life for each devotion counter on {this}"; } private PiousKitsuneEffect(final PiousKitsuneEffect effect) { diff --git a/Mage.Sets/src/mage/cards/p/PistusStrike.java b/Mage.Sets/src/mage/cards/p/PistusStrike.java index 9e931a42e69..e446b0b2fc8 100644 --- a/Mage.Sets/src/mage/cards/p/PistusStrike.java +++ b/Mage.Sets/src/mage/cards/p/PistusStrike.java @@ -16,6 +16,7 @@ import mage.filter.predicate.mageobject.AbilityPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -33,7 +34,7 @@ public final class PistusStrike extends CardImpl { public PistusStrike(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{G}"); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addEffect(new PoisonControllerTargetCreatureEffect()); } diff --git a/Mage.Sets/src/mage/cards/p/PitFight.java b/Mage.Sets/src/mage/cards/p/PitFight.java index a34dbd719f5..09dda5563fd 100644 --- a/Mage.Sets/src/mage/cards/p/PitFight.java +++ b/Mage.Sets/src/mage/cards/p/PitFight.java @@ -4,12 +4,13 @@ import mage.abilities.effects.common.FightTargetsEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2; + /** * @author LevelX2 */ @@ -20,13 +21,8 @@ public final class PitFight extends CardImpl { // Target creature you control fights another target creature. this.getSpellAbility().addEffect(new FightTargetsEffect()); - TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(); - target.setTargetTag(1); - this.getSpellAbility().addTarget(target); - - TargetCreaturePermanent target2 = new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2); - target2.setTargetTag(2); - this.getSpellAbility().addTarget(target2); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent().setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_ANOTHER_CREATURE_TARGET_2).setTargetTag(2)); } private PitFight(final PitFight card) { diff --git a/Mage.Sets/src/mage/cards/p/PitKeeper.java b/Mage.Sets/src/mage/cards/p/PitKeeper.java index 8d31e68c894..d261db5bc13 100644 --- a/Mage.Sets/src/mage/cards/p/PitKeeper.java +++ b/Mage.Sets/src/mage/cards/p/PitKeeper.java @@ -1,28 +1,27 @@ package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.CardsInControllerGraveyardCondition; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author fireshoes */ public final class PitKeeper extends CardImpl { + private static final Condition condition = new CardsInControllerGraveyardCondition(4, StaticFilters.FILTER_CARD_CREATURES); + public PitKeeper(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); this.subtype.add(SubType.HUMAN); @@ -31,12 +30,9 @@ public final class PitKeeper extends CardImpl { this.toughness = new MageInt(1); // When Pit Keeper enters the battlefield, if you have four or more creature cards in your graveyard, you may return target creature card from your graveyard to your hand. - TriggeredAbility triggeredAbility = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); - triggeredAbility.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - triggeredAbility, - new CreatureCardsInControllerGraveyardCondition(4), - "When {this} enters, if you have four or more creature cards in your graveyard, you may return target creature card from your graveyard to your hand.")); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true).withInterveningIf(condition); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.addAbility(ability); } private PitKeeper(final PitKeeper card) { @@ -48,21 +44,3 @@ public final class PitKeeper extends CardImpl { return new PitKeeper(this); } } - -class CreatureCardsInControllerGraveyardCondition implements Condition { - - private int value; - - public CreatureCardsInControllerGraveyardCondition(int value) { - this.value = value; - } - - @Override - public boolean apply(Game game, Ability source) { - Player p = game.getPlayer(source.getControllerId()); - if (p != null && p.getGraveyard().count(StaticFilters.FILTER_CARD_CREATURE, game) >= value) { - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/p/PlagueSpores.java b/Mage.Sets/src/mage/cards/p/PlagueSpores.java index 9e3162505ca..5b08bce7de3 100644 --- a/Mage.Sets/src/mage/cards/p/PlagueSpores.java +++ b/Mage.Sets/src/mage/cards/p/PlagueSpores.java @@ -6,10 +6,13 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetLandPermanent; import mage.target.targetpointer.EachTargetPointer; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author LoneFox @@ -22,7 +25,7 @@ public final class PlagueSpores extends CardImpl { // Destroy target nonblack creature and target land. They can't be regenerated. this.getSpellAbility().addEffect(new DestroyTargetEffect(true).setTargetPointer(new EachTargetPointer())); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.getSpellAbility().addTarget(new TargetLandPermanent()); } diff --git a/Mage.Sets/src/mage/cards/p/PlanarCollapse.java b/Mage.Sets/src/mage/cards/p/PlanarCollapse.java index 96bfb43e1fc..4228f56e032 100644 --- a/Mage.Sets/src/mage/cards/p/PlanarCollapse.java +++ b/Mage.Sets/src/mage/cards/p/PlanarCollapse.java @@ -1,34 +1,37 @@ - package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.filter.StaticFilters; -import mage.game.Game; +import mage.filter.common.FilterCreaturePermanent; + +import java.util.UUID; /** - * * @author Plopman */ public final class PlanarCollapse extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterCreaturePermanent("there are four or more creatures on the battlefield"), + ComparisonType.MORE_THAN, 3, false + ); + public PlanarCollapse(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); // At the beginning of your upkeep, if there are four or more creatures on the battlefield, sacrifice Planar Collapse and destroy all creatures. They can't be regenerated. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceEffect()); - ability.addEffect(new DestroyAllEffect(StaticFilters.FILTER_PERMANENT_CREATURE, true)); - PlanarCollapseCondition contition = new PlanarCollapseCondition(); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, contition, "At the beginning of your upkeep, if there are four or more creatures on the battlefield, sacrifice {this} and destroy all creatures. They can't be regenerated")); - + Ability ability = new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceEffect()).withInterveningIf(condition); + ability.addEffect(new DestroyAllEffect(StaticFilters.FILTER_PERMANENT_CREATURES, true).concatBy("and")); + this.addAbility(ability); } private PlanarCollapse(final PlanarCollapse card) { @@ -39,12 +42,4 @@ public final class PlanarCollapse extends CardImpl { public PlanarCollapse copy() { return new PlanarCollapse(this); } - - static class PlanarCollapseCondition implements mage.abilities.condition.Condition { - - @Override - public boolean apply(Game game, Ability source) { - return game.getBattlefield().count(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game) >= 4; - } - } } diff --git a/Mage.Sets/src/mage/cards/p/PlaneswalkersFury.java b/Mage.Sets/src/mage/cards/p/PlaneswalkersFury.java index dca3c1b02c5..d10ae4380ec 100644 --- a/Mage.Sets/src/mage/cards/p/PlaneswalkersFury.java +++ b/Mage.Sets/src/mage/cards/p/PlaneswalkersFury.java @@ -42,7 +42,7 @@ class PlaneswalkersFuryEffect extends OneShotEffect { PlaneswalkersFuryEffect() { super(Outcome.Damage); - staticText = "Target opponent reveals a card at random from their hand. Planeswalker's Fury deals damage equal to that card's mana value to that player"; + staticText = "Target opponent reveals a card at random from their hand. {this} deals damage equal to that card's mana value to that player"; } private PlaneswalkersFuryEffect(final PlaneswalkersFuryEffect effect) { diff --git a/Mage.Sets/src/mage/cards/p/PlarggDeanOfChaos.java b/Mage.Sets/src/mage/cards/p/PlarggDeanOfChaos.java index 7d417ad9d62..2bd180fbff7 100644 --- a/Mage.Sets/src/mage/cards/p/PlarggDeanOfChaos.java +++ b/Mage.Sets/src/mage/cards/p/PlarggDeanOfChaos.java @@ -22,11 +22,12 @@ import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Controllable; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; +import java.util.Optional; import java.util.UUID; /** @@ -167,13 +168,16 @@ class AugustaDeanOfOrderEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true); - Player controller = game.getPlayer(source.getControllerId()); - controller.chooseTarget(Outcome.Benefit, target, source, game); - target.getTargets().forEach(t -> { - Permanent permanent = game.getPermanent(t); - permanent.tap(source, game); - }); + TargetPermanent target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); + Optional.ofNullable(source) + .map(Controllable::getControllerId) + .map(game::getPlayer) + .ifPresent(player -> player.chooseTarget(Outcome.Benefit, target, source, game)); + for (UUID targetId : target.getTargets()) { + Optional.ofNullable(targetId) + .map(game::getPermanent) + .ifPresent(permanent -> permanent.tap(source, game)); + } return true; } diff --git a/Mage.Sets/src/mage/cards/p/PlasmaCaster.java b/Mage.Sets/src/mage/cards/p/PlasmaCaster.java index 994081709d2..897be0f883e 100644 --- a/Mage.Sets/src/mage/cards/p/PlasmaCaster.java +++ b/Mage.Sets/src/mage/cards/p/PlasmaCaster.java @@ -22,6 +22,7 @@ import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.watchers.common.BlockingOrBlockedWatcher; @@ -60,7 +61,7 @@ public final class PlasmaCaster extends CardImpl { + "Otherwise, {this} deals 1 damage to it"), new PayEnergyCost(2) ); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Equip {2} diff --git a/Mage.Sets/src/mage/cards/p/PlaxcasterFrogling.java b/Mage.Sets/src/mage/cards/p/PlaxcasterFrogling.java index a217ad0388f..6d224464a0d 100644 --- a/Mage.Sets/src/mage/cards/p/PlaxcasterFrogling.java +++ b/Mage.Sets/src/mage/cards/p/PlaxcasterFrogling.java @@ -16,8 +16,11 @@ import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_CREATURE_P1P1; + /** * * @author JotaPeRL @@ -36,7 +39,7 @@ public final class PlaxcasterFrogling extends CardImpl { // {2}: Target creature with a +1/+1 counter on it gains shroud until end of turn. Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(ShroudAbility.getInstance(), Duration.EndOfTurn), new GenericManaCost(2)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_P1P1)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_P1P1)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/PlazaOfHarmony.java b/Mage.Sets/src/mage/cards/p/PlazaOfHarmony.java index 71d652b53b7..2bc0057e502 100644 --- a/Mage.Sets/src/mage/cards/p/PlazaOfHarmony.java +++ b/Mage.Sets/src/mage/cards/p/PlazaOfHarmony.java @@ -1,21 +1,17 @@ package mage.cards.p; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.YouControlTwoOrMoreGatesCondition; import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.common.GatesYouControlHint; import mage.abilities.mana.AnyColorLandsProduceManaAbility; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ComparisonType; import mage.constants.SubType; import mage.constants.TargetController; import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledPermanent; import java.util.UUID; @@ -24,25 +20,14 @@ import java.util.UUID; */ public final class PlazaOfHarmony extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent(); private static final FilterPermanent filter2 = new FilterPermanent(SubType.GATE, "Gate"); - static { - filter.add(SubType.GATE.getPredicate()); - } - - private static final Condition condition - = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); - public PlazaOfHarmony(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // When Plaza of Harmony enters the battlefield, if you control two or more Gates, you gain 3 life. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3)), - condition, "When {this} enters, " + - "if you control two or more Gates, you gain 3 life." - ).addHint(new ConditionHint(condition, "You control two or more Gates"))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3)) + .withInterveningIf(YouControlTwoOrMoreGatesCondition.instance).addHint(GatesYouControlHint.instance)); // {T}: Add {C}. this.addAbility(new ColorlessManaAbility()); diff --git a/Mage.Sets/src/mage/cards/p/Plummet.java b/Mage.Sets/src/mage/cards/p/Plummet.java index fb539c22cb2..559acade3ba 100644 --- a/Mage.Sets/src/mage/cards/p/Plummet.java +++ b/Mage.Sets/src/mage/cards/p/Plummet.java @@ -11,6 +11,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -28,7 +29,7 @@ public final class Plummet extends CardImpl { public Plummet(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{G}"); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/p/PoisonArrow.java b/Mage.Sets/src/mage/cards/p/PoisonArrow.java index ce1bad3cf7f..fb2d330b92d 100644 --- a/Mage.Sets/src/mage/cards/p/PoisonArrow.java +++ b/Mage.Sets/src/mage/cards/p/PoisonArrow.java @@ -7,8 +7,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author LoneFox @@ -21,7 +24,7 @@ public final class PoisonArrow extends CardImpl { // Destroy target nonblack creature. You gain 3 life. this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addEffect(new GainLifeEffect(3)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); } private PoisonArrow(final PoisonArrow card) { diff --git a/Mage.Sets/src/mage/cards/p/PolisCrusher.java b/Mage.Sets/src/mage/cards/p/PolisCrusher.java index 1b615461828..83422c7208a 100644 --- a/Mage.Sets/src/mage/cards/p/PolisCrusher.java +++ b/Mage.Sets/src/mage/cards/p/PolisCrusher.java @@ -1,10 +1,9 @@ package mage.cards.p; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.condition.common.MonstrousCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.MonstrosityAbility; import mage.abilities.keyword.ProtectionAbility; @@ -14,6 +13,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.FilterCard; +import mage.filter.FilterPermanent; import mage.filter.common.FilterEnchantmentCard; import mage.filter.common.FilterEnchantmentPermanent; import mage.target.TargetPermanent; @@ -27,11 +27,7 @@ import java.util.UUID; public final class PolisCrusher extends CardImpl { private static final FilterCard filterCard = new FilterEnchantmentCard("enchantments"); - private static final FilterEnchantmentPermanent filterPermanent = new FilterEnchantmentPermanent("enchantment that player controls"); - - static { - filterCard.add(CardType.ENCHANTMENT.getPredicate()); - } + private static final FilterPermanent filterPermanent = new FilterEnchantmentPermanent("enchantment that player controls"); public PolisCrusher(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{G}"); @@ -50,12 +46,11 @@ public final class PolisCrusher extends CardImpl { this.addAbility(new MonstrosityAbility("{4}{R}{G}", 3)); // Whenever Polis Crusher deals combat damage to a player, if Polis Crusher is monstrous, destroy target enchantment that player controls. - TriggeredAbility ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DestroyTargetEffect(), false, true); + Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility( + new DestroyTargetEffect(), false, true + ).withInterveningIf(MonstrousCondition.instance); ability.addTarget(new TargetPermanent(filterPermanent)); - ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); - - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, MonstrousCondition.instance, - "Whenever {this} deals combat damage to a player, if {this} is monstrous, destroy target enchantment that player controls.")); + this.addAbility(ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster())); } private PolisCrusher(final PolisCrusher card) { diff --git a/Mage.Sets/src/mage/cards/p/PolymorphousRush.java b/Mage.Sets/src/mage/cards/p/PolymorphousRush.java index 5819a2fc124..92462a17caf 100644 --- a/Mage.Sets/src/mage/cards/p/PolymorphousRush.java +++ b/Mage.Sets/src/mage/cards/p/PolymorphousRush.java @@ -8,12 +8,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; -import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import mage.util.functions.EmptyCopyApplier; @@ -31,9 +32,8 @@ public final class PolymorphousRush extends CardImpl { this.addAbility(new StriveAbility("{1}{U}")); // Choose a creature on the battlefield. Any number of target creatures you control each become a copy of that creature until end of turn. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE, StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED, false)); this.getSpellAbility().addEffect(new PolymorphousRushCopyEffect()); - + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE)); } private PolymorphousRush(final PolymorphousRush card) { @@ -66,7 +66,7 @@ class PolymorphousRushCopyEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - Target target = new TargetCreaturePermanent(new FilterCreaturePermanent("")); + Target target = new TargetPermanent(new FilterCreaturePermanent("")); target.withNotTarget(true); target.withTargetName("a creature on the battlefield (creature to copy)"); if (target.canChoose(controller.getId(), source, game) && controller.chooseTarget(outcome, target, source, game)) { diff --git a/Mage.Sets/src/mage/cards/p/PoppetStitcher.java b/Mage.Sets/src/mage/cards/p/PoppetStitcher.java index 018254b646b..00b952d09a7 100644 --- a/Mage.Sets/src/mage/cards/p/PoppetStitcher.java +++ b/Mage.Sets/src/mage/cards/p/PoppetStitcher.java @@ -1,23 +1,25 @@ package mage.cards.p; import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; import mage.abilities.keyword.TransformAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.TokenPredicate; import mage.game.permanent.token.ZombieDecayedToken; import java.util.UUID; @@ -27,11 +29,15 @@ import java.util.UUID; */ public final class PoppetStitcher extends CardImpl { - private static final Condition condition = new PermanentsOnTheBattlefieldCondition( - StaticFilters.FILTER_CREATURE_TOKEN, ComparisonType.MORE_THAN, 2 - ); + private static final FilterPermanent filter = new FilterControlledPermanent("you control three or more creature tokens"); + + static { + filter.add(TokenPredicate.TRUE); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 2); private static final Hint hint = new ValueHint( - "Creature tokens you control", new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CREATURE_TOKEN) + "Creature tokens you control", new PermanentsOnBattlefieldCount(filter) ); public PoppetStitcher(UUID ownerId, CardSetInfo setInfo) { @@ -52,12 +58,8 @@ public final class PoppetStitcher extends CardImpl { // At the beginning of your upkeep, if you control three or more creature tokens, you may transform Poppet Sticher. this.addAbility(new TransformAbility()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - new TransformSourceEffect(), true - ), condition, "At the beginning of your upkeep, " + - "if you control three or more creature tokens, you may transform {this}." - ).addHint(hint)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect(), true) + .withInterveningIf(condition).addHint(hint)); } private PoppetStitcher(final PoppetStitcher card) { diff --git a/Mage.Sets/src/mage/cards/p/PortalManipulator.java b/Mage.Sets/src/mage/cards/p/PortalManipulator.java new file mode 100644 index 00000000000..b4f39834bba --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PortalManipulator.java @@ -0,0 +1,134 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.MageItem; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.IsStepCondition; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterAttackingCreature; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.combat.CombatGroup; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.TargetPlayer; +import mage.target.Targets; +import mage.target.targetpointer.EachTargetPointer; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class PortalManipulator extends CardImpl { + + private static final Condition condition = new IsStepCondition(PhaseStep.DECLARE_ATTACKERS); + private static final FilterPermanent filter = new FilterAttackingCreature("attacking creatures controlled by that player's opponents"); + + static { + filter.add(PortalManipulatorPredicate.instance); + } + + public PortalManipulator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W/U}{W/U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // When Portal Manipulator enters the battlefield during the declare attackers step, choose target player and any number of target attacking creatures their opponents control. Those creatures are now attacking that player. + Ability ability = new EntersBattlefieldTriggeredAbility(new PortalManipulatorEffect()).withTriggerCondition(condition); + ability.addTarget(new TargetPlayer()); + ability.addTarget(new TargetPermanent(0, Integer.MAX_VALUE, filter)); + this.addAbility(ability); + } + + private PortalManipulator(final PortalManipulator card) { + super(card); + } + + @Override + public PortalManipulator copy() { + return new PortalManipulator(this); + } +} + +enum PortalManipulatorPredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return Optional + .ofNullable(input) + .map(ObjectSourcePlayer::getSource) + .map(Ability::getTargets) + .map(Targets::getFirstTarget) + .map(game::getPlayer) + .filter(player -> player.hasOpponent(input.getObject().getControllerId(), game)) + .isPresent(); + } +} + +class PortalManipulatorEffect extends OneShotEffect { + + PortalManipulatorEffect() { + super(Outcome.Benefit); + staticText = "choose target player and any number of target attacking creatures their opponents control. " + + "Those creatures are now attacking that player"; + this.setTargetPointer(new EachTargetPointer()); + } + + private PortalManipulatorEffect(final PortalManipulatorEffect effect) { + super(effect); + } + + @Override + public PortalManipulatorEffect copy() { + return new PortalManipulatorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(this.getTargetPointer().getFirst(game, source)); + if (player == null) { + return false; + } + List permanents = this + .getTargetPointer() + .getTargets(game, source) + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .map(MageItem::getId) + .collect(Collectors.toList()); + if (permanents.isEmpty()) { + return false; + } + for (CombatGroup combatGroup : game.getCombat().getGroups()) { + if (combatGroup.getAttackers().stream().anyMatch(permanents::contains)) { + combatGroup.changeDefenderPostDeclaration(player.getId(), game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PortalOfSanctuary.java b/Mage.Sets/src/mage/cards/p/PortalOfSanctuary.java index 4f854479914..d77c411a23c 100644 --- a/Mage.Sets/src/mage/cards/p/PortalOfSanctuary.java +++ b/Mage.Sets/src/mage/cards/p/PortalOfSanctuary.java @@ -6,7 +6,6 @@ import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.Cards; @@ -32,12 +31,10 @@ public final class PortalOfSanctuary extends CardImpl { // {1}, {T}: Return target creature you control and each Aura attached to it to their owners' hands. Activate this ability only during your turn. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new PortalOfSanctuaryEffect(), - new GenericManaCost(1), MyTurnCondition.instance + new PortalOfSanctuaryEffect(), new GenericManaCost(1), MyTurnCondition.instance ); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetControlledCreaturePermanent()); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); } @@ -83,4 +80,4 @@ class PortalOfSanctuaryEffect extends OneShotEffect { .forEach(perm -> cards.add(perm)); return player.moveCards(cards, Zone.HAND, source, game); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/p/Portcullis.java b/Mage.Sets/src/mage/cards/p/Portcullis.java index a85b6c4c20a..2a67517e06c 100644 --- a/Mage.Sets/src/mage/cards/p/Portcullis.java +++ b/Mage.Sets/src/mage/cards/p/Portcullis.java @@ -2,11 +2,9 @@ package mage.cards.p; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; -import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; @@ -30,17 +28,19 @@ import java.util.UUID; */ public final class Portcullis extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterCreaturePermanent("there are two or more other creatures on the battlefield"), + ComparisonType.MORE_THAN, 1, false + ); + public Portcullis(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // Whenever a creature enters the battlefield, if there are two or more other creatures on the battlefield, exile that creature. Return that card to the battlefield under its owner's control when Portcullis leaves the battlefield. - String rule = "Whenever a creature enters the battlefield, if there are two or more other creatures on the battlefield, exile that creature."; - String rule2 = " Return that card to the battlefield under its owner's control when {this} leaves the battlefield."; - TriggeredAbility ability = new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new PortcullisExileEffect(), - StaticFilters.FILTER_PERMANENT_A_CREATURE, false, SetTargetPointer.PERMANENT); - MoreThanXCreaturesOnBFCondition condition = new MoreThanXCreaturesOnBFCondition(2); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, condition, rule + rule2)); - + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + Zone.BATTLEFIELD, new PortcullisExileEffect(), StaticFilters.FILTER_PERMANENT_A_CREATURE, + false, SetTargetPointer.PERMANENT + ).withInterveningIf(condition)); } private Portcullis(final Portcullis card) { @@ -53,28 +53,12 @@ public final class Portcullis extends CardImpl { } } -class MoreThanXCreaturesOnBFCondition implements Condition { - - protected final int value; - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures on field"); - - public MoreThanXCreaturesOnBFCondition(int value) { - this.value = value; - } - - @Override - public final boolean apply(Game game, Ability source) { - PermanentsOnBattlefieldCount amount = new PermanentsOnBattlefieldCount(filter); - int count = amount.calculate(game, source, null); - return count > value; - } -} - class PortcullisExileEffect extends OneShotEffect { PortcullisExileEffect() { super(Outcome.Exile); - this.staticText = "Whenever a creature enters the battlefield, if there are two or more other creatures on the battlefield, exile that creature"; + this.staticText = "exile that creature. Return that card to the battlefield " + + "under its owner's control when {this} leaves the battlefield"; } private PortcullisExileEffect(final PortcullisExileEffect effect) { @@ -139,6 +123,6 @@ class PortcullisReturnToBattlefieldTriggeredAbility extends DelayedTriggeredAbil @Override public String getRule() { - return "Return this card to the battlefield under its owner's control when Portcullis leaves the battlefield."; + return "Return this card to the battlefield under its owner's control when {this} leaves the battlefield."; } } diff --git a/Mage.Sets/src/mage/cards/p/PossessedAven.java b/Mage.Sets/src/mage/cards/p/PossessedAven.java index 8c85263792a..3e7fce76795 100644 --- a/Mage.Sets/src/mage/cards/p/PossessedAven.java +++ b/Mage.Sets/src/mage/cards/p/PossessedAven.java @@ -22,6 +22,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -59,7 +60,7 @@ public final class PossessedAven extends CardImpl { )); Ability gainedAbility = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{2}{B}")); gainedAbility.addCost(new TapSourceCost()); - gainedAbility.addTarget(new TargetCreaturePermanent(filter)); + gainedAbility.addTarget(new TargetPermanent(filter)); ability.addEffect(new ConditionalContinuousEffect( new GainAbilitySourceEffect(gainedAbility), ThresholdCondition.instance, ", and has \"{2}{B}, {T}: Destroy target blue creature.\"" diff --git a/Mage.Sets/src/mage/cards/p/PossessedBarbarian.java b/Mage.Sets/src/mage/cards/p/PossessedBarbarian.java index c19e6aabca8..7b0b9f0c9bb 100644 --- a/Mage.Sets/src/mage/cards/p/PossessedBarbarian.java +++ b/Mage.Sets/src/mage/cards/p/PossessedBarbarian.java @@ -22,6 +22,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -60,7 +61,7 @@ public final class PossessedBarbarian extends CardImpl { )); Ability gainedAbility = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{2}{B}")); gainedAbility.addCost(new TapSourceCost()); - gainedAbility.addTarget(new TargetCreaturePermanent(filter)); + gainedAbility.addTarget(new TargetPermanent(filter)); ability.addEffect(new ConditionalContinuousEffect( new GainAbilitySourceEffect(gainedAbility), ThresholdCondition.instance, ", and has \"{2}{B}, {T}: Destroy target red creature.\"" diff --git a/Mage.Sets/src/mage/cards/p/PossessedCentaur.java b/Mage.Sets/src/mage/cards/p/PossessedCentaur.java index f35ad616eca..99da498f184 100644 --- a/Mage.Sets/src/mage/cards/p/PossessedCentaur.java +++ b/Mage.Sets/src/mage/cards/p/PossessedCentaur.java @@ -22,6 +22,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -58,7 +59,7 @@ public final class PossessedCentaur extends CardImpl { )); Ability gainedAbility = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{2}{B}")); gainedAbility.addCost(new TapSourceCost()); - gainedAbility.addTarget(new TargetCreaturePermanent(filter)); + gainedAbility.addTarget(new TargetPermanent(filter)); ability.addEffect(new ConditionalContinuousEffect( new GainAbilitySourceEffect(gainedAbility), ThresholdCondition.instance, ", and has \"{2}{B}, {T}: Destroy target green creature.\"" diff --git a/Mage.Sets/src/mage/cards/p/PossessedNomad.java b/Mage.Sets/src/mage/cards/p/PossessedNomad.java index 2d3523f34c5..195170e30cf 100644 --- a/Mage.Sets/src/mage/cards/p/PossessedNomad.java +++ b/Mage.Sets/src/mage/cards/p/PossessedNomad.java @@ -22,6 +22,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -59,7 +60,7 @@ public final class PossessedNomad extends CardImpl { )); Ability gainedAbility = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{2}{B}")); gainedAbility.addCost(new TapSourceCost()); - gainedAbility.addTarget(new TargetCreaturePermanent(filter)); + gainedAbility.addTarget(new TargetPermanent(filter)); ability.addEffect(new ConditionalContinuousEffect( new GainAbilitySourceEffect(gainedAbility), ThresholdCondition.instance, ", and has \"{2}{B}, {T}: Destroy target white creature.\"" diff --git a/Mage.Sets/src/mage/cards/p/PouncingWurm.java b/Mage.Sets/src/mage/cards/p/PouncingWurm.java index 03932a55579..eaa2a553e4c 100644 --- a/Mage.Sets/src/mage/cards/p/PouncingWurm.java +++ b/Mage.Sets/src/mage/cards/p/PouncingWurm.java @@ -1,12 +1,9 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.HasteAbility; @@ -14,18 +11,19 @@ import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.counters.CounterType; +import java.util.UUID; + /** - * * @author Backfir3 */ public final class PouncingWurm extends CardImpl { public PouncingWurm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); this.subtype.add(SubType.WURM); this.power = new MageInt(3); @@ -33,12 +31,14 @@ public final class PouncingWurm extends CardImpl { // Kicker {2}{G} this.addAbility(new KickerAbility("{2}{G}")); + // If Pouncing Wurm was kicked, it enters with three +1/+1 counters on it and with haste. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(3))), - KickedCondition.ONCE,"If Pouncing Wurm was kicked, it enters with three +1/+1 counters on it and with haste."); - ability.addEffect(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield)); - this.addAbility(ability); + Ability ability = new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(3)), KickedCondition.ONCE, + "If {this} was kicked, it enters with three +1/+1 counters on it and with haste.", "" + ); + ability.addEffect(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield)); + this.addAbility(ability); } private PouncingWurm(final PouncingWurm card) { diff --git a/Mage.Sets/src/mage/cards/p/PredatorFlagship.java b/Mage.Sets/src/mage/cards/p/PredatorFlagship.java index 3ad925e2fb1..e7a586da48a 100644 --- a/Mage.Sets/src/mage/cards/p/PredatorFlagship.java +++ b/Mage.Sets/src/mage/cards/p/PredatorFlagship.java @@ -17,6 +17,7 @@ import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -43,7 +44,7 @@ public final class PredatorFlagship extends CardImpl { // {5}, {T}: Destroy target creature with flying. ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{5}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/PrematureBurial.java b/Mage.Sets/src/mage/cards/p/PrematureBurial.java index c74ba2fe51e..23e5b7ac879 100644 --- a/Mage.Sets/src/mage/cards/p/PrematureBurial.java +++ b/Mage.Sets/src/mage/cards/p/PrematureBurial.java @@ -15,6 +15,7 @@ import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.watchers.Watcher; @@ -38,7 +39,7 @@ public final class PrematureBurial extends CardImpl { // Destroy target nonblack creature that entered the battlefield since your last turn ended. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addWatcher(new PrematureBurialWatcher()); } diff --git a/Mage.Sets/src/mage/cards/p/PreyUpon.java b/Mage.Sets/src/mage/cards/p/PreyUpon.java index ebe83d2e98b..9320387fcbc 100644 --- a/Mage.Sets/src/mage/cards/p/PreyUpon.java +++ b/Mage.Sets/src/mage/cards/p/PreyUpon.java @@ -5,11 +5,14 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author BetaSteward */ @@ -21,7 +24,7 @@ public final class PreyUpon extends CardImpl { // Target creature you control fights target creature you don't control. this.getSpellAbility().addEffect(new FightTargetsEffect()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); } private PreyUpon(final PreyUpon card) { diff --git a/Mage.Sets/src/mage/cards/p/PrickleFaeries.java b/Mage.Sets/src/mage/cards/p/PrickleFaeries.java index a25a5ac2c23..525b6089461 100644 --- a/Mage.Sets/src/mage/cards/p/PrickleFaeries.java +++ b/Mage.Sets/src/mage/cards/p/PrickleFaeries.java @@ -1,24 +1,15 @@ package mage.cards.p; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.CardsInHandCondition; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.TargetController; -import mage.constants.Zone; -import mage.game.Game; -import mage.players.Player; +import mage.constants.*; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; import java.util.UUID; /** @@ -26,6 +17,8 @@ import java.util.UUID; */ public final class PrickleFaeries extends CardImpl { + private static final Condition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 3, TargetController.ACTIVE); + public PrickleFaeries(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); @@ -39,13 +32,10 @@ public final class PrickleFaeries extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, Prickle Faeries deals 2 damage to them. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - Zone.BATTLEFIELD, TargetController.OPPONENT, new DamageTargetEffect(2), - false - ), PrickleFaeriesCondition.instance, "At the beginning of each opponent's upkeep, " + - "if that player has two or fewer cards in hand, {this} deals 2 damage to them." - )); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + Zone.BATTLEFIELD, TargetController.OPPONENT, + new DamageTargetEffect(2, true, "them"), false + ).withInterveningIf(condition)); } private PrickleFaeries(final PrickleFaeries card) { @@ -57,18 +47,3 @@ public final class PrickleFaeries extends CardImpl { return new PrickleFaeries(this); } } - -enum PrickleFaeriesCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - return Optional - .ofNullable(game.getActivePlayerId()) - .map(game::getPlayer) - .filter(Objects::nonNull) - .map(Player::getHand) - .map(Set::size) - .orElse(0) <= 2; - } -} diff --git a/Mage.Sets/src/mage/cards/p/PrimalAdversary.java b/Mage.Sets/src/mage/cards/p/PrimalAdversary.java index 659ecf61e14..714342e2f94 100644 --- a/Mage.Sets/src/mage/cards/p/PrimalAdversary.java +++ b/Mage.Sets/src/mage/cards/p/PrimalAdversary.java @@ -1,6 +1,5 @@ package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -11,19 +10,21 @@ import mage.abilities.effects.common.DoIfAnyNumberCostPaid; import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.HasteAbility; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubType; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.token.TokenImpl; import mage.target.TargetPermanent; +import java.util.UUID; + /** * * @author weirddan455 @@ -62,7 +63,7 @@ class PrimalAdversaryEffect extends OneShotEffect { PrimalAdversaryEffect() { super(Outcome.Benefit); - staticText = "put that many +1/+1 counters on Primal Adversary, " + + staticText = "put that many +1/+1 counters on {this}, " + "then up to that many target lands you control become 3/3 Wolf creatures with haste that are still lands"; } diff --git a/Mage.Sets/src/mage/cards/p/Primalcrux.java b/Mage.Sets/src/mage/cards/p/Primalcrux.java index 0b5fcc35d53..fb209126e93 100644 --- a/Mage.Sets/src/mage/cards/p/Primalcrux.java +++ b/Mage.Sets/src/mage/cards/p/Primalcrux.java @@ -32,7 +32,7 @@ public final class Primalcrux extends CardImpl { // Chroma - Primalcrux's power and toughness are each equal to the number of green mana symbols in the mana costs of permanents you control. DynamicValue xValue = new ChromaCount(ManaType.GREEN); Effect effect = new SetBasePowerToughnessSourceEffect(xValue); - effect.setText("Chroma — Primalcrux's power and toughness are each equal to the number of green mana symbols in the mana costs of permanents you control."); + effect.setText("Chroma — {this}'s power and toughness are each equal to the number of green mana symbols in the mana costs of permanents you control."); this.addAbility(new SimpleStaticAbility(Zone.ALL, effect) .addHint(new ValueHint("Green mana symbols in your permanents", xValue)) ); diff --git a/Mage.Sets/src/mage/cards/p/PrimevalSpawn.java b/Mage.Sets/src/mage/cards/p/PrimevalSpawn.java index 5fead7a8e80..15c1a2a0146 100644 --- a/Mage.Sets/src/mage/cards/p/PrimevalSpawn.java +++ b/Mage.Sets/src/mage/cards/p/PrimevalSpawn.java @@ -132,6 +132,8 @@ class PrimevalSpawnSpellEffect extends OneShotEffect { } Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 10)); player.moveCards(cards, Zone.EXILED, source, game); + game.processAction(); + cards.retainZone(Zone.EXILED, game); CardUtil.castMultipleWithAttributeForFree( player, source, game, cards, StaticFilters.FILTER_CARD, Integer.MAX_VALUE, new PrimevalSpawnTracker() diff --git a/Mage.Sets/src/mage/cards/p/PrismaticStrands.java b/Mage.Sets/src/mage/cards/p/PrismaticStrands.java index b61bb5a328d..4c320f5e31c 100644 --- a/Mage.Sets/src/mage/cards/p/PrismaticStrands.java +++ b/Mage.Sets/src/mage/cards/p/PrismaticStrands.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageObject; import mage.ObjectColor; import mage.abilities.Ability; @@ -15,22 +13,22 @@ import mage.choices.ChoiceColor; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; -import mage.constants.TimingRule; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; -import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class PrismaticStrands extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped white creature you control"); + private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("untapped white creature you control"); static { filter.add(TappedPredicate.UNTAPPED); @@ -44,7 +42,7 @@ public final class PrismaticStrands extends CardImpl { this.getSpellAbility().addEffect(new PrismaticStrandsEffect()); // Flashback-Tap an untapped white creature you control. - this.addAbility(new FlashbackAbility(this, new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, false)))); + this.addAbility(new FlashbackAbility(this, new TapTargetCost(filter))); } private PrismaticStrands(final PrismaticStrands card) { @@ -77,18 +75,17 @@ class PrismaticStrandsEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source); - if (controller != null && sourceObject != null) { - ChoiceColor choice = new ChoiceColor(); - controller.choose(Outcome.PreventDamage, choice, game); - if (choice.isChosen()) { - if (!game.isSimulation()) { - game.informPlayers(sourceObject.getLogName() + ": " + controller.getLogName() + " has chosen sources of the color " + choice.getChoice()); - } - game.addEffect(new PrismaticStrandsPreventionEffect(choice.getColor()), source); - return true; - } + if (controller == null || sourceObject == null) { + return false; } - return false; + ChoiceColor choice = new ChoiceColor(); + controller.choose(Outcome.PreventDamage, choice, game); + if (!choice.isChosen()) { + return false; + } + game.informPlayers(sourceObject.getLogName() + ": " + controller.getLogName() + " has chosen sources of the color " + choice.getChoice()); + game.addEffect(new PrismaticStrandsPreventionEffect(choice.getColor()), source); + return true; } } @@ -108,16 +105,13 @@ class PrismaticStrandsPreventionEffect extends PreventionEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (super.applies(event, source, game)) { - if (event.getType() == GameEvent.EventType.DAMAGE_PLAYER - || event.getType() == GameEvent.EventType.DAMAGE_PERMANENT) { - MageObject sourceObject = game.getObject(event.getSourceId()); - if (sourceObject != null && sourceObject.getColor(game).shares(this.color)) { - return true; - } - } + if (!super.applies(event, source, game) + || event.getType() != GameEvent.EventType.DAMAGE_PLAYER + && event.getType() != GameEvent.EventType.DAMAGE_PERMANENT) { + return false; } - return false; + MageObject sourceObject = game.getObject(event.getSourceId()); + return sourceObject != null && sourceObject.getColor(game).shares(this.color); } @Override diff --git a/Mage.Sets/src/mage/cards/p/ProfaneCommand.java b/Mage.Sets/src/mage/cards/p/ProfaneCommand.java index ebe372bff1c..984bba44788 100644 --- a/Mage.Sets/src/mage/cards/p/ProfaneCommand.java +++ b/Mage.Sets/src/mage/cards/p/ProfaneCommand.java @@ -21,6 +21,7 @@ import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; +import mage.target.TargetPermanent; import mage.target.TargetPlayer; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCreaturePermanent; @@ -37,13 +38,12 @@ public final class ProfaneCommand extends CardImpl { public ProfaneCommand(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{B}{B}"); - - DynamicValue xValue = GetXValue.instance; // Choose two - this.getSpellAbility().getModes().setMinModes(2); this.getSpellAbility().getModes().setMaxModes(2); + // * Target player loses X life. - this.getSpellAbility().addEffect(new LoseLifeTargetEffect(xValue)); + this.getSpellAbility().addEffect(new LoseLifeTargetEffect(GetXValue.instance)); this.getSpellAbility().addTarget(new TargetPlayer()); // * Return target creature card with converted mana cost X or less from your graveyard to the battlefield. @@ -52,15 +52,13 @@ public final class ProfaneCommand extends CardImpl { this.getSpellAbility().addMode(mode); // * Target creature gets -X/-X until end of turn. - DynamicValue minusValue = new SignInversionDynamicValue(xValue); + DynamicValue minusValue = new SignInversionDynamicValue(GetXValue.instance); mode = new Mode(new BoostTargetEffect(minusValue, minusValue, Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // * Up to X target creatures gain fear until end of turn. - Effect effect = new GainAbilityTargetEffect(FearAbility.getInstance(), Duration.EndOfTurn); - effect.setText("Up to X target creatures gain fear until end of turn"); - mode = new Mode(effect); + mode = new Mode(new GainAbilityTargetEffect(FearAbility.getInstance(), Duration.EndOfTurn).setText("Up to X target creatures gain fear until end of turn")); mode.addTarget(new TargetCreaturePermanent(0, 1)); this.getSpellAbility().addMode(mode); @@ -95,8 +93,8 @@ enum ProfaneCommandAdjuster implements TargetAdjuster { if (effect instanceof GainAbilityTargetEffect) { mode.getTargets().clear(); FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures gain fear until end of turn"); - mode.addTarget(new TargetCreaturePermanent(0, xValue, filter, false)); + mode.addTarget(new TargetPermanent(0, xValue, filter)); } } } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/p/ProfessorHojo.java b/Mage.Sets/src/mage/cards/p/ProfessorHojo.java index 92eef1471b2..3a199ba66f9 100644 --- a/Mage.Sets/src/mage/cards/p/ProfessorHojo.java +++ b/Mage.Sets/src/mage/cards/p/ProfessorHojo.java @@ -101,12 +101,19 @@ class ProfessorHojoEffect extends CostModificationEffectImpl { @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { + + Set targets; + if (game.inCheckPlayableState()) { + targets = CardUtil.getAllPossibleTargets(abilityToModify, game); + } else { + targets = CardUtil.getAllSelectedTargets(abilityToModify, game); + } + return game.isActivePlayer(source.getControllerId()) && abilityToModify.isControlledBy(source.getControllerId()) + && abilityToModify.isActivatedAbility() && !ProfessorHojoWatcher.checkPlayer(game, source) - && CardUtil - .getAllSelectedTargets(abilityToModify, game) - .stream() + && targets.stream() .map(game::getPermanent) .filter(Objects::nonNull) .filter(permanent -> permanent.isCreature(game)) diff --git a/Mage.Sets/src/mage/cards/p/ProftsEideticMemory.java b/Mage.Sets/src/mage/cards/p/ProftsEideticMemory.java index 8797f7c4fa1..60e17d1518a 100644 --- a/Mage.Sets/src/mage/cards/p/ProftsEideticMemory.java +++ b/Mage.Sets/src/mage/cards/p/ProftsEideticMemory.java @@ -1,32 +1,33 @@ package mage.cards.p; -import java.util.UUID; - import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.DrewTwoOrMoreCardsCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.IntPlusDynamicValue; import mage.abilities.dynamicvalue.common.CardsDrawnThisTurnDynamicValue; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.constants.Duration; -import mage.constants.SuperType; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SuperType; import mage.counters.CounterType; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author DominionSpy */ public final class ProftsEideticMemory extends CardImpl { + private static final DynamicValue xValue = new IntPlusDynamicValue(-1, CardsDrawnThisTurnDynamicValue.instance); + public ProftsEideticMemory(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); @@ -38,21 +39,17 @@ public final class ProftsEideticMemory extends CardImpl { // You have no maximum hand size. this.addAbility(new SimpleStaticAbility(new MaximumHandSizeControllerEffect( Integer.MAX_VALUE, Duration.WhileOnBattlefield, - MaximumHandSizeControllerEffect.HandSizeModification.SET))); + MaximumHandSizeControllerEffect.HandSizeModification.SET + ))); // At the beginning of combat on your turn, if you've drawn more than one card this turn, // put X +1/+1 counters on target creature you control, // where X is the number of cards you've drawn this turn minus one. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - new AddCountersTargetEffect( - CounterType.P1P1.createInstance(), - new IntPlusDynamicValue(-1, CardsDrawnThisTurnDynamicValue.instance)) - ), - DrewTwoOrMoreCardsCondition.instance, - "At the beginning of combat on your turn, if you've drawn more than one card this turn, " + - "put X +1/+1 counters on target creature you control, " + - "where X is the number of cards you've drawn this turn minus one"); + Ability ability = new BeginningOfCombatTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance(), xValue) + .setText("put X +1/+1 counters on target creature you control, " + + "where X is the number of cards you've drawn this turn minus one") + ).withInterveningIf(DrewTwoOrMoreCardsCondition.instance); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/ProgenitorMimic.java b/Mage.Sets/src/mage/cards/p/ProgenitorMimic.java index e671856f85f..fd24facb62b 100644 --- a/Mage.Sets/src/mage/cards/p/ProgenitorMimic.java +++ b/Mage.Sets/src/mage/cards/p/ProgenitorMimic.java @@ -1,37 +1,38 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.CreateTokenCopySourceEffect; import mage.abilities.effects.common.CopyPermanentEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TokenPredicate; import mage.util.functions.AbilityCopyApplier; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ProgenitorMimic extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("no Token"); + private static final FilterPermanent filter = new FilterCreaturePermanent("this creature isn't a token"); static { filter.add(TokenPredicate.FALSE); } + private static final Condition condition = new SourceMatchesFilterCondition(filter); + public ProgenitorMimic(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{G}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{U}"); this.subtype.add(SubType.SHAPESHIFTER); this.power = new MageInt(0); @@ -40,18 +41,14 @@ public final class ProgenitorMimic extends CardImpl { // You may have Progenitor Mimic enter the battlefield as a copy of any creature on the battlefield // except it has "At the beginning of your upkeep, if this creature isn't a token, // create a token that's a copy of this creature." - Effect effect = new CreateTokenCopySourceEffect(); - effect.setText("create a token that's a copy of this creature"); - - AbilityCopyApplier applier = new AbilityCopyApplier( - new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(effect), - new SourceMatchesFilterCondition(filter), - "At the beginning of your upkeep, if this creature isn't a token, create a token that's a copy of this creature.") - ); - effect = new CopyPermanentEffect(applier); - effect.setText("as a copy of any creature on the battlefield except it has \"At the beginning of your upkeep, if this creature isn't a token, create a token that's a copy of this creature.\""); - this.addAbility(new EntersBattlefieldAbility(effect, true)); + this.addAbility(new EntersBattlefieldAbility(new CopyPermanentEffect(new AbilityCopyApplier( + new BeginningOfUpkeepTriggeredAbility( + new CreateTokenCopySourceEffect().setText("create a token that's a copy of this creature") + ).withInterveningIf(condition) + )).setText("as a copy of any creature on the battlefield, except it has " + + "\"At the beginning of your upkeep, if this creature isn't a token, " + + "create a token that's a copy of this creature.\""), true + )); } private ProgenitorMimic(final ProgenitorMimic card) { diff --git a/Mage.Sets/src/mage/cards/p/PromiseOfTomorrow.java b/Mage.Sets/src/mage/cards/p/PromiseOfTomorrow.java index dea8fdf10dd..6dd75516b53 100644 --- a/Mage.Sets/src/mage/cards/p/PromiseOfTomorrow.java +++ b/Mage.Sets/src/mage/cards/p/PromiseOfTomorrow.java @@ -1,13 +1,13 @@ package mage.cards.p; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ExileTargetForSourceEffect; import mage.abilities.effects.common.ReturnFromExileForSourceEffect; import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -15,6 +15,7 @@ import mage.constants.ComparisonType; import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; import java.util.UUID; @@ -24,7 +25,7 @@ import java.util.UUID; public final class PromiseOfTomorrow extends CardImpl { private static final Condition condition = new PermanentsOnTheBattlefieldCondition( - StaticFilters.FILTER_CONTROLLED_CREATURE, + new FilterControlledCreaturePermanent("you control no creatures"), ComparisonType.EQUAL_TO, 0, true ); @@ -38,12 +39,12 @@ public final class PromiseOfTomorrow extends CardImpl { )); // At the beginning of each end step, if you control no creatures, sacrifice Promise of Tomorrow and return all cards exiled with it to the battlefield under your control. - BeginningOfEndStepTriggeredAbility returnAbility = new BeginningOfEndStepTriggeredAbility(TargetController.ANY, new SacrificeSourceEffect(), false); - returnAbility.addEffect(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - returnAbility, condition, "At the beginning of each end step, if you control no creatures, " + - "sacrifice {this} and return all cards exiled with it to the battlefield under your control." - )); + Ability ability = new BeginningOfEndStepTriggeredAbility( + TargetController.ANY, new SacrificeSourceEffect(), false, condition + ); + ability.addEffect(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD) + .setText("and return all cards exiled with it to the battlefield under your control")); + this.addAbility(ability); } private PromiseOfTomorrow(final PromiseOfTomorrow card) { diff --git a/Mage.Sets/src/mage/cards/p/PromisingDuskmage.java b/Mage.Sets/src/mage/cards/p/PromisingDuskmage.java index 3c4fec64340..6edd71de717 100644 --- a/Mage.Sets/src/mage/cards/p/PromisingDuskmage.java +++ b/Mage.Sets/src/mage/cards/p/PromisingDuskmage.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -13,6 +12,7 @@ import mage.constants.SubType; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.util.CardUtil; import java.util.UUID; @@ -30,11 +30,8 @@ public final class PromisingDuskmage extends CardImpl { this.toughness = new MageInt(3); // When Promising Duskmage dies, if it had a +1/+1 counter on it, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(1)), - PromisingDuskmageCondition.instance, "When {this} dies, " + - "if it had a +1/+1 counter on it, draw a card." - )); + this.addAbility(new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .withInterveningIf(PromisingDuskmageCondition.instance)); } private PromisingDuskmage(final PromisingDuskmage card) { @@ -52,7 +49,14 @@ enum PromisingDuskmageCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) source.getEffects().get(0).getValue("permanentLeftBattlefield"); - return permanent != null && permanent.getCounters(game).containsKey(CounterType.P1P1); + return CardUtil + .getEffectValueFromAbility(source, "permanentLeftBattlefield", Permanent.class) + .filter(permanent -> permanent.getCounters(game).containsKey(CounterType.P1P1)) + .isPresent(); + } + + @Override + public String toString() { + return "it had a +1/+1 counter on it"; } } diff --git a/Mage.Sets/src/mage/cards/p/Provoke.java b/Mage.Sets/src/mage/cards/p/Provoke.java index 324c8b8475e..0cf42d67785 100644 --- a/Mage.Sets/src/mage/cards/p/Provoke.java +++ b/Mage.Sets/src/mage/cards/p/Provoke.java @@ -9,10 +9,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author LevelX2 */ @@ -26,7 +29,7 @@ public final class Provoke extends CardImpl { Effect effect = new BlocksIfAbleTargetEffect(Duration.EndOfTurn); effect.setText("That creature blocks this turn if able"); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); diff --git a/Mage.Sets/src/mage/cards/p/PsychoticFury.java b/Mage.Sets/src/mage/cards/p/PsychoticFury.java index 3e051377a96..c3d3ec3634c 100644 --- a/Mage.Sets/src/mage/cards/p/PsychoticFury.java +++ b/Mage.Sets/src/mage/cards/p/PsychoticFury.java @@ -11,6 +11,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.MulticoloredPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -30,7 +31,7 @@ public final class PsychoticFury extends CardImpl { // Target multicolored creature gains double strike until end of turn. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn)); // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); diff --git a/Mage.Sets/src/mage/cards/p/PublicExecution.java b/Mage.Sets/src/mage/cards/p/PublicExecution.java index 7233230dd30..9617a293300 100644 --- a/Mage.Sets/src/mage/cards/p/PublicExecution.java +++ b/Mage.Sets/src/mage/cards/p/PublicExecution.java @@ -15,10 +15,13 @@ import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * @author jeffwadsworth */ @@ -29,7 +32,7 @@ public final class PublicExecution extends CardImpl { // Destroy target creature an opponent controls. Each other creature that player controls gets -2/-0 until end of turn. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.getSpellAbility().addEffect(new PublicExecutionEffect()); } diff --git a/Mage.Sets/src/mage/cards/p/PuncturingLight.java b/Mage.Sets/src/mage/cards/p/PuncturingLight.java index 4e4a2f88670..18faaf075cb 100644 --- a/Mage.Sets/src/mage/cards/p/PuncturingLight.java +++ b/Mage.Sets/src/mage/cards/p/PuncturingLight.java @@ -10,6 +10,7 @@ import mage.constants.ComparisonType; import mage.filter.common.FilterAttackingOrBlockingCreature; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -28,7 +29,7 @@ public final class PuncturingLight extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}"); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/p/Purge.java b/Mage.Sets/src/mage/cards/p/Purge.java index e3d989598ac..232a6c5e5e7 100644 --- a/Mage.Sets/src/mage/cards/p/Purge.java +++ b/Mage.Sets/src/mage/cards/p/Purge.java @@ -10,6 +10,7 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class Purge extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}"); // Destroy target artifact creature or black creature. It can't be regenerated. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); } diff --git a/Mage.Sets/src/mage/cards/p/PusKami.java b/Mage.Sets/src/mage/cards/p/PusKami.java index ac715e4c406..02496217b8b 100644 --- a/Mage.Sets/src/mage/cards/p/PusKami.java +++ b/Mage.Sets/src/mage/cards/p/PusKami.java @@ -15,8 +15,11 @@ import mage.constants.SubType; import mage.constants.ColoredManaSymbol; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author Loki @@ -32,7 +35,7 @@ public final class PusKami extends CardImpl { // {B}, Sacrifice Pus Kami: Destroy target nonblack creature. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ColoredManaCost(ColoredManaSymbol.B)); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + ability.addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.addAbility(ability); this.addAbility(new SoulshiftAbility(6)); } diff --git a/Mage.Sets/src/mage/cards/p/PushPull.java b/Mage.Sets/src/mage/cards/p/PushPull.java index e0a55f6c229..956e3f5c8cd 100644 --- a/Mage.Sets/src/mage/cards/p/PushPull.java +++ b/Mage.Sets/src/mage/cards/p/PushPull.java @@ -22,6 +22,7 @@ import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInASingleGraveyard; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTargets; @@ -49,7 +50,7 @@ public final class PushPull extends SplitCard { // Push // Destroy target tapped creature. getLeftHalfCard().getSpellAbility().addEffect(new DestroyTargetEffect()); - getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + getLeftHalfCard().getSpellAbility().addTarget(new TargetPermanent(filter)); // Pull // Put up to two target creature cards from a single graveyard onto the battlefield under your control. They gain haste until end of turn. Sacrifice them at the beginning of the next end step. diff --git a/Mage.Sets/src/mage/cards/p/Putrefax.java b/Mage.Sets/src/mage/cards/p/Putrefax.java index 5f261b98f1a..ffffa137643 100644 --- a/Mage.Sets/src/mage/cards/p/Putrefax.java +++ b/Mage.Sets/src/mage/cards/p/Putrefax.java @@ -1,28 +1,26 @@ - - package mage.cards.p; -import java.util.UUID; import mage.MageInt; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.InfectAbility; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.events.GameEvent; +import mage.constants.TargetController; + +import java.util.UUID; /** - * * @author Loki */ public final class Putrefax extends CardImpl { - public Putrefax (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}{G}"); + public Putrefax(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); @@ -31,7 +29,9 @@ public final class Putrefax extends CardImpl { this.addAbility(TrampleAbility.getInstance()); this.addAbility(HasteAbility.getInstance()); this.addAbility(InfectAbility.getInstance()); - this.addAbility(new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new SacrificeSourceEffect())); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.NEXT, new SacrificeSourceEffect(), false + )); } private Putrefax(final Putrefax card) { diff --git a/Mage.Sets/src/mage/cards/p/PutridWarrior.java b/Mage.Sets/src/mage/cards/p/PutridWarrior.java index f46b567d50d..e68a0d51708 100644 --- a/Mage.Sets/src/mage/cards/p/PutridWarrior.java +++ b/Mage.Sets/src/mage/cards/p/PutridWarrior.java @@ -4,15 +4,12 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.DealsDamageSourceTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GainLifeAllEffect; import mage.abilities.effects.common.LoseLifeAllPlayersEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.game.Game; -import mage.players.Player; import java.util.UUID; @@ -31,7 +28,7 @@ public final class PutridWarrior extends CardImpl { // Whenever Putrid Warrior deals damage, choose one - Each player loses 1 life; or each player gains 1 life. Ability ability = new DealsDamageSourceTriggeredAbility(new LoseLifeAllPlayersEffect(1)); - ability.addMode(new Mode(new PutridWarriorGainLifeEffect())); + ability.addMode(new Mode(new GainLifeAllEffect(1))); this.addAbility(ability); } @@ -44,32 +41,3 @@ public final class PutridWarrior extends CardImpl { return new PutridWarrior(this); } } - -class PutridWarriorGainLifeEffect extends OneShotEffect { - - PutridWarriorGainLifeEffect() { - super(Outcome.GainLife); - staticText = "each player gains 1 life"; - } - - private PutridWarriorGainLifeEffect(final PutridWarriorGainLifeEffect effect) { - super(effect); - } - - @Override - public PutridWarriorGainLifeEffect copy() { - return new PutridWarriorGainLifeEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - player.gainLife(1, game, source); - } - } - return true; - } - -} diff --git a/Mage.Sets/src/mage/cards/p/PyreZombie.java b/Mage.Sets/src/mage/cards/p/PyreZombie.java index 9a67214ee97..83fdbc0a4e2 100644 --- a/Mage.Sets/src/mage/cards/p/PyreZombie.java +++ b/Mage.Sets/src/mage/cards/p/PyreZombie.java @@ -34,7 +34,7 @@ public final class PyreZombie extends CardImpl { // At the beginning of your upkeep, if Pyre Zombie is in your graveyard, you may pay {1}{B}{B}. If you do, return Pyre Zombie to your hand. this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.GRAVEYARD, - TargetController.YOU, new DoIfCostPaid(new ReturnToHandSourceEffect().setText("return {this} to your hand"), new ManaCostsImpl<>("{1}{B}{B}")), + TargetController.YOU, new DoIfCostPaid(new ReturnToHandSourceEffect().setText("return it to your hand"), new ManaCostsImpl<>("{1}{B}{B}")), false).withInterveningIf(SourceInGraveyardCondition.instance)); // {1}{R}{R}, Sacrifice Pyre Zombie: Pyre Zombie deals 2 damage to any target. diff --git a/Mage.Sets/src/mage/cards/p/PyrewildShaman.java b/Mage.Sets/src/mage/cards/p/PyrewildShaman.java index 93dc40f06c0..9b8a684b8d3 100644 --- a/Mage.Sets/src/mage/cards/p/PyrewildShaman.java +++ b/Mage.Sets/src/mage/cards/p/PyrewildShaman.java @@ -30,7 +30,7 @@ public final class PyrewildShaman extends CardImpl { // Whenever one or more creatures you control deal combat damage to a player, if Pyrewild Shaman is in your graveyard, you may pay {3}. If you do, return Pyrewild Shaman to your hand. this.addAbility(new OneOrMoreCombatDamagePlayerTriggeredAbility(Zone.GRAVEYARD, new DoIfCostPaid( - new ReturnToHandSourceEffect().setText("return {this} to your hand"), + new ReturnToHandSourceEffect().setText("return this card to your hand"), new ManaCostsImpl<>("{3}") ), StaticFilters.FILTER_PERMANENT_CREATURES, SetTargetPointer.NONE, false) .withInterveningIf(SourceInGraveyardCondition.instance)); diff --git a/Mage.Sets/src/mage/cards/p/Pyrohemia.java b/Mage.Sets/src/mage/cards/p/Pyrohemia.java index 5ebe14c9cdc..c161ce7991f 100644 --- a/Mage.Sets/src/mage/cards/p/Pyrohemia.java +++ b/Mage.Sets/src/mage/cards/p/Pyrohemia.java @@ -1,36 +1,37 @@ - package mage.cards.p; -import java.util.UUID; -import mage.abilities.TriggeredAbility; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.condition.common.CreatureCountCondition; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageEverythingEffect; import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.TargetController; -import mage.constants.Zone; -import mage.game.events.GameEvent; +import mage.filter.common.FilterCreaturePermanent; + +import java.util.UUID; /** - * * @author fireshoes */ public final class Pyrohemia extends CardImpl { - private static final String ruleText = "At the beginning of the end step, if no creatures are on the battlefield, sacrifice {this}."; + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterCreaturePermanent("no creatures are on the battlefield"), ComparisonType.EQUAL_TO, 0 + ); public Pyrohemia(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}{R}"); // 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 ConditionalInterveningIfTriggeredAbility(triggered, new CreatureCountCondition(0, TargetController.ANY), ruleText)); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.NEXT, new SacrificeSourceEffect(), false, condition + )); // {R}: Pyrohemia deals 1 damage to each creature and each player. this.addAbility(new SimpleActivatedAbility(new DamageEverythingEffect(1), new ManaCostsImpl<>("{R}"))); diff --git a/Mage.Sets/src/mage/cards/q/QueenMarchesa.java b/Mage.Sets/src/mage/cards/q/QueenMarchesa.java index 1c4d74e037d..79019ed5ac6 100644 --- a/Mage.Sets/src/mage/cards/q/QueenMarchesa.java +++ b/Mage.Sets/src/mage/cards/q/QueenMarchesa.java @@ -1,18 +1,15 @@ - package mage.cards.q; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.BecomesMonarchSourceEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.common.MonarchHint; import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.HasteAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -21,8 +18,9 @@ import mage.constants.SuperType; import mage.game.Game; import mage.game.permanent.token.QueenMarchesaAssassinToken; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class QueenMarchesa extends CardImpl { @@ -38,16 +36,16 @@ public final class QueenMarchesa extends CardImpl { // Deathtouch this.addAbility(DeathtouchAbility.getInstance()); + // Haste + this.addAbility(HasteAbility.getInstance()); // When Queen Marchesa enters the battlefield, you become the monarch. this.addAbility(new EntersBattlefieldTriggeredAbility(new BecomesMonarchSourceEffect()).addHint(MonarchHint.instance)); // At the beginning of your upkeep, if an opponent is the monarch, create a 1/1 black Assassin creature token with deathtouch and haste. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new QueenMarchesaAssassinToken())), - OpponentIsMonarchCondition.instance, - "At the beginning of your upkeep, if an opponent is the monarch, create a 1/1 black Assassin creature token with deathtouch and haste.")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new QueenMarchesaAssassinToken())) + .withInterveningIf(QueenMarchesaCondition.instance)); } private QueenMarchesa(final QueenMarchesa card) { @@ -60,9 +58,8 @@ public final class QueenMarchesa extends CardImpl { } } -enum OpponentIsMonarchCondition implements Condition { - - instance; +enum QueenMarchesaCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { diff --git a/Mage.Sets/src/mage/cards/q/Quicksand.java b/Mage.Sets/src/mage/cards/q/Quicksand.java index 9229168c64e..434e50ad3a9 100644 --- a/Mage.Sets/src/mage/cards/q/Quicksand.java +++ b/Mage.Sets/src/mage/cards/q/Quicksand.java @@ -16,6 +16,7 @@ import mage.constants.Zone; import mage.filter.common.FilterAttackingCreature; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class Quicksand extends CardImpl { SimpleActivatedAbility ability = new SimpleActivatedAbility( new BoostTargetEffect(-1, -2, Duration.EndOfTurn), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/q/QuietContemplation.java b/Mage.Sets/src/mage/cards/q/QuietContemplation.java index 5d3358c991c..c19f2be85da 100644 --- a/Mage.Sets/src/mage/cards/q/QuietContemplation.java +++ b/Mage.Sets/src/mage/cards/q/QuietContemplation.java @@ -12,8 +12,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -30,7 +33,7 @@ public final class QuietContemplation extends CardImpl { effect.setText("and it doesn't untap during its controller's next untap step"); doIfCostPaid.addEffect(effect); Ability ability = new SpellCastControllerTriggeredAbility(doIfCostPaid, StaticFilters.FILTER_SPELL_A_NON_CREATURE, false); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/q/QuilledGreatwurm.java b/Mage.Sets/src/mage/cards/q/QuilledGreatwurm.java index 5f5cf52e503..cebc2dd16f8 100644 --- a/Mage.Sets/src/mage/cards/q/QuilledGreatwurm.java +++ b/Mage.Sets/src/mage/cards/q/QuilledGreatwurm.java @@ -24,7 +24,7 @@ import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.CounterAnyPredicate; import mage.game.Game; import mage.players.Player; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; import java.util.UUID; @@ -102,7 +102,7 @@ class QuilledGreatwurmEffect extends AsThoughEffectImpl { return false; } Costs costs = new CostsImpl<>(); - costs.add(new RemoveCounterCost(new TargetControlledCreaturePermanent(1, 6, filter, true), null, 6)); + costs.add(new RemoveCounterCost(new TargetControlledPermanent(1, 6, filter, true), null, 6)); controller.setCastSourceIdWithAlternateMana( objectId, new ManaCostsImpl<>("{4}{G}{G}"), costs, MageIdentifier.QuilledGreatwurmAlternateCast diff --git a/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java b/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java index ffd15b4f2cf..6466c942f14 100644 --- a/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java +++ b/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java @@ -17,6 +17,7 @@ import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.XManaValueTargetAdjuster; @@ -43,7 +44,7 @@ public final class QuillmaneBaku extends CardImpl { Ability ability = new SimpleActivatedAbility(new ReturnToHandTargetEffect(), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); ability.addCost(new RemoveVariableCountersSourceCost(CounterType.KI)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); ability.setTargetAdjuster(new XManaValueTargetAdjuster(ComparisonType.OR_LESS)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RabidBite.java b/Mage.Sets/src/mage/cards/r/RabidBite.java index 7344f543dd9..7a9b21225fe 100644 --- a/Mage.Sets/src/mage/cards/r/RabidBite.java +++ b/Mage.Sets/src/mage/cards/r/RabidBite.java @@ -5,11 +5,14 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author fireshoes */ @@ -21,7 +24,7 @@ public final class RabidBite extends CardImpl { // Target creature you control deals damage equal to its power to target creature you don't control. this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); } private RabidBite(final RabidBite card) { diff --git a/Mage.Sets/src/mage/cards/r/RabidRats.java b/Mage.Sets/src/mage/cards/r/RabidRats.java index 77a86379821..c407e560fff 100644 --- a/Mage.Sets/src/mage/cards/r/RabidRats.java +++ b/Mage.Sets/src/mage/cards/r/RabidRats.java @@ -14,6 +14,7 @@ import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterBlockingCreature; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -30,7 +31,7 @@ public final class RabidRats extends CardImpl { // {tap}: Target blocking creature gets -1/-1 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(-1, -1, Duration.EndOfTurn), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(new FilterBlockingCreature())); + ability.addTarget(new TargetPermanent(new FilterBlockingCreature())); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RadiantPerformer.java b/Mage.Sets/src/mage/cards/r/RadiantPerformer.java index baf97129cec..89ed4ec669d 100644 --- a/Mage.Sets/src/mage/cards/r/RadiantPerformer.java +++ b/Mage.Sets/src/mage/cards/r/RadiantPerformer.java @@ -6,7 +6,6 @@ import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromHandSourcePermanentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CopySpellForEachItCouldTargetEffect; import mage.abilities.keyword.FlashAbility; import mage.cards.CardImpl; @@ -52,13 +51,8 @@ public final class RadiantPerformer extends CardImpl { this.addAbility(FlashAbility.getInstance()); // When Radiant Performer enters the battlefield, if you cast it from your hand, choose target spell or ability that targets only a single permanent or player. Copy that spell or ability for each other permanent or player the spell or ability could target. Each copy targets a different one of those permanents and players. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new RadiantPerformerEffect()), - CastFromHandSourcePermanentCondition.instance, "When {this} enters, " + - "if you cast it from your hand, choose target spell or ability that targets only " + - "a single permanent or player. Copy that spell or ability for each other permanent or player " + - "the spell or ability could target. Each copy targets a different one of those permanents and players." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new RadiantPerformerEffect()) + .withInterveningIf(CastFromHandSourcePermanentCondition.instance); ability.addTarget(new TargetStackObject(filter)); this.addAbility(ability, new CastFromHandWatcher()); } @@ -98,6 +92,7 @@ class RadiantPerformerEffect extends CopySpellForEachItCouldTargetEffect { RadiantPerformerEffect() { super(); + staticText = "choose target spell or ability that targets only a single permanent or player. Copy that spell or ability for each other permanent or player the spell or ability could target. Each copy targets a different one of those permanents and players"; } private RadiantPerformerEffect(final RadiantPerformerEffect effect) { diff --git a/Mage.Sets/src/mage/cards/r/RadiantsJudgment.java b/Mage.Sets/src/mage/cards/r/RadiantsJudgment.java index 8ce18659009..db92762efa3 100644 --- a/Mage.Sets/src/mage/cards/r/RadiantsJudgment.java +++ b/Mage.Sets/src/mage/cards/r/RadiantsJudgment.java @@ -11,6 +11,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class RadiantsJudgment extends CardImpl { // Destroy target creature with power 4 or greater. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Cycling {2} this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{2}"))); } diff --git a/Mage.Sets/src/mage/cards/r/RafterDemon.java b/Mage.Sets/src/mage/cards/r/RafterDemon.java index 9c966444ab6..9bffe4ebf87 100644 --- a/Mage.Sets/src/mage/cards/r/RafterDemon.java +++ b/Mage.Sets/src/mage/cards/r/RafterDemon.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.SpectacleCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; import mage.abilities.keyword.SpectacleAbility; @@ -32,14 +31,9 @@ public final class RafterDemon extends CardImpl { this.addAbility(new SpectacleAbility(this, new ManaCostsImpl<>("{3}{B}{R}"))); // When Rafter Demon enters the battlefield, if its spectacle cost was paid, each opponent discards a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DiscardEachPlayerEffect( - StaticValue.get(1), false, TargetController.OPPONENT - )), SpectacleCondition.instance, - "When {this} enters, " + - "if its spectacle cost was paid, " + - "each opponent discards a card." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DiscardEachPlayerEffect( + StaticValue.get(1), false, TargetController.OPPONENT + )).withInterveningIf(SpectacleCondition.instance)); } private RafterDemon(final RafterDemon card) { diff --git a/Mage.Sets/src/mage/cards/r/RagMan.java b/Mage.Sets/src/mage/cards/r/RagMan.java index 7bfdf48b6a2..619f3a68947 100644 --- a/Mage.Sets/src/mage/cards/r/RagMan.java +++ b/Mage.Sets/src/mage/cards/r/RagMan.java @@ -8,12 +8,10 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.RevealHandTargetEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; @@ -35,11 +33,12 @@ public final class RagMan extends CardImpl { this.toughness = new MageInt(1); // {B}{B}{B}, {T}: Target opponent reveals their hand and discards a creature card at random. Activate this ability only during your turn. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new RevealHandTargetEffect(), new ManaCostsImpl<>("{B}{B}{B}"), MyTurnCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new RevealHandTargetEffect(), new ManaCostsImpl<>("{B}{B}{B}"), MyTurnCondition.instance + ); ability.addCost(new TapSourceCost()); ability.addEffect(new RagManDiscardEffect()); ability.addTarget(new TargetOpponent()); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/Ragamuffyn.java b/Mage.Sets/src/mage/cards/r/Ragamuffyn.java index 21f8e3433e9..7e1733d9fc0 100644 --- a/Mage.Sets/src/mage/cards/r/Ragamuffyn.java +++ b/Mage.Sets/src/mage/cards/r/Ragamuffyn.java @@ -1,48 +1,46 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.common.HellbentCondition; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; -import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; /** - * * @author djbrez */ public final class Ragamuffyn extends CardImpl { - + private static final FilterControlledPermanent filter = new FilterControlledPermanent("a creature or land"); - + static { filter.add(Predicates.or(CardType.CREATURE.getPredicate(), CardType.LAND.getPredicate())); } public Ragamuffyn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.CLERIC); this.power = new MageInt(2); this.toughness = new MageInt(2); // Hellbent - {tap}, Sacrifice a creature or land: Draw a card. Activate this ability only if you have no cards in hand. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD,new DrawCardSourceControllerEffect(1),new TapSourceCost(), HellbentCondition.instance); - ability.setAbilityWord(AbilityWord.HELLBENT); + Ability ability = new ActivateIfConditionActivatedAbility( + new DrawCardSourceControllerEffect(1), new TapSourceCost(), HellbentCondition.instance + ); ability.addCost(new SacrificeTargetCost(filter)); - this.addAbility(ability); + this.addAbility(ability.setAbilityWord(AbilityWord.HELLBENT)); } private Ragamuffyn(final Ragamuffyn card) { diff --git a/Mage.Sets/src/mage/cards/r/RageWeaver.java b/Mage.Sets/src/mage/cards/r/RageWeaver.java index 293a3e8f18e..cdcce1908bb 100644 --- a/Mage.Sets/src/mage/cards/r/RageWeaver.java +++ b/Mage.Sets/src/mage/cards/r/RageWeaver.java @@ -18,6 +18,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -42,7 +43,7 @@ public final class RageWeaver extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(1); Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn), new GenericManaCost(2)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RagingBattleMouse.java b/Mage.Sets/src/mage/cards/r/RagingBattleMouse.java index fbd10b2475b..76a043ed272 100644 --- a/Mage.Sets/src/mage/cards/r/RagingBattleMouse.java +++ b/Mage.Sets/src/mage/cards/r/RagingBattleMouse.java @@ -2,32 +2,33 @@ package mage.cards.r; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.CelebrationCondition; +import mage.abilities.condition.common.YouCastExactOneSpellThisTurnCondition; import mage.abilities.decorator.ConditionalCostModificationEffect; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; import mage.target.common.TargetControlledCreaturePermanent; import mage.watchers.common.PermanentsEnteredBattlefieldWatcher; -import mage.abilities.condition.common.YouCastExactOneSpellThisTurnCondition; import java.util.UUID; /** - * * @author Susucr */ public final class RagingBattleMouse extends CardImpl { public RagingBattleMouse(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); - + this.subtype.add(SubType.MOUSE); this.power = new MageInt(2); this.toughness = new MageInt(1); @@ -39,17 +40,11 @@ public final class RagingBattleMouse extends CardImpl { ))); // Celebration -- At the beginning of combat on your turn, if two or more nonland permanents entered the battlefield under your control this turn, target creature you control gets +1/+1 until end of turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - new BoostTargetEffect(1, 1, Duration.EndOfTurn) - ), CelebrationCondition.instance, "At the beginning of combat on your turn, " - + "if two or more nonland permanents entered the battlefield under your control this turn, " - + "target creature you control gets +1/+1 until end of turn." - ); + Ability ability = new BeginningOfCombatTriggeredAbility( + new BoostTargetEffect(1, 1, Duration.EndOfTurn) + ).withInterveningIf(CelebrationCondition.instance); ability.addTarget(new TargetControlledCreaturePermanent()); - ability.setAbilityWord(AbilityWord.CELEBRATION); - ability.addHint(CelebrationCondition.getHint()); - this.addAbility(ability, new PermanentsEnteredBattlefieldWatcher()); + this.addAbility(ability.setAbilityWord(AbilityWord.CELEBRATION).addHint(CelebrationCondition.getHint()), new PermanentsEnteredBattlefieldWatcher()); } private RagingBattleMouse(final RagingBattleMouse card) { diff --git a/Mage.Sets/src/mage/cards/r/RagingRiver.java b/Mage.Sets/src/mage/cards/r/RagingRiver.java index fffdfdc0d5a..0977d98abd8 100644 --- a/Mage.Sets/src/mage/cards/r/RagingRiver.java +++ b/Mage.Sets/src/mage/cards/r/RagingRiver.java @@ -12,6 +12,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; @@ -22,7 +23,7 @@ import mage.game.combat.CombatGroup; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.targetpointer.FixedTarget; import java.util.ArrayList; @@ -57,6 +58,12 @@ public final class RagingRiver extends CardImpl { class RagingRiverEffect extends OneShotEffect { + private static final FilterPermanent filterBlockers = new FilterControlledCreaturePermanent("creatures without flying you control to assign to the \"left\" pile (creatures not chosen will be assigned to the \"right\" pile)"); + + static { + filterBlockers.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); + } + RagingRiverEffect() { super(Outcome.Detriment); staticText = "each defending player divides all creatures without flying they control into a \"left\" pile and a \"right\" pile. Then, for each attacking creature you control, choose \"left\" or \"right.\" That creature can't be blocked this combat except by creatures with flying and creatures in a pile with the chosen label"; @@ -74,84 +81,87 @@ class RagingRiverEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - List left = new ArrayList<>(); - List right = new ArrayList<>(); - - for (UUID defenderId : game.getCombat().getPlayerDefenders(game)) { - Player defender = game.getPlayer(defenderId); - if (defender != null) { - List leftLog = new ArrayList<>(); - List rightLog = new ArrayList<>(); - FilterControlledCreaturePermanent filterBlockers = new FilterControlledCreaturePermanent("creatures without flying you control to assign to the \"left\" pile (creatures not chosen will be assigned to the \"right\" pile)"); - filterBlockers.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); - Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filterBlockers, true); - if (target.canChoose(defenderId, source, game)) { - if (defender.chooseTarget(Outcome.Neutral, target, source, game)) { - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), defenderId, game)) { - if (target.getTargets().contains(permanent.getId())) { - left.add(permanent); - leftLog.add(permanent); - } else if (filterBlockers.match(permanent, defenderId, source, game)) { - right.add(permanent); - rightLog.add(permanent); - } - } - } - - // it could be nice to invoke some graphic indicator of which creature is Left or Right in this spot - StringBuilder sb = new StringBuilder("Left pile of ").append(defender.getLogName()).append(": "); - sb.append(leftLog.stream().map(MageObject::getLogName).collect(Collectors.joining(", "))); - - game.informPlayers(sb.toString()); - - sb = new StringBuilder("Right pile of ").append(defender.getLogName()).append(": "); - sb.append(rightLog.stream().map(MageObject::getLogName).collect(Collectors.joining(", "))); - - game.informPlayers(sb.toString()); - } - } - } - - for (UUID attackers : game.getCombat().getAttackers()) { - Permanent attacker = game.getPermanent(attackers); - if (attacker != null && Objects.equals(attacker.getControllerId(), controller.getId())) { - CombatGroup combatGroup = game.getCombat().findGroup(attacker.getId()); - if (combatGroup != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - Player defender = game.getPlayer(combatGroup.getDefendingPlayerId()); - if (defender != null) { - if (left.isEmpty() && right.isEmpty()) { - // shortcut in case of no labeled blockers available - filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); - } else { - List leftLog = left.stream() - .filter(permanent -> permanent.getControllerId() != null) - .filter(permanent -> permanent.isControlledBy(defender.getId())) - .collect(Collectors.toList()); - List rightLog = right.stream() - .filter(permanent -> permanent.getControllerId() != null) - .filter(permanent -> permanent.isControlledBy(defender.getId())) - .collect(Collectors.toList()); - - - if (controller.choosePile(outcome, attacker.getName() + ": attacking " + defender.getName(), leftLog, rightLog, game)) { - filter.add(Predicates.not(Predicates.or(new AbilityPredicate(FlyingAbility.class), new PermanentReferenceInCollectionPredicate(left, game)))); - game.informPlayers(attacker.getLogName() + ": attacks left (" + defender.getLogName() + ")"); - } else { - filter.add(Predicates.not(Predicates.or(new AbilityPredicate(FlyingAbility.class), new PermanentReferenceInCollectionPredicate(right, game)))); - game.informPlayers(attacker.getLogName() + ": attacks right (" + defender.getLogName() + ")"); - } - } - RestrictionEffect effect = new CantBeBlockedByAllTargetEffect(filter, Duration.EndOfCombat); - effect.setTargetPointer(new FixedTarget(attacker.getId(), game)); - game.addEffect(effect, source); - } - } - } - } - return true; + if (controller == null) { + return false; } - return false; + List left = new ArrayList<>(); + List right = new ArrayList<>(); + + for (UUID defenderId : game.getCombat().getPlayerDefenders(game)) { + Player defender = game.getPlayer(defenderId); + if (defender == null) { + continue; + } + List leftLog = new ArrayList<>(); + List rightLog = new ArrayList<>(); + Target target = new TargetPermanent(0, Integer.MAX_VALUE, filterBlockers, true); + if (!target.canChoose(defenderId, source, game)) { + continue; + } + if (defender.chooseTarget(Outcome.Neutral, target, source, game)) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), defenderId, game)) { + if (target.getTargets().contains(permanent.getId())) { + left.add(permanent); + leftLog.add(permanent); + } else if (filterBlockers.match(permanent, defenderId, source, game)) { + right.add(permanent); + rightLog.add(permanent); + } + } + } + + // it could be nice to invoke some graphic indicator of which creature is Left or Right in this spot + StringBuilder sb = new StringBuilder("Left pile of ").append(defender.getLogName()).append(": "); + sb.append(leftLog.stream().map(MageObject::getLogName).collect(Collectors.joining(", "))); + + game.informPlayers(sb.toString()); + + sb = new StringBuilder("Right pile of ").append(defender.getLogName()).append(": "); + sb.append(rightLog.stream().map(MageObject::getLogName).collect(Collectors.joining(", "))); + + game.informPlayers(sb.toString()); + } + + for (UUID attackers : game.getCombat().getAttackers()) { + Permanent attacker = game.getPermanent(attackers); + if (attacker == null || !Objects.equals(attacker.getControllerId(), controller.getId())) { + continue; + } + CombatGroup combatGroup = game.getCombat().findGroup(attacker.getId()); + if (combatGroup == null) { + continue; + } + FilterCreaturePermanent filter = new FilterCreaturePermanent(); + Player defender = game.getPlayer(combatGroup.getDefendingPlayerId()); + if (defender == null) { + continue; + } + if (left.isEmpty() && right.isEmpty()) { + // shortcut in case of no labeled blockers available + filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); + } else { + List leftLog = left.stream() + .filter(permanent -> permanent.getControllerId() != null) + .filter(permanent -> permanent.isControlledBy(defender.getId())) + .collect(Collectors.toList()); + List rightLog = right.stream() + .filter(permanent -> permanent.getControllerId() != null) + .filter(permanent -> permanent.isControlledBy(defender.getId())) + .collect(Collectors.toList()); + + + if (controller.choosePile(outcome, attacker.getName() + ": attacking " + defender.getName(), leftLog, rightLog, game)) { + filter.add(Predicates.not(Predicates.or(new AbilityPredicate(FlyingAbility.class), new PermanentReferenceInCollectionPredicate(left, game)))); + game.informPlayers(attacker.getLogName() + ": attacks left (" + defender.getLogName() + ")"); + } else { + filter.add(Predicates.not(Predicates.or(new AbilityPredicate(FlyingAbility.class), new PermanentReferenceInCollectionPredicate(right, game)))); + game.informPlayers(attacker.getLogName() + ": attacks right (" + defender.getLogName() + ")"); + } + } + RestrictionEffect effect = new CantBeBlockedByAllTargetEffect(filter, Duration.EndOfCombat); + effect.setTargetPointer(new FixedTarget(attacker.getId(), game)); + game.addEffect(effect, source); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/r/RaidersWake.java b/Mage.Sets/src/mage/cards/r/RaidersWake.java index d69a9914f2b..0feb1e688ca 100644 --- a/Mage.Sets/src/mage/cards/r/RaidersWake.java +++ b/Mage.Sets/src/mage/cards/r/RaidersWake.java @@ -1,13 +1,12 @@ package mage.cards.r; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.DiscardsACardOpponentTriggeredAbility; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.hint.common.RaidHint; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; @@ -27,16 +26,15 @@ public final class RaidersWake extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}"); // Whenever an opponent discards a card, that player loses 2 life. - this.addAbility(new DiscardsACardOpponentTriggeredAbility(new LoseLifeTargetEffect(2), false, SetTargetPointer.PLAYER)); + this.addAbility(new DiscardsACardOpponentTriggeredAbility( + new LoseLifeTargetEffect(2), false, SetTargetPointer.PLAYER + )); // Raid — At the beginning of your end step, if you attacked this turn, target opponent discards a card. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility(new DiscardTargetEffect(1)), RaidCondition.instance, - "At the beginning of your end step, if you attacked this turn, target opponent discards a card."); + Ability ability = new BeginningOfEndStepTriggeredAbility(new DiscardTargetEffect(1)) + .withInterveningIf(RaidCondition.instance); ability.addTarget(new TargetOpponent()); - ability.setAbilityWord(AbilityWord.RAID); - ability.addHint(RaidHint.instance); - this.addAbility(ability, new PlayerAttackedWatcher()); + this.addAbility(ability.setAbilityWord(AbilityWord.RAID).addHint(RaidHint.instance), new PlayerAttackedWatcher()); } private RaidersWake(final RaidersWake card) { diff --git a/Mage.Sets/src/mage/cards/r/RaidingParty.java b/Mage.Sets/src/mage/cards/r/RaidingParty.java index 4284c5b0a1a..21aa94e0f14 100644 --- a/Mage.Sets/src/mage/cards/r/RaidingParty.java +++ b/Mage.Sets/src/mage/cards/r/RaidingParty.java @@ -1,9 +1,6 @@ package mage.cards.r; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -17,9 +14,8 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.FilterStackObject; import mage.filter.FilterPermanent; +import mage.filter.FilterStackObject; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.ColorPredicate; @@ -29,27 +25,29 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.TargetPermanent; -import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; /** - * * @author L_J */ public final class RaidingParty extends CardImpl { - + private static final FilterStackObject filterWhite = new FilterStackObject("white spells or abilities from white sources"); private static final FilterControlledPermanent filterOrc = new FilterControlledPermanent(SubType.ORC, "an Orc"); - + static { filterWhite.add(new ColorPredicate(ObjectColor.WHITE)); } public RaidingParty(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); // Raiding Party can't be the target of white spells or abilities from white sources. this.addAbility(new SimpleStaticAbility(new CantBeTargetedSourceEffect(filterWhite, Duration.WhileOnBattlefield))); - + // Sacrifice an Orc: Each player may tap any number of untapped white creatures they control. For each creature tapped this way, that player chooses up to two Plains. Then destroy all Plains that weren't chosen this way by any player. this.addAbility(new SimpleActivatedAbility(new RaidingPartyEffect(), new SacrificeTargetCost(filterOrc))); } @@ -66,7 +64,7 @@ public final class RaidingParty extends CardImpl { class RaidingPartyEffect extends OneShotEffect { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped white creatures"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("untapped white creatures"); private static final FilterPermanent filter2 = new FilterPermanent("Plains"); static { @@ -99,7 +97,7 @@ class RaidingPartyEffect extends OneShotEffect { if (player != null) { int countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).size(); int tappedCount = 0; - Target untappedCreatureTarget = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true); + Target untappedCreatureTarget = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); if (player.choose(Outcome.Benefit, untappedCreatureTarget, source, game)) { tappedCount = untappedCreatureTarget.getTargets().size(); for (UUID creatureId : untappedCreatureTarget.getTargets()) { diff --git a/Mage.Sets/src/mage/cards/r/RakaSanctuary.java b/Mage.Sets/src/mage/cards/r/RakaSanctuary.java index 5e06e5d7a2b..ebaa5bf0a34 100644 --- a/Mage.Sets/src/mage/cards/r/RakaSanctuary.java +++ b/Mage.Sets/src/mage/cards/r/RakaSanctuary.java @@ -1,18 +1,17 @@ - package mage.cards.r; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.common.SanctuaryInterveningIfTriggeredAbility; +import mage.abilities.common.SanctuaryTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class RakaSanctuary extends CardImpl { @@ -21,10 +20,10 @@ public final class RakaSanctuary extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); // At the beginning of your upkeep, if you control a white or blue permanent, Raka Sanctuary deals 1 damage to target creature. If you control a white permanent and a blue permanent, Raka Sanctuary deals 3 damage to that creature instead. - Ability ability = new SanctuaryInterveningIfTriggeredAbility( - new DamageTargetEffect(1), new DamageTargetEffect(3), ObjectColor.WHITE, ObjectColor.BLUE, - "At the beginning of your upkeep, if you control a white or blue permanent, Raka Sanctuary deals 1 damage to target creature. " - + "If you control a white permanent and a blue permanent, Raka Sanctuary deals 3 damage to that creature instead." + Ability ability = new SanctuaryTriggeredAbility( + new DamageTargetEffect(1), new DamageTargetEffect(3), + ObjectColor.WHITE, ObjectColor.BLUE, "{this} deals 1 damage to target creature. " + + "If you control a white permanent and a blue permanent, {this} deals 3 damage to that creature instead." ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/r/RakdosFirewheeler.java b/Mage.Sets/src/mage/cards/r/RakdosFirewheeler.java index 025ef05376f..e9db64acfe7 100644 --- a/Mage.Sets/src/mage/cards/r/RakdosFirewheeler.java +++ b/Mage.Sets/src/mage/cards/r/RakdosFirewheeler.java @@ -9,7 +9,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; import mage.target.common.TargetCreatureOrPlaneswalker; import mage.target.common.TargetOpponent; @@ -34,7 +33,7 @@ public final class RakdosFirewheeler extends CardImpl { effect.setText("it deals 2 damage to target opponent and 2 damage to up to one target creature or planeswalker"); Ability ability = new EntersBattlefieldTriggeredAbility(effect, false); ability.addTarget(new TargetOpponent()); - ability.addTarget(new TargetCreatureOrPlaneswalker(0, 1, new FilterCreatureOrPlaneswalkerPermanent(), false)); + ability.addTarget(new TargetCreatureOrPlaneswalker(0, 1)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RakdosRoustabout.java b/Mage.Sets/src/mage/cards/r/RakdosRoustabout.java index c439fbb8d04..74fc73e2e15 100644 --- a/Mage.Sets/src/mage/cards/r/RakdosRoustabout.java +++ b/Mage.Sets/src/mage/cards/r/RakdosRoustabout.java @@ -74,6 +74,6 @@ class RakdosRoustaboutAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever {this} becomes blocked, it deals 1 damage to the player or planeswalker it's attacking"; + return "Whenever {this} becomes blocked, it deals 1 damage to the player or planeswalker it's attacking."; } } diff --git a/Mage.Sets/src/mage/cards/r/RakeclawGargantuan.java b/Mage.Sets/src/mage/cards/r/RakeclawGargantuan.java index 2d6361b7812..eef9b352c95 100644 --- a/Mage.Sets/src/mage/cards/r/RakeclawGargantuan.java +++ b/Mage.Sets/src/mage/cards/r/RakeclawGargantuan.java @@ -16,6 +16,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class RakeclawGargantuan extends CardImpl { SimpleActivatedAbility ability = new SimpleActivatedAbility( new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{1}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RallyManeuver.java b/Mage.Sets/src/mage/cards/r/RallyManeuver.java index fc7e7fbe24e..27f46357750 100644 --- a/Mage.Sets/src/mage/cards/r/RallyManeuver.java +++ b/Mage.Sets/src/mage/cards/r/RallyManeuver.java @@ -1,7 +1,5 @@ package mage.cards.r; -import java.util.UUID; - import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.FirstStrikeAbility; @@ -12,11 +10,13 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.other.AnotherTargetPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.SecondTargetPointer; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class RallyManeuver extends CardImpl { @@ -31,25 +31,22 @@ public final class RallyManeuver extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); // Target creature gets +2/+0 and gains first strike until end of turn. Up to one other target creature gets +0/+2 and gains lifelink until end of turn. - TargetCreaturePermanent target = new TargetCreaturePermanent(); - target.setTargetTag(1); - this.getSpellAbility().addTarget(target.withChooseHint("+2/+0 and first strike")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().setTargetTag(1).withChooseHint("+2/+0 and first strike")); this.getSpellAbility().addEffect(new BoostTargetEffect(2, 0).setText("Target creature gets +2/+0")); this.getSpellAbility().addEffect(new GainAbilityTargetEffect( - FirstStrikeAbility.getInstance(), Duration.EndOfTurn, "and gains first strike until end of turn" + FirstStrikeAbility.getInstance(), Duration.EndOfTurn, + "and gains first strike until end of turn" )); - - target = new TargetCreaturePermanent(0, 1, filter2, false); - target.setTargetTag(2); - this.getSpellAbility().addTarget(target.withChooseHint("+0/+2 and lifelink")); + this.getSpellAbility().addTarget(new TargetPermanent(0, 1, filter2) + .setTargetTag(2).withChooseHint("+0/+2 and lifelink")); this.getSpellAbility().addEffect(new BoostTargetEffect(0, 2) .setText("Up to one other target creature gets +0/+2") .setTargetPointer(new SecondTargetPointer()) ); - this.getSpellAbility().addEffect( - new GainAbilityTargetEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn, "and gains lifelink until end of turn") - .setTargetPointer(new SecondTargetPointer()) - ); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + LifelinkAbility.getInstance(), Duration.EndOfTurn, + "and gains lifelink until end of turn" + ).setTargetPointer(new SecondTargetPointer())); } private RallyManeuver(final RallyManeuver card) { diff --git a/Mage.Sets/src/mage/cards/r/RallyTheMonastery.java b/Mage.Sets/src/mage/cards/r/RallyTheMonastery.java index 7867c2c0c48..dae91cbf035 100644 --- a/Mage.Sets/src/mage/cards/r/RallyTheMonastery.java +++ b/Mage.Sets/src/mage/cards/r/RallyTheMonastery.java @@ -1,7 +1,5 @@ package mage.cards.r; -import java.util.UUID; - import mage.abilities.Mode; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.CastAnotherSpellThisTurnCondition; @@ -14,13 +12,14 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.Zone; -import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.game.permanent.token.MonasteryMentorToken; import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** * @author balazskristof */ @@ -44,16 +43,16 @@ public final class RallyTheMonastery extends CardImpl { // Choose one — this.getSpellAbility().getModes().setMinModes(1); this.getSpellAbility().getModes().setMaxModes(1); + // • Create two 1/1 white Monk creature tokens with prowess. this.getSpellAbility().addEffect(new CreateTokenEffect(new MonasteryMentorToken(), 2)); + // • Up to two target creatures you control each get +2/+2 until end of turn. - Mode mode = new Mode(new BoostTargetEffect(2, 2)); - mode.addTarget(new TargetControlledCreaturePermanent(0, 2, StaticFilters.FILTER_CONTROLLED_CREATURES, false)); - this.getSpellAbility().getModes().addMode(mode); + this.getSpellAbility().getModes().addMode(new Mode(new BoostTargetEffect(2, 2)) + .addTarget(new TargetControlledCreaturePermanent(0, 2))); + // • Destroy target creature with power 4 or greater. - Mode mode2 = new Mode(new DestroyTargetEffect()); - mode2.addTarget(new TargetPermanent(filter)); - this.getSpellAbility().getModes().addMode(mode2); + this.getSpellAbility().getModes().addMode(new Mode(new DestroyTargetEffect()).addTarget(new TargetPermanent(filter))); } private RallyTheMonastery(final RallyTheMonastery card) { @@ -65,4 +64,3 @@ public final class RallyTheMonastery extends CardImpl { return new RallyTheMonastery(this); } } - diff --git a/Mage.Sets/src/mage/cards/r/RalsStaticaster.java b/Mage.Sets/src/mage/cards/r/RalsStaticaster.java index d05013c785b..3745ab51b15 100644 --- a/Mage.Sets/src/mage/cards/r/RalsStaticaster.java +++ b/Mage.Sets/src/mage/cards/r/RalsStaticaster.java @@ -1,35 +1,30 @@ package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.constants.SubType; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.TargetController; -import mage.filter.FilterPermanent; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPlaneswalkerPermanent; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class RalsStaticaster extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("a Ral planeswalker"); - - static { - filter.add(TargetController.YOU.getControllerPredicate()); - filter.add(CardType.PLANESWALKER.getPredicate()); - filter.add(SubType.RAL.getPredicate()); - } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPlaneswalkerPermanent(SubType.RAL, "you control a Ral planeswalker") + ); public RalsStaticaster(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{R}"); @@ -43,14 +38,9 @@ public final class RalsStaticaster extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Whenever Ral's Staticaster attacks, if you control a Ral planeswalker, Ral's Staticaster gets +1/+0 for each card in your hand until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new BoostSourceEffect( - CardsInControllerHandCount.ANY, StaticValue.get(0), - Duration.EndOfTurn), false), - new PermanentsOnTheBattlefieldCondition(filter), - "Whenever {this} attacks, if you control a Ral planeswalker, " - + "{this} gets +1/+0 for each card in your hand until end of turn." - )); + this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect( + CardsInControllerHandCount.ANY, StaticValue.get(0), Duration.EndOfTurn + ).setText("this creature gets +1/+0 for each card in your hand until end of turn")).withInterveningIf(condition)); } private RalsStaticaster(final RalsStaticaster card) { diff --git a/Mage.Sets/src/mage/cards/r/RamThrough.java b/Mage.Sets/src/mage/cards/r/RamThrough.java index 0dbccc0a842..582f0ccb988 100644 --- a/Mage.Sets/src/mage/cards/r/RamThrough.java +++ b/Mage.Sets/src/mage/cards/r/RamThrough.java @@ -11,11 +11,14 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author TheElk801 */ @@ -27,7 +30,7 @@ public final class RamThrough extends CardImpl { // Target creature you control deals damage equal to its power to target creature you don't control. If the creature you control has trample, excess damage is dealt to that creature's controller instead. this.getSpellAbility().addEffect(new RamThroughEffect()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); } private RamThrough(final RamThrough card) { diff --git a/Mage.Sets/src/mage/cards/r/RampagingRaptor.java b/Mage.Sets/src/mage/cards/r/RampagingRaptor.java index bf4ee11f65b..4f69d51409a 100644 --- a/Mage.Sets/src/mage/cards/r/RampagingRaptor.java +++ b/Mage.Sets/src/mage/cards/r/RampagingRaptor.java @@ -1,7 +1,8 @@ package mage.cards.r; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToOpponentTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.SavedDamageValue; @@ -14,16 +15,15 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.filter.predicate.permanent.ProtectorIdPredicate; import mage.game.Game; -import mage.game.events.DamagedEvent; -import mage.game.events.GameEvent; import mage.players.Player; import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; +import mage.target.targetpointer.FirstTargetPointer; import java.util.UUID; @@ -51,7 +51,10 @@ public final class RampagingRaptor extends CardImpl { )); // Whenever Rampaging Raptor deals combat damage to an opponent, it deals that much damage to target planeswalker that player controls or battle that player protects. - this.addAbility(new RampagingRaptorTriggeredAbility()); + Ability ability = new DealsDamageToOpponentTriggeredAbility(new DamageTargetEffect(SavedDamageValue.MUCH) + .withTargetDescription("target planeswalker that player controls or battle that player protects"), false, true, true); + ability.setTargetAdjuster(RampagingRaptorTargetAdjuster.instance); + this.addAbility(ability); } private RampagingRaptor(final RampagingRaptor card) { @@ -64,33 +67,17 @@ public final class RampagingRaptor extends CardImpl { } } -class RampagingRaptorTriggeredAbility extends TriggeredAbilityImpl { - - RampagingRaptorTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(SavedDamageValue.MUCH), false); - } - - private RampagingRaptorTriggeredAbility(final RampagingRaptorTriggeredAbility ability) { - super(ability); - } +enum RampagingRaptorTargetAdjuster implements TargetAdjuster { + instance; @Override - public RampagingRaptorTriggeredAbility copy() { - return new RampagingRaptorTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Player opponent = game.getPlayer(event.getPlayerId()); - if (opponent == null - || !event.getSourceId().equals(this.getSourceId()) - || !((DamagedEvent) event).isCombatDamage()) { - return false; + public void adjustTargets(Ability ability, Game game) { + UUID opponentId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability); + Player opponent = game.getPlayer(opponentId); + ability.getTargets().clear(); + ability.getAllEffects().setTargetPointer(new FirstTargetPointer()); + if (opponent == null) { + return; } FilterPermanent filter = new FilterPermanent( "planeswalker " + opponent.getLogName() + " controls " + @@ -106,15 +93,6 @@ class RampagingRaptorTriggeredAbility extends TriggeredAbilityImpl { new ProtectorIdPredicate(opponent.getId()) ) )); - this.getEffects().setValue("damage", event.getAmount()); - this.getTargets().clear(); - this.addTarget(new TargetPermanent(filter)); - return true; - } - - @Override - public String getRule() { - return "Whenever {this} deals combat damage to an opponent, it deals that much damage " + - "to target planeswalker that player controls or battle that player protects."; + ability.addTarget(new TargetPermanent(filter)); } } diff --git a/Mage.Sets/src/mage/cards/r/RampagingWarMammoth.java b/Mage.Sets/src/mage/cards/r/RampagingWarMammoth.java index 36302890eb2..af293b7cbfc 100644 --- a/Mage.Sets/src/mage/cards/r/RampagingWarMammoth.java +++ b/Mage.Sets/src/mage/cards/r/RampagingWarMammoth.java @@ -1,22 +1,21 @@ package mage.cards.r; import mage.MageInt; -import mage.abilities.common.ZoneChangeTriggeredAbility; +import mage.abilities.Ability; +import mage.abilities.common.CycleTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.EffectKeyValue; import mage.abilities.effects.common.DestroyTargetEffect; -import mage.abilities.hint.StaticHint; import mage.abilities.keyword.CyclingAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.stack.StackObject; -import mage.target.common.TargetArtifactPermanent; -import mage.util.CardUtil; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterArtifactPermanent; +import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetsCountAdjuster; import java.util.UUID; @@ -25,6 +24,8 @@ import java.util.UUID; */ public final class RampagingWarMammoth extends CardImpl { + private static final FilterPermanent filter = new FilterArtifactPermanent("up to X target artifacts"); + public RampagingWarMammoth(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}{R}"); @@ -39,7 +40,10 @@ public final class RampagingWarMammoth extends CardImpl { this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{X}{2}{R}"))); // When you cycle Rampaging War Mammoth, destroy up to X target artifacts. - this.addAbility(new RampagingWarMammothTriggeredAbility()); + Ability ability = new CycleTriggeredAbility(new DestroyTargetEffect()); + ability.addTarget(new TargetPermanent(0,1, filter)); + ability.setTargetAdjuster(new TargetsCountAdjuster(new EffectKeyValue("cycleXValue"))); + this.addAbility(ability); } private RampagingWarMammoth(final RampagingWarMammoth card) { @@ -51,56 +55,3 @@ public final class RampagingWarMammoth extends CardImpl { return new RampagingWarMammoth(this); } } - -class RampagingWarMammothTriggeredAbility extends ZoneChangeTriggeredAbility { - - RampagingWarMammothTriggeredAbility() { - super(Zone.ALL, null, "", false); - } - - private RampagingWarMammothTriggeredAbility(RampagingWarMammothTriggeredAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (!event.getSourceId().equals(this.getSourceId())) { - return false; - } - StackObject object = game.getStack().getStackObject(event.getSourceId()); - if (object == null || !(object.getStackAbility() instanceof CyclingAbility)) { - return false; - } - - CyclingAbility cyclingAbility = (CyclingAbility) object.getStackAbility(); - // If X is 0, or cycling from another ability that does not have {X} in cost, - // this should trigger (but do nothing). - int xValue = CardUtil.getSourceCostsTag(game, cyclingAbility, "X", 0); - - this.getEffects().clear(); - this.getTargets().clear(); - - this.addEffect(new DestroyTargetEffect()); - // Target up to X artifacts - this.addTarget(new TargetArtifactPermanent(0, xValue)); - this.getHints().clear(); - this.addHint(new StaticHint("X = " + xValue)); - - return true; - } - - @Override - public RampagingWarMammothTriggeredAbility copy() { - return new RampagingWarMammothTriggeredAbility(this); - } - - @Override - public String getRule() { - return "When you cycle {this}, destroy up to X target artifacts."; - } -} diff --git a/Mage.Sets/src/mage/cards/r/RamsesOverdark.java b/Mage.Sets/src/mage/cards/r/RamsesOverdark.java index 93a86234a2a..458b4a8f126 100644 --- a/Mage.Sets/src/mage/cards/r/RamsesOverdark.java +++ b/Mage.Sets/src/mage/cards/r/RamsesOverdark.java @@ -15,6 +15,7 @@ import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.EnchantedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class RamsesOverdark extends CardImpl { // {tap}: Destroy target enchanted creature. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RasaadYnBashir.java b/Mage.Sets/src/mage/cards/r/RasaadYnBashir.java index 1eb28c1e9d6..1aafde868bd 100644 --- a/Mage.Sets/src/mage/cards/r/RasaadYnBashir.java +++ b/Mage.Sets/src/mage/cards/r/RasaadYnBashir.java @@ -6,7 +6,6 @@ import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.ChooseABackgroundAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.HaveInitiativeCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.ruleModifying.CombatDamageByToughnessControlledEffect; @@ -42,11 +41,8 @@ public final class RasaadYnBashir extends CardImpl { this.addAbility(new SimpleStaticAbility(new CombatDamageByToughnessControlledEffect())); // Whenever Rasaad yn Bashir attacks, if you have the initiative, double the toughness of each creature you control until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new RasaadYnBashirEffect()), - HaveInitiativeCondition.instance, "Whenever {this} attacks, if you have the initiative, " + - "double the toughness of each creature you control until end of turn." - ).addHint(InitiativeHint.instance)); + this.addAbility(new AttacksTriggeredAbility(new RasaadYnBashirEffect()) + .withInterveningIf(HaveInitiativeCondition.instance).addHint(InitiativeHint.instance)); // Choose a Background this.addAbility(ChooseABackgroundAbility.getInstance()); @@ -66,6 +62,7 @@ class RasaadYnBashirEffect extends OneShotEffect { RasaadYnBashirEffect() { super(Outcome.Benefit); + staticText = "double the toughness of each creature you control until end of turn"; } private RasaadYnBashirEffect(final RasaadYnBashirEffect effect) { diff --git a/Mage.Sets/src/mage/cards/r/RashidaScalebane.java b/Mage.Sets/src/mage/cards/r/RashidaScalebane.java index 9e93758cf35..aa4bdce442d 100644 --- a/Mage.Sets/src/mage/cards/r/RashidaScalebane.java +++ b/Mage.Sets/src/mage/cards/r/RashidaScalebane.java @@ -20,6 +20,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.AttackingPredicate; import mage.filter.predicate.permanent.BlockingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -48,7 +49,7 @@ public final class RashidaScalebane extends CardImpl { Effect effect = new GainLifeEffect(TargetPermanentPowerCount.instance); effect.setText("You gain life equal to its power"); ability.addEffect(effect); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RasputinDreamweaver.java b/Mage.Sets/src/mage/cards/r/RasputinDreamweaver.java index ae03012f912..d499b452b17 100644 --- a/Mage.Sets/src/mage/cards/r/RasputinDreamweaver.java +++ b/Mage.Sets/src/mage/cards/r/RasputinDreamweaver.java @@ -1,23 +1,18 @@ - package mage.cards.r; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.Mana; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.CantHaveMoreThanAmountCountersSourceAbility; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.common.RemoveCountersSourceCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.CountersSourceCount; import mage.abilities.effects.common.PreventDamageToSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.mana.SimpleManaAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -28,6 +23,10 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.watchers.Watcher; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** * @author emerald000 */ @@ -43,23 +42,29 @@ public final class RasputinDreamweaver extends CardImpl { this.toughness = new MageInt(1); // Rasputin Dreamweaver enters the battlefield with seven dream counters on it. - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.DREAM.createInstance(7)), "with seven dream counters on it")); + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.DREAM.createInstance(7)), + "with seven dream counters on it" + )); // Remove a dream counter from Rasputin: Add {C}. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.ColorlessMana(1), + this.addAbility(new SimpleManaAbility( + Zone.BATTLEFIELD, Mana.ColorlessMana(1), new RemoveCountersSourceCost(CounterType.DREAM.createInstance()), - new CountersSourceCount(CounterType.DREAM))); + new CountersSourceCount(CounterType.DREAM) + )); // Remove a dream counter from Rasputin: Prevent the next 1 damage that would be dealt to Rasputin this turn. - this.addAbility(new SimpleActivatedAbility(new PreventDamageToSourceEffect(Duration.EndOfTurn, 1), new RemoveCountersSourceCost(CounterType.DREAM.createInstance()))); + this.addAbility(new SimpleActivatedAbility( + new PreventDamageToSourceEffect(Duration.EndOfTurn, 1), + new RemoveCountersSourceCost(CounterType.DREAM.createInstance()) + )); // At the beginning of your upkeep, if Rasputin started the turn untapped, put a dream counter on it. - this.addAbility( - new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.DREAM.createInstance())), - RasputinDreamweaverStartedUntappedCondition.instance, - "At the beginning of your upkeep, if {this} started the turn untapped, put a dream counter on it."), - new RasputinDreamweaverStartedUntappedWatcher()); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new AddCountersSourceEffect(CounterType.DREAM.createInstance()) + .setText("put a dream counter on it") + ).withInterveningIf(RasputinDreamweaverCondition.instance), new RasputinDreamweaverWatcher()); // Rasputin can't have more than seven dream counters on it. this.addAbility(new CantHaveMoreThanAmountCountersSourceAbility(CounterType.DREAM, 7)); @@ -75,17 +80,12 @@ public final class RasputinDreamweaver extends CardImpl { } } -enum RasputinDreamweaverStartedUntappedCondition implements Condition { - +enum RasputinDreamweaverCondition implements Condition { instance; @Override public boolean apply(Game game, Ability source) { - RasputinDreamweaverStartedUntappedWatcher watcher = game.getState().getWatcher(RasputinDreamweaverStartedUntappedWatcher.class); - if (watcher != null) { - return watcher.startedUntapped(source.getSourceId()); - } - return false; + return game.getState().getWatcher(RasputinDreamweaverWatcher.class).startedUntapped(source.getSourceId()); } @Override @@ -94,9 +94,9 @@ enum RasputinDreamweaverStartedUntappedCondition implements Condition { } } -class RasputinDreamweaverStartedUntappedWatcher extends Watcher { +class RasputinDreamweaverWatcher extends Watcher { - private static final FilterPermanent filter = new FilterPermanent("Untapped permanents"); + private static final FilterPermanent filter = new FilterPermanent(); static { filter.add(TappedPredicate.UNTAPPED); @@ -104,7 +104,7 @@ class RasputinDreamweaverStartedUntappedWatcher extends Watcher { private final Set startedUntapped = new HashSet<>(0); - RasputinDreamweaverStartedUntappedWatcher() { + RasputinDreamweaverWatcher() { super(WatcherScope.GAME); } diff --git a/Mage.Sets/src/mage/cards/r/RathiAssassin.java b/Mage.Sets/src/mage/cards/r/RathiAssassin.java index 7e5ae73b63b..6f70b089eeb 100644 --- a/Mage.Sets/src/mage/cards/r/RathiAssassin.java +++ b/Mage.Sets/src/mage/cards/r/RathiAssassin.java @@ -23,6 +23,7 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCreaturePermanent; @@ -55,7 +56,7 @@ public final class RathiAssassin extends CardImpl { // {1}{B}{B}, {T}: Destroy target tapped nonblack creature. Ability destroyAbility = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{1}{B}{B}")); destroyAbility.addCost(new TapSourceCost()); - destroyAbility.addTarget(new TargetCreaturePermanent(destroyFilter)); + destroyAbility.addTarget(new TargetPermanent(destroyFilter)); this.addAbility(destroyAbility); // {3}, {T}: Search your library for a Mercenary permanent card with converted mana cost 3 or less and put it onto the battlefield. Then shuffle your library. diff --git a/Mage.Sets/src/mage/cards/r/Rattlechains.java b/Mage.Sets/src/mage/cards/r/Rattlechains.java index d26b1938ae8..5d12df82102 100644 --- a/Mage.Sets/src/mage/cards/r/Rattlechains.java +++ b/Mage.Sets/src/mage/cards/r/Rattlechains.java @@ -19,6 +19,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -49,7 +50,7 @@ public final class Rattlechains extends CardImpl { // When Rattlechains enters the battlefield, target spirit gains hexproof until end of turn. Ability ability = new EntersBattlefieldTriggeredAbility(new GainAbilityTargetEffect(HexproofAbility.getInstance(), Duration.EndOfTurn), false); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // You may cast Spirit spells as though they had flash. diff --git a/Mage.Sets/src/mage/cards/r/RavagingBlaze.java b/Mage.Sets/src/mage/cards/r/RavagingBlaze.java index 40c11a6cc3f..aa0a718d3ee 100644 --- a/Mage.Sets/src/mage/cards/r/RavagingBlaze.java +++ b/Mage.Sets/src/mage/cards/r/RavagingBlaze.java @@ -1,7 +1,6 @@ package mage.cards.r; -import java.util.UUID; import mage.abilities.condition.common.SpellMasteryCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.dynamicvalue.common.GetXValue; @@ -12,6 +11,8 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * * @author LevelX2 @@ -26,7 +27,7 @@ public final class RavagingBlaze extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Spell mastery — If there are two or more instant and/or sorcery cards in your graveyard, Ravaging Blaze also deals X damage to that creature's controller. this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new DamageTargetControllerEffect(GetXValue.instance), - SpellMasteryCondition.instance, "
Spell mastery — If there are two or more instant and/or sorcery cards in your graveyard, Ravaging Blaze also deals X damage to that creature's controller.")); + SpellMasteryCondition.instance, "
Spell mastery — If there are two or more instant and/or sorcery cards in your graveyard, {this} also deals X damage to that creature's controller.")); } private RavagingBlaze(final RavagingBlaze card) { diff --git a/Mage.Sets/src/mage/cards/r/RavenloftAdventurer.java b/Mage.Sets/src/mage/cards/r/RavenloftAdventurer.java index 61630d1b877..089f9f62d12 100644 --- a/Mage.Sets/src/mage/cards/r/RavenloftAdventurer.java +++ b/Mage.Sets/src/mage/cards/r/RavenloftAdventurer.java @@ -6,7 +6,6 @@ import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.CompletedDungeonCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.TakeTheInitiativeEffect; @@ -46,12 +45,9 @@ public final class RavenloftAdventurer extends CardImpl { this.addAbility(new SimpleStaticAbility(new RavenloftAdventurerReplacementEffect())); // Whenever Ravenloft Adventurer attacks, if you've completed a dungeon, defending player loses 1 life for each card they own in exile with a hit counter on it. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility( - new RavenloftAdventurerLifeEffect(), false, "", SetTargetPointer.PLAYER - ), CompletedDungeonCondition.instance, "Whenever {this} attacks, if you've completed a dungeon, " + - "defending player loses 1 life for each card they own in exile with a hit counter on it." - ).addHint(CompletedDungeonCondition.getHint()), new CompletedDungeonWatcher()); + this.addAbility(new AttacksTriggeredAbility( + new RavenloftAdventurerLifeEffect(), false, "", SetTargetPointer.PLAYER + ).withInterveningIf(CompletedDungeonCondition.instance).addHint(CompletedDungeonCondition.getHint()), new CompletedDungeonWatcher()); } private RavenloftAdventurer(final RavenloftAdventurer card) { @@ -108,6 +104,7 @@ class RavenloftAdventurerLifeEffect extends OneShotEffect { RavenloftAdventurerLifeEffect() { super(Outcome.Benefit); + staticText = "defending player loses 1 life for each card they own in exile with a hit counter on it"; } private RavenloftAdventurerLifeEffect(final RavenloftAdventurerLifeEffect effect) { diff --git a/Mage.Sets/src/mage/cards/r/RavenousChupacabra.java b/Mage.Sets/src/mage/cards/r/RavenousChupacabra.java index 32fad1fc866..b48c7c2bfd0 100644 --- a/Mage.Sets/src/mage/cards/r/RavenousChupacabra.java +++ b/Mage.Sets/src/mage/cards/r/RavenousChupacabra.java @@ -11,8 +11,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author L_J @@ -28,7 +31,7 @@ public final class RavenousChupacabra extends CardImpl { // When Ravenous Chupacabra enters the battlefield, destroy target creature an opponent controls. Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RavenousGigantotherium.java b/Mage.Sets/src/mage/cards/r/RavenousGigantotherium.java index eeaacab7a2b..1e877367a4f 100644 --- a/Mage.Sets/src/mage/cards/r/RavenousGigantotherium.java +++ b/Mage.Sets/src/mage/cards/r/RavenousGigantotherium.java @@ -3,6 +3,8 @@ package mage.cards.r; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageMultiEffect; import mage.abilities.keyword.DevourAbility; @@ -12,10 +14,10 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.Target; import mage.target.common.TargetCreaturePermanentAmount; +import mage.util.CardUtil; import java.util.Collection; import java.util.List; @@ -39,7 +41,11 @@ public final class RavenousGigantotherium extends CardImpl { this.addAbility(new DevourAbility(3)); // When Ravenous Gigantotherium enters the battlefield, it deals X damage divided as you choose among up to X target creatures, where X is its power. Each of those creatures deals damage equal to its power to Ravenous Gigantotherium. - this.addAbility(new RavenousGigantotheriumAbility()); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageMultiEffect()); + ability.addEffect(new RavenousGigantotheriumEffect()); + ability.addTarget(new TargetCreaturePermanentAmount(RavenousGigantotheriumAmount.instance) + .withTargetName("up to X target creatures, where X is its power")); + this.addAbility(ability); } private RavenousGigantotherium(final RavenousGigantotherium card) { @@ -52,47 +58,28 @@ public final class RavenousGigantotherium extends CardImpl { } } -class RavenousGigantotheriumAbility extends EntersBattlefieldTriggeredAbility { +enum RavenousGigantotheriumAmount implements DynamicValue { + instance; - RavenousGigantotheriumAbility() { - super(null, false); - } - - private RavenousGigantotheriumAbility(final RavenousGigantotheriumAbility ability) { - super(ability); + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return CardUtil.getEffectValueFromAbility(sourceAbility, "permanentEnteredBattlefield", Permanent.class) + .map(permanent -> permanent.getPower().getValue()).orElse(0); } @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (!super.checkTrigger(event, game)) { - return false; - } - Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId()); - if (permanent == null) { - return false; - } - int power = Math.max(permanent.getPower().getValue(), 0); - this.getEffects().clear(); - this.addEffect(new DamageMultiEffect()); - this.addEffect(new RavenousGigantotheriumEffect()); - this.getTargets().clear(); - if (power < 1) { - return true; - } - this.addTarget(new TargetCreaturePermanentAmount(power, 0, power)); - return true; + public DynamicValue copy() { + return instance; } @Override - public String getRule() { - return "When {this} enters, it deals X damage " + - "divided as you choose among up to X target creatures, where X is its power. " + - "Each of those creatures deals damage equal to its power to {this}."; + public String getMessage() { + return "its power"; } @Override - public RavenousGigantotheriumAbility copy() { - return new RavenousGigantotheriumAbility(this); + public String toString() { + return "X"; } } @@ -100,6 +87,7 @@ class RavenousGigantotheriumEffect extends OneShotEffect { RavenousGigantotheriumEffect() { super(Outcome.Benefit); + this.setText("Each of those creatures deals damage equal to its power to {this}."); } private RavenousGigantotheriumEffect(final RavenousGigantotheriumEffect effect) { diff --git a/Mage.Sets/src/mage/cards/r/RavenousTyrannosaurus.java b/Mage.Sets/src/mage/cards/r/RavenousTyrannosaurus.java index 64b0cdab0ef..7460dc4fbfc 100644 --- a/Mage.Sets/src/mage/cards/r/RavenousTyrannosaurus.java +++ b/Mage.Sets/src/mage/cards/r/RavenousTyrannosaurus.java @@ -12,12 +12,11 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; /** - * * @author notgreat */ public final class RavenousTyrannosaurus extends CardImpl { @@ -27,6 +26,7 @@ public final class RavenousTyrannosaurus extends CardImpl { static { filter.add(AnotherPredicate.instance); } + public RavenousTyrannosaurus(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}{G}"); this.subtype.add(SubType.DINOSAUR); @@ -39,7 +39,7 @@ public final class RavenousTyrannosaurus extends CardImpl { // Whenever Ravenous Tyrannosaurus attacks, it deals damage equal to its power to up to one other target creature. Excess damage is dealt to that creature's controller instead. Ability ability = new AttacksTriggeredAbility(new DamageWithExcessEffect(SourcePermanentPowerValue.NOT_NEGATIVE) .setText("it deals damage equal to its power to up to one other target creature. Excess damage is dealt to that creature's controller instead.")); - ability.addTarget(new TargetCreaturePermanent(0, 1, filter, false)); + ability.addTarget(new TargetPermanent(0, 1, filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RavingVisionary.java b/Mage.Sets/src/mage/cards/r/RavingVisionary.java index 5703d4286b3..2ccbbb7cf33 100644 --- a/Mage.Sets/src/mage/cards/r/RavingVisionary.java +++ b/Mage.Sets/src/mage/cards/r/RavingVisionary.java @@ -15,7 +15,6 @@ import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import java.util.UUID; @@ -41,8 +40,7 @@ public final class RavingVisionary extends CardImpl { // Delirium — {2}{U}, {T}: Draw a card. Activate only if there are four or more card types among cards in your graveyard. ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), - new ManaCostsImpl<>("{2}{U}"), DeliriumCondition.instance + new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{2}{U}"), DeliriumCondition.instance ); ability.addCost(new TapSourceCost()); this.addAbility(ability.addHint(CardTypesInGraveyardCount.YOU.getHint()).setAbilityWord(AbilityWord.DELIRIUM)); diff --git a/Mage.Sets/src/mage/cards/r/RayOfCommand.java b/Mage.Sets/src/mage/cards/r/RayOfCommand.java index dc57a6e4f06..def359df27c 100644 --- a/Mage.Sets/src/mage/cards/r/RayOfCommand.java +++ b/Mage.Sets/src/mage/cards/r/RayOfCommand.java @@ -16,8 +16,11 @@ import mage.constants.Duration; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -32,7 +35,7 @@ public final class RayOfCommand extends CardImpl { this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfTurn).setText("and gain control of it until end of turn")); this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn).setText("that creature gains haste until end of turn")); this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new RayOfCommandDelayedTriggeredAbility(), true)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); } private RayOfCommand(final RayOfCommand card) { diff --git a/Mage.Sets/src/mage/cards/r/RayOfFrost.java b/Mage.Sets/src/mage/cards/r/RayOfFrost.java index 1fc0da9b8cb..1f5773ee892 100644 --- a/Mage.Sets/src/mage/cards/r/RayOfFrost.java +++ b/Mage.Sets/src/mage/cards/r/RayOfFrost.java @@ -1,32 +1,44 @@ package mage.cards.r; -import java.util.UUID; - +import mage.ObjectColor; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.condition.common.AttachedToMatchesFilterCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.DontUntapInControllersUntapStepEnchantedEffect; import mage.abilities.effects.common.TapEnchantedEffect; -import mage.constants.*; -import mage.abilities.keyword.FlashAbility; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.common.TargetCreaturePermanent; -import mage.abilities.Ability; -import mage.abilities.effects.common.AttachEffect; -import mage.target.TargetPermanent; +import mage.abilities.effects.common.continuous.LoseAllAbilitiesAttachedEffect; import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlashAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; /** - * * @author weirddan455 */ public final class RayOfFrost extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent("enchanted creature is red"); + + static { + filter.add(new ColorPredicate(ObjectColor.RED)); + } + + private static final Condition condition = new AttachedToMatchesFilterCondition(filter); + public RayOfFrost(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); @@ -43,14 +55,15 @@ public final class RayOfFrost extends CardImpl { this.addAbility(ability); // When Ray of Frost enters the battlefield, if enchanted creature is red, tap it. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new TapEnchantedEffect()), - RayOfFrostCondition.instance, - "When {this} enters, if enchanted creature is red, tap it." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new TapEnchantedEffect().setText("tap it") + ).withInterveningIf(condition)); // As long as enchanted creature is red, it loses all abilities. - this.addAbility(new SimpleStaticAbility(new RayOfFrostLoseAbilitiesEffect())); + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new LoseAllAbilitiesAttachedEffect(AttachmentType.AURA), condition, + "as long as enchanted creature is red, it loses all abilities" + ))); // Enchanted creature doesn't untap during its controller's untap step. this.addAbility(new SimpleStaticAbility(new DontUntapInControllersUntapStepEnchantedEffect())); @@ -65,52 +78,3 @@ public final class RayOfFrost extends CardImpl { return new RayOfFrost(this); } } - -enum RayOfFrostCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - Permanent enchantment = source.getSourcePermanentIfItStillExists(game); - if (enchantment == null) { - return false; - } - Permanent creature = game.getPermanent(enchantment.getAttachedTo()); - return creature != null && creature.getColor(game).isRed(); - } - - @Override - public String toString() { - return "if enchanted creature is red"; - } -} - -class RayOfFrostLoseAbilitiesEffect extends ContinuousEffectImpl { - - RayOfFrostLoseAbilitiesEffect() { - super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.LoseAbility); - this.staticText = "As long as enchanted creature is red, it loses all abilities"; - } - - private RayOfFrostLoseAbilitiesEffect(final RayOfFrostLoseAbilitiesEffect effect) { - super(effect); - } - - @Override - public RayOfFrostLoseAbilitiesEffect copy() { - return new RayOfFrostLoseAbilitiesEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent enchantment = source.getSourcePermanentIfItStillExists(game); - if (enchantment != null) { - Permanent creature = game.getPermanent(enchantment.getAttachedTo()); - if (creature != null && creature.getColor(game).isRed()) { - creature.removeAllAbilities(source.getSourceId(), game); - return true; - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/r/RaziaBorosArchangel.java b/Mage.Sets/src/mage/cards/r/RaziaBorosArchangel.java index efe756e5831..319e6cd964d 100644 --- a/Mage.Sets/src/mage/cards/r/RaziaBorosArchangel.java +++ b/Mage.Sets/src/mage/cards/r/RaziaBorosArchangel.java @@ -24,6 +24,7 @@ import mage.filter.predicate.other.AnotherTargetPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; @@ -59,7 +60,7 @@ public final class RaziaBorosArchangel extends CardImpl { FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature (damage is redirected to)"); filter.add(new AnotherTargetPredicate(2)); - target = new TargetCreaturePermanent(filter); + target = new TargetPermanent(filter); target.setTargetTag(2); ability.addTarget(target); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/r/RazorPendulum.java b/Mage.Sets/src/mage/cards/r/RazorPendulum.java index 238040897a7..a611d207e30 100644 --- a/Mage.Sets/src/mage/cards/r/RazorPendulum.java +++ b/Mage.Sets/src/mage/cards/r/RazorPendulum.java @@ -1,17 +1,14 @@ package mage.cards.r; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.condition.common.LifeCompareCondition; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; +import mage.constants.ComparisonType; import mage.constants.TargetController; -import mage.game.Game; -import mage.players.Player; import java.util.UUID; @@ -20,17 +17,17 @@ import java.util.UUID; */ public final class RazorPendulum extends CardImpl { + private static final Condition condition = new LifeCompareCondition(TargetController.ACTIVE, ComparisonType.OR_LESS, 5); + public RazorPendulum(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); - // At the beginning of each player’s end step, if that player has 5 or less life, Razor Pendulum deals 2 damage to that player. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - TargetController.ANY, new RazorPendulumEffect(), false - ), RazorPendulumCondition.instance, "At the beginning of each player's end step, " + - "if that player has 5 or less life, {this} deals 2 damage to that player." - )); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.EACH_PLAYER, + new DamageTargetEffect(2, true, "that player"), + false, condition + ).withTargetPointerSet(true)); } private RazorPendulum(final RazorPendulum card) { @@ -42,41 +39,3 @@ public final class RazorPendulum extends CardImpl { return new RazorPendulum(this); } } - -class RazorPendulumEffect extends OneShotEffect { - - RazorPendulumEffect() { - super(Outcome.Benefit); - } - - private RazorPendulumEffect(final RazorPendulumEffect effect) { - super(effect); - } - - @Override - public RazorPendulumEffect copy() { - return new RazorPendulumEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(game.getActivePlayerId()); - if (player == null) { - return false; - } - return player.damage(2, source.getSourceId(), source, game) > 0; - } -} - -enum RazorPendulumCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(game.getActivePlayerId()); - if (player == null) { - return false; - } - return player.getLife() < 6; - } -} diff --git a/Mage.Sets/src/mage/cards/r/RazorfinAbolisher.java b/Mage.Sets/src/mage/cards/r/RazorfinAbolisher.java index 5eb4ebe3cbf..8b97aa063d4 100644 --- a/Mage.Sets/src/mage/cards/r/RazorfinAbolisher.java +++ b/Mage.Sets/src/mage/cards/r/RazorfinAbolisher.java @@ -16,6 +16,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.CounterAnyPredicate; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -41,7 +42,7 @@ public final class RazorfinAbolisher extends CardImpl { // {1}{U}, {tap}: Return target creature with a counter on it to its owner's hand. Ability ability = new SimpleActivatedAbility(new ReturnToHandTargetEffect(), new ManaCostsImpl<>("{1}{U}")); ability.addCost(new TapSourceCost()); - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); ability.addTarget(target); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/r/RazorgrassInvoker.java b/Mage.Sets/src/mage/cards/r/RazorgrassInvoker.java index 0bbced7dc8e..2bcaeed45fb 100644 --- a/Mage.Sets/src/mage/cards/r/RazorgrassInvoker.java +++ b/Mage.Sets/src/mage/cards/r/RazorgrassInvoker.java @@ -13,7 +13,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -36,7 +36,7 @@ public final class RazorgrassInvoker extends CardImpl { // {8}: Razorgrass Invoker and up to one other target creature each get +3/+3 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostSourceEffect(3, 3, Duration.EndOfTurn).setText("{this}"), new ManaCostsImpl<>("{8}")); ability.addEffect(new BoostTargetEffect(3, 3, Duration.EndOfTurn).setText("and up to one other target creature each get +3/+3 until end of turn")); - ability.addTarget(new TargetCreaturePermanent(0, 1, StaticFilters.FILTER_ANOTHER_TARGET_CREATURE, false)); + ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/ReachOfShadows.java b/Mage.Sets/src/mage/cards/r/ReachOfShadows.java index a956f8e6fd2..679bda0f4cc 100644 --- a/Mage.Sets/src/mage/cards/r/ReachOfShadows.java +++ b/Mage.Sets/src/mage/cards/r/ReachOfShadows.java @@ -9,6 +9,7 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorlessPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -28,7 +29,7 @@ public final class ReachOfShadows extends CardImpl { // Destroy target creature that's one or more colors. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private ReachOfShadows(final ReachOfShadows card) { diff --git a/Mage.Sets/src/mage/cards/r/RealmScorcherHellkite.java b/Mage.Sets/src/mage/cards/r/RealmScorcherHellkite.java index 979122cd0b7..c50c2dca1cd 100644 --- a/Mage.Sets/src/mage/cards/r/RealmScorcherHellkite.java +++ b/Mage.Sets/src/mage/cards/r/RealmScorcherHellkite.java @@ -6,7 +6,6 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.BargainedCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.mana.AddManaInAnyCombinationEffect; import mage.abilities.keyword.BargainAbility; @@ -42,11 +41,8 @@ public final class RealmScorcherHellkite extends CardImpl { this.addAbility(HasteAbility.getInstance()); // When Realm-Scorcher Hellkite enters the battlefield, if it was bargained, add four mana in any combination of colors. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new AddManaInAnyCombinationEffect(4)), - BargainedCondition.instance, - "When {this} enters, if it was bargained, add four mana in any combination of colors." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new AddManaInAnyCombinationEffect(4)) + .withInterveningIf(BargainedCondition.instance)); // {1}{R}: Realm-Scorcher Hellkite deals 1 damage to any target. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new ManaCostsImpl<>("{1}{R}")); diff --git a/Mage.Sets/src/mage/cards/r/ReaperOfFlightMoonsilver.java b/Mage.Sets/src/mage/cards/r/ReaperOfFlightMoonsilver.java index 598639a9933..0426b23e070 100644 --- a/Mage.Sets/src/mage/cards/r/ReaperOfFlightMoonsilver.java +++ b/Mage.Sets/src/mage/cards/r/ReaperOfFlightMoonsilver.java @@ -1,23 +1,22 @@ package mage.cards.r; -import java.util.UUID; - import mage.MageInt; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; - import mage.filter.StaticFilters; +import java.util.UUID; + /** * @author fireshoes */ @@ -34,13 +33,10 @@ public final class ReaperOfFlightMoonsilver extends CardImpl { // Delirium — Sacrifice another creature: Reaper of Flight Moonsilver gets +2/+1 until end of turn. // Activate this ability only if there are four or more card types among cards in your graveyard. - this.addAbility(new ConditionalActivatedAbility(Zone.BATTLEFIELD, + this.addAbility(new ActivateIfConditionActivatedAbility( new BoostSourceEffect(2, 1, Duration.EndOfTurn), - new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE), - DeliriumCondition.instance, - "Delirium — Sacrifice another creature: Reaper of Flight Moonsilver gets +2/+1 until end of turn. " - + "Activate only if there are four or more card types among cards in your graveyard.") - .addHint(CardTypesInGraveyardCount.YOU.getHint())); + new SacrificeTargetCost(StaticFilters.FILTER_ANOTHER_CREATURE), DeliriumCondition.instance + ).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); } private ReaperOfFlightMoonsilver(final ReaperOfFlightMoonsilver card) { diff --git a/Mage.Sets/src/mage/cards/r/ReaperOfNight.java b/Mage.Sets/src/mage/cards/r/ReaperOfNight.java index c65a5f356a9..b36da00f5c6 100644 --- a/Mage.Sets/src/mage/cards/r/ReaperOfNight.java +++ b/Mage.Sets/src/mage/cards/r/ReaperOfNight.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.keyword.FlyingAbility; @@ -32,12 +31,9 @@ public final class ReaperOfNight extends AdventureCard { this.toughness = new MageInt(5); // Whenever Reaper of Night attacks, if defending player has two or fewer cards in hand, it gains flying until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new GainAbilitySourceEffect( - FlyingAbility.getInstance(), Duration.EndOfTurn - ), false), ReaperOfNightCondition.instance, "Whenever {this} attacks, " + - "if defending player has two or fewer cards in hand, it gains flying until end of turn." - )); + this.addAbility(new AttacksTriggeredAbility(new GainAbilitySourceEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ).setText("it gains flying until end of turn")).withInterveningIf(ReaperOfNightCondition.instance)); // Harvest Fear // Target opponent discards two cards. @@ -65,4 +61,9 @@ enum ReaperOfNightCondition implements Condition { Player player = game.getPlayer(game.getCombat().getDefendingPlayerId(source.getSourceId(), game)); return player != null && player.getHand().size() <= 2; } -} \ No newline at end of file + + @Override + public String toString() { + return "defending player has two or fewer cards in hand"; + } +} diff --git a/Mage.Sets/src/mage/cards/r/ReaveSoul.java b/Mage.Sets/src/mage/cards/r/ReaveSoul.java index f128744f362..84095ae479e 100644 --- a/Mage.Sets/src/mage/cards/r/ReaveSoul.java +++ b/Mage.Sets/src/mage/cards/r/ReaveSoul.java @@ -9,6 +9,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -28,7 +29,7 @@ public final class ReaveSoul extends CardImpl { // Destroy target creature with power 3 or less. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private ReaveSoul(final ReaveSoul card) { diff --git a/Mage.Sets/src/mage/cards/r/ReaverAmbush.java b/Mage.Sets/src/mage/cards/r/ReaverAmbush.java index c9724a11924..8a273c9ba5c 100644 --- a/Mage.Sets/src/mage/cards/r/ReaverAmbush.java +++ b/Mage.Sets/src/mage/cards/r/ReaverAmbush.java @@ -9,6 +9,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -27,7 +28,7 @@ public final class ReaverAmbush extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{B}"); // Exile target creature with power 3 or less. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new ExileTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/r/RecklessBushwhacker.java b/Mage.Sets/src/mage/cards/r/RecklessBushwhacker.java index c6686dbc3bf..f4d123f0f37 100644 --- a/Mage.Sets/src/mage/cards/r/RecklessBushwhacker.java +++ b/Mage.Sets/src/mage/cards/r/RecklessBushwhacker.java @@ -1,10 +1,9 @@ package mage.cards.r; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.SurgedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.HasteAbility; @@ -12,18 +11,19 @@ import mage.abilities.keyword.SurgeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author fireshoes */ public final class RecklessBushwhacker extends CardImpl { public RecklessBushwhacker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); this.subtype.add(SubType.GOBLIN); this.subtype.add(SubType.WARRIOR); this.subtype.add(SubType.ALLY); @@ -37,11 +37,14 @@ public final class RecklessBushwhacker extends CardImpl { this.addAbility(HasteAbility.getInstance()); // When Reckless Bushwhacker enters the battlefield, if its surge cost was paid, other creatures you control get +1/+0 and gain haste until end of turn. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new BoostControlledEffect(1, 0, Duration.EndOfTurn, true), false); - ability.addEffect(new GainAbilityControlledEffect(HasteAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_OTHER_CONTROLLED_CREATURES, true)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, SurgedCondition.instance, - "When {this} enters, if its surge cost was paid, other creatures you control get +1/+0 and gain haste until end of turn.")); - + Ability ability = new EntersBattlefieldTriggeredAbility(new BoostControlledEffect( + 1, 0, Duration.EndOfTurn, true + ).setText("other creatures you control get +1/+0")).withInterveningIf(SurgedCondition.instance); + ability.addEffect(new GainAbilityControlledEffect( + HasteAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE, true + ).setText("and gain haste until end of turn")); + this.addAbility(ability); } private RecklessBushwhacker(final RecklessBushwhacker card) { diff --git a/Mage.Sets/src/mage/cards/r/RecklessRage.java b/Mage.Sets/src/mage/cards/r/RecklessRage.java index 452aeb78886..79b30f0ec35 100644 --- a/Mage.Sets/src/mage/cards/r/RecklessRage.java +++ b/Mage.Sets/src/mage/cards/r/RecklessRage.java @@ -5,12 +5,15 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.SecondTargetPointer; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author JayDi85 */ @@ -20,7 +23,7 @@ public final class RecklessRage extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); // Reckless Rage deals 4 damage to target creature you don't control and 2 damage to target creature you control. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.getSpellAbility().addEffect(new DamageTargetEffect(4).setUseOnlyTargetPointer(true)); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); this.getSpellAbility().addEffect(new DamageTargetEffect(2).setUseOnlyTargetPointer(true) diff --git a/Mage.Sets/src/mage/cards/r/RecklessSpite.java b/Mage.Sets/src/mage/cards/r/RecklessSpite.java index 280e0a92109..3948633a390 100644 --- a/Mage.Sets/src/mage/cards/r/RecklessSpite.java +++ b/Mage.Sets/src/mage/cards/r/RecklessSpite.java @@ -6,21 +6,20 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; /** - * * @author Loki */ public final class RecklessSpite extends CardImpl { public RecklessSpite(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}{B}"); this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(2, 2, StaticFilters.FILTER_PERMANENT_CREATURES_NON_BLACK, false)); + this.getSpellAbility().addTarget(new TargetPermanent(2, StaticFilters.FILTER_PERMANENT_CREATURES_NON_BLACK)); this.getSpellAbility().addEffect(new LoseLifeSourceControllerEffect(5)); } diff --git a/Mage.Sets/src/mage/cards/r/ReclusiveWight.java b/Mage.Sets/src/mage/cards/r/ReclusiveWight.java index 13a130eaf55..00fad2016ee 100644 --- a/Mage.Sets/src/mage/cards/r/ReclusiveWight.java +++ b/Mage.Sets/src/mage/cards/r/ReclusiveWight.java @@ -1,33 +1,36 @@ package mage.cards.r; -import java.util.UUID; import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.SacrificeSourceEffect; -import mage.constants.SubType; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AnotherPredicate; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class ReclusiveWight extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("another nonland permanent"); + private static final FilterPermanent filter = new FilterControlledPermanent("you control another nonland permanent"); static { filter.add(Predicates.not(CardType.LAND.getPredicate())); filter.add(AnotherPredicate.instance); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + public ReclusiveWight(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); @@ -37,11 +40,7 @@ public final class ReclusiveWight extends CardImpl { this.toughness = new MageInt(4); // At the beginning of your upkeep, if you control another nonland permanent, sacrifice Reclusive Wight. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceEffect()), - new PermanentsOnTheBattlefieldCondition(filter), - "At the beginning of your upkeep, if you control another nonland permanent, sacrifice {this}." - )); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceEffect()).withInterveningIf(condition)); } private ReclusiveWight(final ReclusiveWight card) { diff --git a/Mage.Sets/src/mage/cards/r/Reconnaissance.java b/Mage.Sets/src/mage/cards/r/Reconnaissance.java index 3c0555a76d0..a84ef28130c 100644 --- a/Mage.Sets/src/mage/cards/r/Reconnaissance.java +++ b/Mage.Sets/src/mage/cards/r/Reconnaissance.java @@ -1,41 +1,38 @@ - package mage.cards.r; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.RemoveFromCombatTargetEffect; +import mage.abilities.effects.common.UntapTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.AttackingPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author spjspj */ public final class Reconnaissance extends CardImpl { - private static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("attacking creature controlled by you"); + private static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("attacking creature you control"); static { filter.add(AttackingPredicate.instance); } public Reconnaissance(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); // {0}: Remove target attacking creature you control from combat and untap it. - Ability ability = new SimpleActivatedAbility(new ReconnaissanceRemoveFromCombatEffect(), new ManaCostsImpl<>("{0}")); - ability.addTarget(new TargetControlledCreaturePermanent(filter)); + Ability ability = new SimpleActivatedAbility(new RemoveFromCombatTargetEffect() + .setText("remove target attacking creature you control from combat"), new GenericManaCost(0)); + ability.addEffect(new UntapTargetEffect("and untap it")); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } @@ -48,33 +45,3 @@ public final class Reconnaissance extends CardImpl { return new Reconnaissance(this); } } - -class ReconnaissanceRemoveFromCombatEffect extends OneShotEffect { - - ReconnaissanceRemoveFromCombatEffect() { - super(Outcome.Benefit); - this.staticText = "Remove target attacking creature you control from combat and untap it"; - } - - private ReconnaissanceRemoveFromCombatEffect(final ReconnaissanceRemoveFromCombatEffect effect) { - super(effect); - } - - @Override - public ReconnaissanceRemoveFromCombatEffect copy() { - return new ReconnaissanceRemoveFromCombatEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent creature = game.getPermanent(source.getFirstTarget()); - Player player = game.getPlayer(source.getControllerId()); - - if (creature != null && player != null && creature.isAttacking()) { - creature.removeFromCombat(game); - creature.untap(game); - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/r/RedTigerMechan.java b/Mage.Sets/src/mage/cards/r/RedTigerMechan.java new file mode 100644 index 00000000000..f78b3b44594 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RedTigerMechan.java @@ -0,0 +1,41 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.WarpAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RedTigerMechan extends CardImpl { + + public RedTigerMechan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.ROBOT); + this.subtype.add(SubType.CAT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Warp {1}{R} + this.addAbility(new WarpAbility(this, "{1}{R}")); + } + + private RedTigerMechan(final RedTigerMechan card) { + super(card); + } + + @Override + public RedTigerMechan copy() { + return new RedTigerMechan(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RedXIIIProudWarrior.java b/Mage.Sets/src/mage/cards/r/RedXIIIProudWarrior.java index ebe56a52fc7..e5bc2b774cc 100644 --- a/Mage.Sets/src/mage/cards/r/RedXIIIProudWarrior.java +++ b/Mage.Sets/src/mage/cards/r/RedXIIIProudWarrior.java @@ -33,7 +33,7 @@ public final class RedXIIIProudWarrior extends CardImpl { static { filter.add(ModifiedPredicate.instance); - filter.add(Predicates.or( + filter2.add(Predicates.or( SubType.AURA.getPredicate(), SubType.EQUIPMENT.getPredicate() )); diff --git a/Mage.Sets/src/mage/cards/r/RedemptionChoir.java b/Mage.Sets/src/mage/cards/r/RedemptionChoir.java index 1c3a7ff67b6..84dbd00739b 100644 --- a/Mage.Sets/src/mage/cards/r/RedemptionChoir.java +++ b/Mage.Sets/src/mage/cards/r/RedemptionChoir.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; import mage.abilities.condition.common.CovenCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.hint.common.CovenHint; import mage.abilities.keyword.LifelinkAbility; @@ -25,14 +24,16 @@ import java.util.UUID; */ public final class RedemptionChoir extends CardImpl { - private static final FilterPermanentCard filter = new FilterPermanentCard("permanent card with mana value 3 or less from your graveyard"); + private static final FilterPermanentCard filter + = new FilterPermanentCard("permanent card with mana value 3 or less from your graveyard"); + static { filter.add(new ManaValuePredicate(ComparisonType.OR_LESS, 3)); } public RedemptionChoir(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); - + this.subtype.add(SubType.VAMPIRE); this.subtype.add(SubType.CLERIC); this.power = new MageInt(3); @@ -42,13 +43,9 @@ public final class RedemptionChoir extends CardImpl { this.addAbility(LifelinkAbility.getInstance()); // Coven -- Whenever Redemption Choir enters the battlefield or attacks, if you control three or more creatures with different powers, return target permanent card with mana value 3 or less from your graveyard to the battlefield. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldOrAttacksSourceTriggeredAbility( - new ReturnFromGraveyardToBattlefieldTargetEffect() - ), CovenCondition.instance, "Whenever {this} enters or attacks, " + - "if you control three or more creatures with different powers, " + - "return target permanent card with mana value 3 or less from your graveyard to the battlefield." - ); + Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect() + ).withInterveningIf(CovenCondition.instance); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability.addHint(CovenHint.instance).setAbilityWord(AbilityWord.COVEN)); diff --git a/Mage.Sets/src/mage/cards/r/ReflectorMage.java b/Mage.Sets/src/mage/cards/r/ReflectorMage.java index df5dc5d9021..da145860a07 100644 --- a/Mage.Sets/src/mage/cards/r/ReflectorMage.java +++ b/Mage.Sets/src/mage/cards/r/ReflectorMage.java @@ -15,6 +15,7 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.util.CardUtil; @@ -41,7 +42,7 @@ public final class ReflectorMage extends CardImpl { // When Reflector Mage enters the battlefield, return target creature an opponent controls to its owner's hand. That creature's owner can't cast spells with the same name as that creature until your next turn. Ability ability = new EntersBattlefieldTriggeredAbility(new ReflectorMageEffect(), false); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RefuseCooperate.java b/Mage.Sets/src/mage/cards/r/RefuseCooperate.java index b51df9a6eb7..23bac480f0e 100644 --- a/Mage.Sets/src/mage/cards/r/RefuseCooperate.java +++ b/Mage.Sets/src/mage/cards/r/RefuseCooperate.java @@ -52,7 +52,7 @@ class RefuseEffect extends OneShotEffect { RefuseEffect() { super(Outcome.Damage); - staticText = "Refuse deals damage to target spell's controller equal to that spell's mana value"; + staticText = "{this} deals damage to target spell's controller equal to that spell's mana value"; } private RefuseEffect(final RefuseEffect effect) { diff --git a/Mage.Sets/src/mage/cards/r/RegalBloodlord.java b/Mage.Sets/src/mage/cards/r/RegalBloodlord.java index e739b254bfc..6c9483820d7 100644 --- a/Mage.Sets/src/mage/cards/r/RegalBloodlord.java +++ b/Mage.Sets/src/mage/cards/r/RegalBloodlord.java @@ -1,12 +1,12 @@ package mage.cards.r; import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.YouGainedLifeCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.ControllerGainedLifeCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -22,6 +22,8 @@ import java.util.UUID; */ public final class RegalBloodlord extends CardImpl { + private static final Condition condition = new YouGainedLifeCondition(); + public RegalBloodlord(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{B}"); @@ -34,15 +36,8 @@ public final class RegalBloodlord extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // At the beginning of each end step, if you gained life this turn, create a 1/1 black Bat creature token with flying. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - TargetController.ANY, new CreateTokenEffect(new BatToken()), - false - ), - new YouGainedLifeCondition(), - "At the beginning of each end step, " - + "if you gained life this turn, " - + "create a 1/1 black Bat creature token with flying." + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.ANY, new CreateTokenEffect(new BatToken()), false, condition ).addHint(ControllerGainedLifeCount.getHint()), new PlayerGainedLifeWatcher()); } diff --git a/Mage.Sets/src/mage/cards/r/RegnaTheRedeemer.java b/Mage.Sets/src/mage/cards/r/RegnaTheRedeemer.java index 794e2187e35..86327b0b9af 100644 --- a/Mage.Sets/src/mage/cards/r/RegnaTheRedeemer.java +++ b/Mage.Sets/src/mage/cards/r/RegnaTheRedeemer.java @@ -1,29 +1,25 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.abilities.condition.IntCompareCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.effects.common.CreateTokenEffect; -import mage.constants.SubType; -import mage.constants.SuperType; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.PartnerWithAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.constants.TargetController; import mage.game.Game; import mage.game.permanent.token.WarriorToken; -import mage.players.Player; import mage.watchers.common.PlayerGainedLifeWatcher; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class RegnaTheRedeemer extends CardImpl { @@ -43,15 +39,9 @@ public final class RegnaTheRedeemer extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // At the beginning of each end step, if your team gained life this turn, create two 1/1 white Warrior creature tokens. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - TargetController.ANY, new CreateTokenEffect(new WarriorToken(), 2), - false - ), - new RegnaTheRedeemerCondition(), - "At the beginning of each end step, " - + "if your team gained life this turn, " - + "create two 1/1 white Warrior creature tokens" + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.ANY, new CreateTokenEffect(new WarriorToken(), 2), + false, RegnaTheRedeemerCondition.instance ), new PlayerGainedLifeWatcher()); } @@ -65,27 +55,20 @@ public final class RegnaTheRedeemer extends CardImpl { } } -class RegnaTheRedeemerCondition extends IntCompareCondition { +enum RegnaTheRedeemerCondition implements Condition { + instance; - public RegnaTheRedeemerCondition() { - super(ComparisonType.MORE_THAN, 0); + @Override + public boolean apply(Game game, Ability source) { + // TODO: if teammates are ever implemented this will need to be refactored + return game + .getState() + .getWatcher(PlayerGainedLifeWatcher.class) + .getLifeGained(source.getControllerId()) > 0; } @Override - protected int getInputValue(Game game, Ability source) { - int gainedLife = 0; - PlayerGainedLifeWatcher watcher = game.getState().getWatcher(PlayerGainedLifeWatcher.class); - if (watcher != null) { - for (UUID playerId : game.getPlayerList()) { - Player player = game.getPlayer(playerId); - if (player != null && !player.hasOpponent(source.getControllerId(), game)) { - gainedLife = watcher.getLifeGained(playerId); - if (gainedLife > 0) { - break; - } - } - } - } - return gainedLife; + public String toString() { + return "your team gained life this turn"; } } diff --git a/Mage.Sets/src/mage/cards/r/ReiverDemon.java b/Mage.Sets/src/mage/cards/r/ReiverDemon.java index 8f5b71c3f74..7dc7132c13d 100644 --- a/Mage.Sets/src/mage/cards/r/ReiverDemon.java +++ b/Mage.Sets/src/mage/cards/r/ReiverDemon.java @@ -1,12 +1,9 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromHandSourcePermanentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -18,8 +15,9 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; import mage.watchers.common.CastFromHandWatcher; +import java.util.UUID; + /** - * * @author daagar */ public final class ReiverDemon extends CardImpl { @@ -32,7 +30,7 @@ public final class ReiverDemon extends CardImpl { } public ReiverDemon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}{B}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}{B}{B}"); this.subtype.add(SubType.DEMON); this.power = new MageInt(6); this.toughness = new MageInt(6); @@ -41,11 +39,8 @@ public final class ReiverDemon extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Reiver Demon enters the battlefield, if you cast it from your hand, destroy all nonartifact, nonblack creatures. They can't be regenerated. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(filter, true), false), - CastFromHandSourcePermanentCondition.instance, - "When {this} enters, if you cast it from your hand, destroy all nonartifact, nonblack creatures. They can't be regenerated."), - new CastFromHandWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(filter, true)) + .withInterveningIf(CastFromHandSourcePermanentCondition.instance), new CastFromHandWatcher()); } private ReiverDemon(final ReiverDemon card) { diff --git a/Mage.Sets/src/mage/cards/r/RekindledFlame.java b/Mage.Sets/src/mage/cards/r/RekindledFlame.java index 92115531b71..daaf37c3f6a 100644 --- a/Mage.Sets/src/mage/cards/r/RekindledFlame.java +++ b/Mage.Sets/src/mage/cards/r/RekindledFlame.java @@ -1,12 +1,11 @@ package mage.cards.r; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.common.OpponentHasNoCardsInHandCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -22,7 +21,7 @@ import java.util.UUID; public final class RekindledFlame extends CardImpl { private static final Hint hint = new ConditionHint( - OpponentHasNoCardsInHandCondition.instance, "Opponent has no cards in hand" + OpponentHasNoCardsInHandCondition.instance, "An opponent has no cards in hand" ); public RekindledFlame(UUID ownerId, CardSetInfo setInfo) { @@ -33,13 +32,9 @@ public final class RekindledFlame extends CardImpl { this.getSpellAbility().addTarget(new TargetAnyTarget()); // At the beginning of your upkeep, if an opponent has no cards in hand, you may return Rekindled Flame from your graveyard to your hand. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - Zone.GRAVEYARD, TargetController.YOU, new ReturnSourceFromGraveyardToHandEffect(), - true - ), OpponentHasNoCardsInHandCondition.instance, "At the beginning of your upkeep, " + - "if an opponent has no cards in hand, you may return {this} from your graveyard to your hand." - ).addHint(hint)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + Zone.GRAVEYARD, TargetController.YOU, new ReturnSourceFromGraveyardToHandEffect(), true + ).withInterveningIf(OpponentHasNoCardsInHandCondition.instance).addHint(hint)); } private RekindledFlame(final RekindledFlame card) { diff --git a/Mage.Sets/src/mage/cards/r/RelentlessDead.java b/Mage.Sets/src/mage/cards/r/RelentlessDead.java index 3d5f3299013..ff8fbef7956 100644 --- a/Mage.Sets/src/mage/cards/r/RelentlessDead.java +++ b/Mage.Sets/src/mage/cards/r/RelentlessDead.java @@ -3,22 +3,21 @@ package mage.cards.r; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.costs.common.DynamicValueGenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.TargetManaValue; import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.effects.common.ReturnToHandSourceEffect; import mage.abilities.keyword.MenaceAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.SubType; import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.filter.predicate.mageobject.ManaValuePredicate; -import mage.game.Game; -import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; -import mage.util.ManaUtil; import java.util.UUID; @@ -27,6 +26,13 @@ import java.util.UUID; */ public final class RelentlessDead extends CardImpl { + private static final FilterCard filter = new FilterCreatureCard("another target Zombie creature card with mana value X from your graveyard"); // This target defines X + + static { + filter.add(SubType.ZOMBIE.getPredicate()); + filter.add(AnotherPredicate.instance); + } + public RelentlessDead(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{B}"); this.subtype.add(SubType.ZOMBIE); @@ -40,7 +46,11 @@ public final class RelentlessDead extends CardImpl { this.addAbility(new DiesSourceTriggeredAbility(new DoIfCostPaid(new ReturnToHandSourceEffect().setText("return it to its owner's hand"), new ManaCostsImpl<>("{B}")))); // When Relentless Dead dies, you may pay {X}. If you do, return another target Zombie creature card with converted mana cost X from your graveyard to the battlefield. - this.addAbility(new DiesSourceTriggeredAbility(new RelentlessDeadEffect())); + Ability ability = new DiesSourceTriggeredAbility(new DoIfCostPaid( + new ReturnFromGraveyardToBattlefieldTargetEffect(), + new DynamicValueGenericManaCost(TargetManaValue.instance, "{X}"))); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); } private RelentlessDead(final RelentlessDead card) { @@ -52,46 +62,3 @@ public final class RelentlessDead extends CardImpl { return new RelentlessDead(this); } } - -class RelentlessDeadEffect extends OneShotEffect { - - RelentlessDeadEffect() { - super(Outcome.PutCardInPlay); - this.staticText = "you may pay {X}. If you do, return another target Zombie creature card with mana value X from your graveyard to the battlefield"; - } - - private RelentlessDeadEffect(final RelentlessDeadEffect effect) { - super(effect); - } - - @Override - public RelentlessDeadEffect copy() { - return new RelentlessDeadEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - if (controller.chooseUse(Outcome.Benefit, "Do you want to pay {X} to return zombie?", source, game)) { - int payCount = ManaUtil.playerPaysXGenericMana(true, "Relentless Dead", controller, source, game); - // can be 0 - FilterCard filter = new FilterCard("Another target Zombie card with mana value {" + payCount + "}"); - filter.add(SubType.ZOMBIE.getPredicate()); - filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, payCount)); - filter.add(AnotherPredicate.instance); - TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(filter); - if (controller.chooseTarget(outcome, target, source, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - controller.moveCards(card, Zone.BATTLEFIELD, source, game); - } - } - - } - return true; - } - return false; - - } -} diff --git a/Mage.Sets/src/mage/cards/r/RendFlesh.java b/Mage.Sets/src/mage/cards/r/RendFlesh.java index 8c4a95520b6..6997f245a38 100644 --- a/Mage.Sets/src/mage/cards/r/RendFlesh.java +++ b/Mage.Sets/src/mage/cards/r/RendFlesh.java @@ -10,6 +10,7 @@ import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -30,7 +31,7 @@ public final class RendFlesh extends CardImpl { this.subtype.add(SubType.ARCANE); // Destroy target non-Spirit creature. - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); this.getSpellAbility().addTarget(target); this.getSpellAbility().addEffect(new DestroyTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/r/RendingVolley.java b/Mage.Sets/src/mage/cards/r/RendingVolley.java index 7a877174423..2d547010c04 100644 --- a/Mage.Sets/src/mage/cards/r/RendingVolley.java +++ b/Mage.Sets/src/mage/cards/r/RendingVolley.java @@ -15,6 +15,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -43,7 +44,7 @@ public final class RendingVolley extends CardImpl { // Rending Volley deals 4 damage to target white or blue creature. this.getSpellAbility().addEffect(new DamageTargetEffect(4)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private RendingVolley(final RendingVolley card) { diff --git a/Mage.Sets/src/mage/cards/r/RenegadeSilent.java b/Mage.Sets/src/mage/cards/r/RenegadeSilent.java index 7ce19daa21f..a6fef0d7585 100644 --- a/Mage.Sets/src/mage/cards/r/RenegadeSilent.java +++ b/Mage.Sets/src/mage/cards/r/RenegadeSilent.java @@ -12,10 +12,13 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author Susucr */ @@ -33,7 +36,7 @@ public final class RenegadeSilent extends CardImpl { Ability ability = new BeginningOfEndStepTriggeredAbility( new GoadTargetEffect().setText("goad up to one target creature you don't control") ); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); ability.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance()) .concatBy("and")); ability.addEffect(new PhaseOutSourceEffect()); diff --git a/Mage.Sets/src/mage/cards/r/RepeatingBarrage.java b/Mage.Sets/src/mage/cards/r/RepeatingBarrage.java index 52a2eb7e75c..525d1314c5b 100644 --- a/Mage.Sets/src/mage/cards/r/RepeatingBarrage.java +++ b/Mage.Sets/src/mage/cards/r/RepeatingBarrage.java @@ -3,7 +3,7 @@ package mage.cards.r; import mage.abilities.Ability; import mage.abilities.condition.common.RaidCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; import mage.abilities.hint.common.RaidHint; @@ -30,7 +30,7 @@ public final class RepeatingBarrage extends CardImpl { this.getSpellAbility().addTarget(new TargetAnyTarget()); // Raid — {3}{R}{R}: Return Repeating Barrage from your graveyard to your hand. Activate this ability only if you attacked this turn. - Ability ability = new ConditionalActivatedAbility(Zone.GRAVEYARD, + Ability ability = new ActivateIfConditionActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), new ManaCostsImpl<>("{3}{R}{R}"), RaidCondition.instance); diff --git a/Mage.Sets/src/mage/cards/r/RepentantVampire.java b/Mage.Sets/src/mage/cards/r/RepentantVampire.java index 1cfb1d451f9..6be51e84ac0 100644 --- a/Mage.Sets/src/mage/cards/r/RepentantVampire.java +++ b/Mage.Sets/src/mage/cards/r/RepentantVampire.java @@ -23,6 +23,7 @@ import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -59,7 +60,7 @@ public final class RepentantVampire extends CardImpl { ThresholdCondition.instance, "As long as seven or more cards are in your graveyard, {this} is white" )); Ability gainedAbility = new SimpleActivatedAbility(new DestroyTargetEffect(), new TapSourceCost()); - gainedAbility.addTarget(new TargetCreaturePermanent(filter)); + gainedAbility.addTarget(new TargetPermanent(filter)); ability.addEffect(new ConditionalContinuousEffect( new GainAbilitySourceEffect(gainedAbility, Duration.WhileOnBattlefield), ThresholdCondition.instance, "and has \"{T}: Destroy target black creature.\"" diff --git a/Mage.Sets/src/mage/cards/r/Reprisal.java b/Mage.Sets/src/mage/cards/r/Reprisal.java index 0d51718bf2f..219a8a605af 100644 --- a/Mage.Sets/src/mage/cards/r/Reprisal.java +++ b/Mage.Sets/src/mage/cards/r/Reprisal.java @@ -9,6 +9,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class Reprisal extends CardImpl { // Destroy target creature with power 4 or greater. It can't be regenerated. this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private Reprisal(final Reprisal card) { diff --git a/Mage.Sets/src/mage/cards/r/ReservoirKraken.java b/Mage.Sets/src/mage/cards/r/ReservoirKraken.java index 33a36860b35..1f57e43a487 100644 --- a/Mage.Sets/src/mage/cards/r/ReservoirKraken.java +++ b/Mage.Sets/src/mage/cards/r/ReservoirKraken.java @@ -1,31 +1,31 @@ package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.common.SourceTappedCondition; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.constants.Outcome; -import mage.constants.SubType; import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.WardAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.TargetController; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.FishToken; import mage.players.Player; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author weirddan455 */ public final class ReservoirKraken extends CardImpl { @@ -44,11 +44,9 @@ public final class ReservoirKraken extends CardImpl { this.addAbility(new WardAbility(new GenericManaCost(2), false)); // At the beginning of each combat, if Reservoir Kraken is untapped, any opponent may tap an untapped creature they control. If they do, tap Reservoir Kraken and create a 1/1 blue Fish creature token with "This creature can't be blocked." - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility(TargetController.ANY, new ReservoirKrakenEffect(), false), - SourceTappedCondition.UNTAPPED, - "At the beginning of each combat, if {this} is untapped, any opponent may tap an untapped creature they control. If they do, tap {this} and create a 1/1 blue Fish creature token with \"This creature can't be blocked.\"" - )); + this.addAbility(new BeginningOfCombatTriggeredAbility( + TargetController.ANY, new ReservoirKrakenEffect(), false + ).withInterveningIf(SourceTappedCondition.UNTAPPED)); } private ReservoirKraken(final ReservoirKraken card) { @@ -71,7 +69,7 @@ class ReservoirKrakenEffect extends OneShotEffect { public ReservoirKrakenEffect() { super(Outcome.Tap); - this.staticText = "any opponent may tap an untapped creature they control. If they do, tap {this} and create a 1/1 blue Fish creature token with \"This creature can't be blocked.\""; + this.staticText = "any opponent may tap an untapped creature they control. If they do, tap {this} and create a 1/1 blue Fish creature token with \"This token can't be blocked.\""; } private ReservoirKrakenEffect(final ReservoirKrakenEffect effect) { @@ -88,15 +86,19 @@ class ReservoirKrakenEffect extends OneShotEffect { boolean opponentTapped = false; for (UUID opponentId : game.getOpponents(source.getControllerId())) { Player opponent = game.getPlayer(opponentId); - if (opponent != null) { - TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(1, 1, filter, true); - if (target.canChoose(opponentId, source, game) && opponent.chooseUse(Outcome.AIDontUseIt, "Tap an untapped creature you control?", source, game)) { - opponent.chooseTarget(Outcome.Tap, target, source, game); - Permanent permanent = game.getPermanent(target.getFirstTarget()); - if (permanent != null && permanent.tap(source, game)) { - opponentTapped = true; - } - } + if (opponent == null) { + continue; + } + TargetPermanent target = new TargetPermanent(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE); + target.withNotTarget(true); + if (!target.canChoose(opponentId, source, game) + || !opponent.chooseUse(Outcome.AIDontUseIt, "Tap an untapped creature you control?", source, game)) { + continue; + } + opponent.chooseTarget(Outcome.Tap, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null && permanent.tap(source, game)) { + opponentTapped = true; } } if (opponentTapped) { diff --git a/Mage.Sets/src/mage/cards/r/ResistanceBomber.java b/Mage.Sets/src/mage/cards/r/ResistanceBomber.java index be0c252c332..b5ca1bade46 100644 --- a/Mage.Sets/src/mage/cards/r/ResistanceBomber.java +++ b/Mage.Sets/src/mage/cards/r/ResistanceBomber.java @@ -1,32 +1,31 @@ package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.common.SourceAttackingCondition; import mage.abilities.costs.common.RemoveCountersSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.SpaceflightAbility; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; +import mage.constants.SubType; import mage.counters.CounterType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author NinthWorld */ public final class ResistanceBomber extends CardImpl { public ResistanceBomber(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{R}"); - + this.subtype.add(SubType.REBEL); this.subtype.add(SubType.STARSHIP); this.power = new MageInt(2); @@ -37,14 +36,15 @@ public final class ResistanceBomber extends CardImpl { // Resistance Bomber enters the battlefield with a charge counter on it. this.addAbility(new EntersBattlefieldAbility( - new AddCountersSourceEffect(CounterType.CHARGE.createInstance()) - .setText("with a charge counter on it"))); + new AddCountersSourceEffect(CounterType.CHARGE.createInstance()), "with a charge counter on it" + )); // Remove a charge counter from Resistance Bomber: Resistance Bomber deals 5 damage to target creature. Activate this ability only if Resistance Bomber is attacking. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, + Ability ability = new ActivateIfConditionActivatedAbility( new DamageTargetEffect(5), new RemoveCountersSourceCost(CounterType.CHARGE.createInstance()), - SourceAttackingCondition.instance); + SourceAttackingCondition.instance + ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/ResistanceSquad.java b/Mage.Sets/src/mage/cards/r/ResistanceSquad.java index 2ea52a106b3..fe29afaf179 100644 --- a/Mage.Sets/src/mage/cards/r/ResistanceSquad.java +++ b/Mage.Sets/src/mage/cards/r/ResistanceSquad.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; @@ -23,14 +22,14 @@ import java.util.UUID; */ public final class ResistanceSquad extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent(SubType.HUMAN); + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.HUMAN, "you control another Human"); static { filter.add(AnotherPredicate.instance); } private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); - private static final Hint hint = new ConditionHint(condition, "You control another Human"); + private static final Hint hint = new ConditionHint(condition); public ResistanceSquad(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); @@ -41,11 +40,8 @@ public final class ResistanceSquad extends CardImpl { this.toughness = new MageInt(2); // When Resistance Squad enters the battlefield, if you control another Human, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( - new DrawCardSourceControllerEffect(1)), - condition, "When {this} enters, " + - "if you control another Human, draw a card." - ).addHint(hint)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .withInterveningIf(condition).addHint(hint)); } private ResistanceSquad(final ResistanceSquad card) { diff --git a/Mage.Sets/src/mage/cards/r/ResplendentGriffin.java b/Mage.Sets/src/mage/cards/r/ResplendentGriffin.java index d4a3045b668..2d70a3a082f 100644 --- a/Mage.Sets/src/mage/cards/r/ResplendentGriffin.java +++ b/Mage.Sets/src/mage/cards/r/ResplendentGriffin.java @@ -3,7 +3,6 @@ package mage.cards.r; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.CitysBlessingCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; @@ -35,10 +34,10 @@ public final class ResplendentGriffin extends CardImpl { this.addAbility(new AscendAbility()); // Whenever Resplendent Griffin attacks, if you have the city's blessing, put a +1/+1 counter on it. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new AttacksTriggeredAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false), CitysBlessingCondition.instance, - "Whenever {this} attacks, if you have the city's blessing, put a +1/+1 counter on it.") - .addHint(CitysBlessingHint.instance)); + this.addAbility(new AttacksTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()) + .setText("put a +1/+1 counter on it") + ).withInterveningIf(CitysBlessingCondition.instance).addHint(CitysBlessingHint.instance)); } private ResplendentGriffin(final ResplendentGriffin card) { diff --git a/Mage.Sets/src/mage/cards/r/ResplendentMarshal.java b/Mage.Sets/src/mage/cards/r/ResplendentMarshal.java index 3421512625b..cd6f67ec705 100644 --- a/Mage.Sets/src/mage/cards/r/ResplendentMarshal.java +++ b/Mage.Sets/src/mage/cards/r/ResplendentMarshal.java @@ -1,6 +1,5 @@ package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -9,13 +8,13 @@ import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.costs.common.ExileFromGraveCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DoWhenCostPaid; -import mage.cards.Card; -import mage.constants.Outcome; -import mage.constants.SubType; import mage.abilities.keyword.FlyingAbility; +import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; @@ -25,6 +24,8 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** * * @author weirddan455 @@ -54,7 +55,7 @@ public final class ResplendentMarshal extends CardImpl { this.addAbility(new EntersBattlefieldOrDiesSourceTriggeredAbility( new DoWhenCostPaid( new ReflexiveTriggeredAbility(new ResplendentMarshalEffect(), false, - "put a +1/+1 counter on each creature you control other than Resplendent Marshal that shares a creature type with the exiled card"), + "put a +1/+1 counter on each creature you control other than {this} that shares a creature type with the exiled card"), new ExileFromGraveCost(new TargetCardInYourGraveyard(filter), true), "Exile another creature card from your graveyard?" ), false diff --git a/Mage.Sets/src/mage/cards/r/RestlessVinestalk.java b/Mage.Sets/src/mage/cards/r/RestlessVinestalk.java index 8bc24640ea7..f9e66ba12e9 100644 --- a/Mage.Sets/src/mage/cards/r/RestlessVinestalk.java +++ b/Mage.Sets/src/mage/cards/r/RestlessVinestalk.java @@ -18,7 +18,7 @@ import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.permanent.token.custom.CreatureToken; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -53,7 +53,7 @@ public final class RestlessVinestalk extends CardImpl { // Whenever Restless Vinestalk attacks, up to one other target creature has base power and toughness 3/3 until end of turn. Ability ability = new AttacksTriggeredAbility(new SetBasePowerToughnessTargetEffect(3, 3, Duration.EndOfTurn), false); - ability.addTarget(new TargetCreaturePermanent(0, 1, filter, false)); + ability.addTarget(new TargetPermanent(0, 1, filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/ResurrectedCultist.java b/Mage.Sets/src/mage/cards/r/ResurrectedCultist.java index fb1f574e1b9..8d46aa372ef 100644 --- a/Mage.Sets/src/mage/cards/r/ResurrectedCultist.java +++ b/Mage.Sets/src/mage/cards/r/ResurrectedCultist.java @@ -30,8 +30,8 @@ public final class ResurrectedCultist extends CardImpl { this.addAbility(new ActivateIfConditionActivatedAbility( Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldWithCounterEffect(CounterType.FINALITY.createInstance(), false), - new ManaCostsImpl<>("{2}{B}{B}"), DeliriumCondition.instance, TimingRule.SORCERY - ).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); + new ManaCostsImpl<>("{2}{B}{B}"), DeliriumCondition.instance + ).setTiming(TimingRule.SORCERY).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); } private ResurrectedCultist(final ResurrectedCultist card) { diff --git a/Mage.Sets/src/mage/cards/r/Retribution.java b/Mage.Sets/src/mage/cards/r/Retribution.java index 6a26dec77ad..9c855f3878b 100644 --- a/Mage.Sets/src/mage/cards/r/Retribution.java +++ b/Mage.Sets/src/mage/cards/r/Retribution.java @@ -1,8 +1,5 @@ - package mage.cards.r; -import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -10,15 +7,22 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetImpl; +import mage.target.TargetPermanent; +import mage.target.common.TargetPermanentSameController; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; /** - * * @author jeffwadsworth */ public final class Retribution extends CardImpl { @@ -28,8 +32,7 @@ public final class Retribution extends CardImpl { // Choose two target creatures an opponent controls. That player chooses and sacrifices one of those creatures. Put a -1/-1 counter on the other. this.getSpellAbility().addEffect(new RetributionEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanentOpponentSameController(2, 2, StaticFilters.FILTER_PERMANENT_CREATURE, false)); - + this.getSpellAbility().addTarget(new TargetPermanentSameController(2, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES)); } private Retribution(final Retribution card) { @@ -60,66 +63,48 @@ class RetributionEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = source.getSourceObject(game); - if (sourceObject != null) { - boolean sacrificeDone = false; - int count = 0; - for (UUID targetId : getTargetPointer().getTargets(game, source)) { - Permanent creature = game.getPermanent(targetId); - if (creature != null) { - Player controllerOfCreature = game.getPlayer(creature.getControllerId()); - if ((count == 0 && controllerOfCreature != null - && controllerOfCreature.chooseUse(Outcome.Sacrifice, "Sacrifice " + creature.getLogName() + '?', source, game)) - || (count == 1 - && !sacrificeDone)) { - creature.sacrifice(source, game); - sacrificeDone = true; - } else { - creature.addCounters(CounterType.M1M1.createInstance(), source.getControllerId(), source, game); - } - count++; - } - } - return true; + List permanents = this + .getTargetPointer() + .getTargets(game, source) + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + List canSac = permanents + .stream() + .filter(Permanent::canBeSacrificed) + .collect(Collectors.toList()); + Permanent toSacrifice; + switch (canSac.size()) { + case 0: + toSacrifice = null; + break; + case 1: + toSacrifice = canSac.get(0); + break; + default: + toSacrifice = Optional + .ofNullable(canSac.get(0).getControllerId()) + .map(game::getPlayer) + .map(player -> { + FilterPermanent filter = new FilterPermanent(); + filter.add(new PermanentReferenceInCollectionPredicate(canSac, game)); + TargetPermanent target = new TargetPermanent(filter); + target.withNotTarget(true); + player.choose(Outcome.Sacrifice, target, source, game); + return target; + }) + .map(TargetImpl::getFirstTarget) + .map(game::getPermanent) + .orElse(null); } - return false; - } -} - -class TargetCreaturePermanentOpponentSameController extends TargetCreaturePermanent { - - public TargetCreaturePermanentOpponentSameController(int minNumTargets, int maxNumTargets, FilterCreaturePermanent filter, boolean notTarget) { - super(minNumTargets, maxNumTargets, filter, notTarget); - } - - private TargetCreaturePermanentOpponentSameController(final TargetCreaturePermanentOpponentSameController target) { - super(target); - } - - @Override - public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (super.canTarget(controllerId, id, source, game)) { - Permanent firstTargetPermanent = game.getPermanent(id); - if (firstTargetPermanent != null - && game.getOpponents(controllerId).contains(firstTargetPermanent.getControllerId())) { - for (UUID targetId : getTargets()) { - Permanent targetPermanent = game.getPermanent(targetId); - if (targetPermanent != null) { - if (!firstTargetPermanent.getId().equals(targetPermanent.getId())) { - if (!firstTargetPermanent.isControlledBy(targetPermanent.getOwnerId())) { - return false; - } - } - } - } - return true; - } - } - return false; - } - - @Override - public TargetCreaturePermanentOpponentSameController copy() { - return new TargetCreaturePermanentOpponentSameController(this); + if (toSacrifice != null) { + permanents.remove(toSacrifice); + toSacrifice.sacrifice(source, game); + } + for (Permanent permanent : permanents) { + permanent.addCounters(CounterType.M1M1.createInstance(), source, game); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/r/RetrieverPhoenix.java b/Mage.Sets/src/mage/cards/r/RetrieverPhoenix.java index 61219940ad9..af5ef5abc79 100644 --- a/Mage.Sets/src/mage/cards/r/RetrieverPhoenix.java +++ b/Mage.Sets/src/mage/cards/r/RetrieverPhoenix.java @@ -1,12 +1,10 @@ package mage.cards.r; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.LearnEffect; import mage.abilities.hint.common.OpenSideboardHint; @@ -41,10 +39,8 @@ public final class RetrieverPhoenix extends CardImpl { this.addAbility(HasteAbility.getInstance()); // When Retriever Phoenix enters the battlefield, if you cast it, learn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new LearnEffect()), CastFromEverywhereSourceCondition.instance, - "When {this} enters, if you cast it, " + LearnEffect.getDefaultText() - ).addHint(OpenSideboardHint.instance)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new LearnEffect()) + .withInterveningIf(CastFromEverywhereSourceCondition.instance).addHint(OpenSideboardHint.instance)); // As long as Retriever Phoenix is in your graveyard, if you would learn, you may instead return Retriever Phoenix to the battlefield. this.addAbility(new SimpleStaticAbility(Zone.GRAVEYARD, new RetrieverPhoenixEffect())); @@ -64,8 +60,8 @@ class RetrieverPhoenixEffect extends ReplacementEffectImpl { RetrieverPhoenixEffect() { super(Duration.WhileInGraveyard, Outcome.PutCreatureInPlay); - staticText = "as long as {this} is in your graveyard, if you would learn, " + - "you may instead return {this} to the battlefield"; + staticText = "as long as this card is in your graveyard, if you would learn, " + + "you may instead return this card to the battlefield"; } private RetrieverPhoenixEffect(final RetrieverPhoenixEffect effect) { diff --git a/Mage.Sets/src/mage/cards/r/RevealingWind.java b/Mage.Sets/src/mage/cards/r/RevealingWind.java index e57804aa3c8..d02d9e8f212 100644 --- a/Mage.Sets/src/mage/cards/r/RevealingWind.java +++ b/Mage.Sets/src/mage/cards/r/RevealingWind.java @@ -17,6 +17,7 @@ import mage.filter.predicate.card.FaceDownPredicate; import mage.game.Game; import mage.players.Player; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -77,7 +78,7 @@ class RevealingWindEffect extends OneShotEffect { if (!controller.canRespond()) { return false; } - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); if (controller.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/r/RevelInRiches.java b/Mage.Sets/src/mage/cards/r/RevelInRiches.java index 4a98b043e30..34bebbde4e5 100644 --- a/Mage.Sets/src/mage/cards/r/RevelInRiches.java +++ b/Mage.Sets/src/mage/cards/r/RevelInRiches.java @@ -1,14 +1,14 @@ package mage.cards.r; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.WinGameSourceControllerEffect; +import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -26,24 +26,22 @@ import java.util.UUID; */ public final class RevelInRiches extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent("Treasures"); - - static { - filter.add(SubType.TREASURE.getPredicate()); - } + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.TREASURE, "you control ten or more Treasures"); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 9); + private static final Hint hint = new ValueHint("Treasures you control", new PermanentsOnBattlefieldCount(filter)); public RevelInRiches(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{B}"); // Whenever a creature an opponent controls dies, create a colorless Treasure artifact token with "{T}, Sacrifice this artifact: Add one mana of any color." - this.addAbility(new DiesCreatureTriggeredAbility(new CreateTokenEffect(new TreasureToken()), false, StaticFilters.FILTER_OPPONENTS_PERMANENT_A_CREATURE)); + this.addAbility(new DiesCreatureTriggeredAbility( + new CreateTokenEffect(new TreasureToken()), false, + StaticFilters.FILTER_OPPONENTS_PERMANENT_A_CREATURE + )); + // At the beginning of your upkeep, if you control ten or more Treasures, you win the game. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - ability, - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 9), - "At the beginning of your upkeep, if you control ten or more Treasures, you win the game.") - .addHint(new ValueHint("Treasures you control", new PermanentsOnBattlefieldCount(filter)))); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect()) + .withInterveningIf(condition).addHint(hint)); } private RevelInRiches(final RevelInRiches card) { diff --git a/Mage.Sets/src/mage/cards/r/RevenantPatriarch.java b/Mage.Sets/src/mage/cards/r/RevenantPatriarch.java index c2da5059104..93ae00b6cb0 100644 --- a/Mage.Sets/src/mage/cards/r/RevenantPatriarch.java +++ b/Mage.Sets/src/mage/cards/r/RevenantPatriarch.java @@ -1,27 +1,25 @@ package mage.cards.r; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.CantBlockAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.ManaWasSpentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.SkipCombatStepEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.ColoredManaSymbol; import mage.constants.Duration; +import mage.constants.SubType; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author ilcartographer */ public final class RevenantPatriarch extends CardImpl { - + public RevenantPatriarch(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); this.subtype.add(SubType.SPIRIT); @@ -29,18 +27,21 @@ public final class RevenantPatriarch extends CardImpl { this.toughness = new MageInt(3); // When Revenant Patriarch enters the battlefield, if {W} was spent to cast it, target player skips their next combat phase. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new SkipCombatStepEffect(Duration.OneUse).setText("target player skips their next combat phase."), false); + Ability ability = new EntersBattlefieldTriggeredAbility( + new SkipCombatStepEffect(Duration.OneUse) + .setText("target player skips their next combat phase.") + ).withInterveningIf(ManaWasSpentCondition.WHITE); ability.addTarget(new TargetPlayer()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, ManaWasSpentCondition.WHITE, - "When {this} enters, if {W} was spent to cast it, target player skips their next combat phase.")); + this.addAbility(ability); + // Revenant Patriarch can't block. this.addAbility(new CantBlockAbility()); } - + private RevenantPatriarch(final RevenantPatriarch card) { super(card); } - + @Override public RevenantPatriarch copy() { return new RevenantPatriarch(this); diff --git a/Mage.Sets/src/mage/cards/r/RhonasTheIndomitable.java b/Mage.Sets/src/mage/cards/r/RhonasTheIndomitable.java index 34ac88a308b..54386f927d0 100644 --- a/Mage.Sets/src/mage/cards/r/RhonasTheIndomitable.java +++ b/Mage.Sets/src/mage/cards/r/RhonasTheIndomitable.java @@ -22,10 +22,13 @@ import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * @author fireshoes */ @@ -55,7 +58,7 @@ public final class RhonasTheIndomitable extends CardImpl { effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); effect.setText("and gains trample until end of turn"); ability.addEffect(effect); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RhoxMeditant.java b/Mage.Sets/src/mage/cards/r/RhoxMeditant.java index 53565f142e9..81b367df20d 100644 --- a/Mage.Sets/src/mage/cards/r/RhoxMeditant.java +++ b/Mage.Sets/src/mage/cards/r/RhoxMeditant.java @@ -1,13 +1,10 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; -import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -16,22 +13,23 @@ import mage.constants.SubType; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class RhoxMeditant extends CardImpl { - - private static final FilterControlledPermanent filter = new FilterControlledPermanent("green permanent"); - + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("you control a green permanent"); + static { filter.add(new ColorPredicate(ObjectColor.GREEN)); } - - private static final String rule = "When {this} enters, if you control a green permanent, draw a card."; + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); public RhoxMeditant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.subtype.add(SubType.RHINO); this.subtype.add(SubType.MONK); @@ -39,9 +37,7 @@ public final class RhoxMeditant extends CardImpl { this.toughness = new MageInt(4); // When Rhox Meditant enters the battlefield, if you control a green permanent, draw a card. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1), false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new PermanentsOnTheBattlefieldCondition(filter), rule)); - + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)).withInterveningIf(condition)); } private RhoxMeditant(final RhoxMeditant card) { diff --git a/Mage.Sets/src/mage/cards/r/RictusRobber.java b/Mage.Sets/src/mage/cards/r/RictusRobber.java index caedfac1ebf..b3eca840cf5 100644 --- a/Mage.Sets/src/mage/cards/r/RictusRobber.java +++ b/Mage.Sets/src/mage/cards/r/RictusRobber.java @@ -3,7 +3,6 @@ package mage.cards.r; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.MorbidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.common.MorbidHint; import mage.abilities.keyword.PlotAbility; @@ -29,11 +28,8 @@ public final class RictusRobber extends CardImpl { this.toughness = new MageInt(3); // When Rictus Robber enters the battlefield, if a creature died this turn, create a 2/2 blue and black Zombie Rogue creature token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ZombieRogueToken())), - MorbidCondition.instance, - "When {this} enters, if a creature died this turn, create a 2/2 blue and black Zombie Rogue creature token." - ).addHint(MorbidHint.instance)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ZombieRogueToken())) + .withInterveningIf(MorbidCondition.instance).addHint(MorbidHint.instance)); // Plot {2}{B} this.addAbility(new PlotAbility("{2}{B}")); diff --git a/Mage.Sets/src/mage/cards/r/RiddlemasterSphinx.java b/Mage.Sets/src/mage/cards/r/RiddlemasterSphinx.java index dd84c95e107..3e575d469bf 100644 --- a/Mage.Sets/src/mage/cards/r/RiddlemasterSphinx.java +++ b/Mage.Sets/src/mage/cards/r/RiddlemasterSphinx.java @@ -11,8 +11,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author TheElk801 @@ -31,7 +34,7 @@ public final class RiddlemasterSphinx extends CardImpl { // When Riddlemaster Sphinx enters the battlefield, you may return target creature an opponent controls to its owner's hand. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RideDown.java b/Mage.Sets/src/mage/cards/r/RideDown.java index aa53517e959..ba2b17c53a7 100644 --- a/Mage.Sets/src/mage/cards/r/RideDown.java +++ b/Mage.Sets/src/mage/cards/r/RideDown.java @@ -17,6 +17,7 @@ import mage.game.Game; import mage.game.combat.CombatGroup; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -37,7 +38,7 @@ public final class RideDown extends CardImpl { // Destroy target blocking creature. Creatures that were blocked by that creature this combat gain trample until end of turn. this.getSpellAbility().addEffect(new RideDownEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } diff --git a/Mage.Sets/src/mage/cards/r/Righteousness.java b/Mage.Sets/src/mage/cards/r/Righteousness.java index 70cbd275712..0a6c6294ede 100644 --- a/Mage.Sets/src/mage/cards/r/Righteousness.java +++ b/Mage.Sets/src/mage/cards/r/Righteousness.java @@ -9,6 +9,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.filter.common.FilterBlockingCreature; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -24,7 +25,7 @@ public final class Righteousness extends CardImpl { this.getSpellAbility().addEffect(new BoostTargetEffect(7, 7, Duration.EndOfTurn)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private Righteousness(final Righteousness card) { diff --git a/Mage.Sets/src/mage/cards/r/RilingDawnbreaker.java b/Mage.Sets/src/mage/cards/r/RilingDawnbreaker.java index 21921919b2b..fdb12b8eb59 100644 --- a/Mage.Sets/src/mage/cards/r/RilingDawnbreaker.java +++ b/Mage.Sets/src/mage/cards/r/RilingDawnbreaker.java @@ -16,6 +16,7 @@ import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.permanent.token.Soldier22Token; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -46,7 +47,7 @@ public final class RilingDawnbreaker extends OmenCard { // At the beginning of combat on your turn, another target creature you control gets +1/+0 until end of turn. Ability ability = new BeginningOfCombatTriggeredAbility(new BoostTargetEffect(1, 0)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Signaling Roar diff --git a/Mage.Sets/src/mage/cards/r/RimehornAurochs.java b/Mage.Sets/src/mage/cards/r/RimehornAurochs.java index 36926fd0039..a31e80e47e7 100644 --- a/Mage.Sets/src/mage/cards/r/RimehornAurochs.java +++ b/Mage.Sets/src/mage/cards/r/RimehornAurochs.java @@ -20,6 +20,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.watchers.common.BlockedAttackerWatcher; @@ -53,8 +54,8 @@ public final class RimehornAurochs extends CardImpl { // {2}{S}: Target creature blocks target creature this turn if able. Ability ability = new SimpleActivatedAbility(new RimehornAurochsEffect(), new ManaCostsImpl<>("{2}{S}")); - ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature that must block"))); - ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature that is to be blocked"))); + ability.addTarget(new TargetPermanent(new FilterCreaturePermanent("creature that must block"))); + ability.addTarget(new TargetPermanent(new FilterCreaturePermanent("creature that is to be blocked"))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RimescaleDragon.java b/Mage.Sets/src/mage/cards/r/RimescaleDragon.java index ebfd7ba63f1..0d6218c7bf2 100644 --- a/Mage.Sets/src/mage/cards/r/RimescaleDragon.java +++ b/Mage.Sets/src/mage/cards/r/RimescaleDragon.java @@ -20,7 +20,6 @@ import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** - * * @author JRHerlehy */ public final class RimescaleDragon extends CardImpl { @@ -33,7 +32,7 @@ public final class RimescaleDragon extends CardImpl { public RimescaleDragon(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}{R}"); - + this.supertype.add(SuperType.SNOW); this.subtype.add(SubType.DRAGON); this.power = new MageInt(5); @@ -50,7 +49,7 @@ public final class RimescaleDragon extends CardImpl { Effect effect = new AddCountersTargetEffect(CounterType.ICE.createInstance()); effect.setText("and put an ice counter on it"); ability.addEffect(effect); - ability.addTarget(new TargetCreaturePermanent(1)); + ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); // Creatures with ice counters on them don't untap during their controllers' untap steps. diff --git a/Mage.Sets/src/mage/cards/r/RimewindCryomancer.java b/Mage.Sets/src/mage/cards/r/RimewindCryomancer.java index 5eeca35b0f8..12588de2d9f 100644 --- a/Mage.Sets/src/mage/cards/r/RimewindCryomancer.java +++ b/Mage.Sets/src/mage/cards/r/RimewindCryomancer.java @@ -1,10 +1,9 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; @@ -12,37 +11,39 @@ import mage.abilities.effects.common.CounterTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; +import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.target.common.TargetActivatedAbility; +import java.util.UUID; + /** - * * @author fireshoes */ public final class RimewindCryomancer extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("you control four or more snow permanents"); + private static final FilterPermanent filter = new FilterControlledPermanent("you control four or more snow permanents"); static { filter.add(SuperType.SNOW.getPredicate()); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 3); + public RimewindCryomancer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(2); this.toughness = new MageInt(3); // {1}, {tap}: Counter target activated ability. Activate this ability only if you control four or more snow permanents. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new CounterTargetEffect(), - new GenericManaCost(1), - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 3)); + Ability ability = new ActivateIfConditionActivatedAbility( + new CounterTargetEffect(), new GenericManaCost(1), condition + ); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetActivatedAbility()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/r/RimewindTaskmage.java b/Mage.Sets/src/mage/cards/r/RimewindTaskmage.java index c0c2a709d71..c1b49f2160e 100644 --- a/Mage.Sets/src/mage/cards/r/RimewindTaskmage.java +++ b/Mage.Sets/src/mage/cards/r/RimewindTaskmage.java @@ -1,10 +1,9 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; @@ -12,15 +11,15 @@ import mage.abilities.effects.common.MayTapOrUntapTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; +import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class RimewindTaskmage extends CardImpl { @@ -31,18 +30,19 @@ public final class RimewindTaskmage extends CardImpl { filter.add(SuperType.SNOW.getPredicate()); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 3); + public RimewindTaskmage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(1); this.toughness = new MageInt(2); // {1}, {tap}: You may tap or untap target permanent. Activate this ability only if you control four or more snow permanents. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new MayTapOrUntapTargetEffect(), - new GenericManaCost(1), - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 3)); + Ability ability = new ActivateIfConditionActivatedAbility( + new MayTapOrUntapTargetEffect(), new GenericManaCost(1), condition + ); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetPermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/r/RiseOfTheDreadMarn.java b/Mage.Sets/src/mage/cards/r/RiseOfTheDreadMarn.java index d43c026d0ba..adb23cf51aa 100644 --- a/Mage.Sets/src/mage/cards/r/RiseOfTheDreadMarn.java +++ b/Mage.Sets/src/mage/cards/r/RiseOfTheDreadMarn.java @@ -4,6 +4,8 @@ import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; import mage.abilities.keyword.ForetellAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -31,6 +33,7 @@ public final class RiseOfTheDreadMarn extends CardImpl { new ZombieBerserkerToken(), RiseOfTheDreadMarnValue.instance )); this.getSpellAbility().addWatcher(new RiseOfTheDreadMarnWatcher()); + this.getSpellAbility().addHint(RiseOfTheDreadMarnValue.getHint()); // Foretell {B} this.addAbility(new ForetellAbility(this, "{B}")); @@ -48,11 +51,18 @@ public final class RiseOfTheDreadMarn extends CardImpl { enum RiseOfTheDreadMarnValue implements DynamicValue { instance; + private static final Hint hint = new ValueHint("Nontoken creatures that died this turn", instance); + + public static Hint getHint() { + return hint; + } @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - RiseOfTheDreadMarnWatcher watcher = game.getState().getWatcher(RiseOfTheDreadMarnWatcher.class); - return watcher != null ? watcher.getCreaturesDied() : 0; + return game + .getState() + .getWatcher(RiseOfTheDreadMarnWatcher.class) + .getCreaturesDied(); } @Override @@ -81,9 +91,13 @@ class RiseOfTheDreadMarnWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.ZONE_CHANGE - && ((ZoneChangeEvent) event).isDiesEvent() - && !(((ZoneChangeEvent) event).getTarget() instanceof PermanentToken)) { + if (event.getType() != GameEvent.EventType.ZONE_CHANGE) { + return; + } + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.isDiesEvent() + && zEvent.getTarget().isCreature(game) + && !(zEvent.getTarget() instanceof PermanentToken)) { creaturesDied += 1; } } diff --git a/Mage.Sets/src/mage/cards/r/RisonaAsariCommander.java b/Mage.Sets/src/mage/cards/r/RisonaAsariCommander.java index bd0bbdeba0a..ca678994940 100644 --- a/Mage.Sets/src/mage/cards/r/RisonaAsariCommander.java +++ b/Mage.Sets/src/mage/cards/r/RisonaAsariCommander.java @@ -45,7 +45,7 @@ public final class RisonaAsariCommander extends CardImpl { // Whenever Risona, Asari Commander deals combat damage to a player, if it doesn't have an indestructible counter on it, put an indestructible counter on it. this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new AddCountersSourceEffect( CounterType.INDESTRUCTIBLE.createInstance()), false - ).withInterveningIf(RisonaAsariCommanderCondition.instance)); + ).withInterveningIf(RisonaAsariCommanderCondition.instance).withRuleTextReplacement(true)); // Whenever combat damage is dealt to you, remove an indestructible counter from Risona. this.addAbility(new RisonaAsariCommanderTriggeredAbility()); diff --git a/Mage.Sets/src/mage/cards/r/RitesOfReaping.java b/Mage.Sets/src/mage/cards/r/RitesOfReaping.java index f44dd378d39..42a3bce85af 100644 --- a/Mage.Sets/src/mage/cards/r/RitesOfReaping.java +++ b/Mage.Sets/src/mage/cards/r/RitesOfReaping.java @@ -1,45 +1,31 @@ - package mage.cards.r; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.other.AnotherTargetPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class RitesOfReaping extends CardImpl { public RitesOfReaping(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{B}{G}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}{G}"); // Target creature gets +3/+3 until end of turn. Another target creature gets -3/-3 until end of turn. - this.getSpellAbility().addEffect(new RitesOfReapingEffect()); - - FilterCreaturePermanent filter1 = new FilterCreaturePermanent("creature (gets +3/+3 until end of turn)"); - TargetCreaturePermanent target1 = new TargetCreaturePermanent(filter1); - target1.setTargetTag(1); - this.getSpellAbility().addTarget(target1); - - FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another creature (gets -3/-3 until end of turn)"); - filter2.add(new AnotherTargetPredicate(2)); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter2); - target2.setTargetTag(2); - this.getSpellAbility().addTarget(target2); + this.getSpellAbility().addEffect(new BoostTargetEffect(3, 3)); + this.getSpellAbility().addEffect(new BoostTargetEffect(-3, -3) + .setTargetPointer(new SecondTargetPointer()) + .setText("Another target creature gets -3/-3 until end of turn")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("+3/+3").setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2).withChooseHint("-3/-3").setTargetTag(2)); } private RitesOfReaping(final RitesOfReaping card) { @@ -51,35 +37,3 @@ public final class RitesOfReaping extends CardImpl { return new RitesOfReaping(this); } } - -class RitesOfReapingEffect extends ContinuousEffectImpl { - - RitesOfReapingEffect() { - super(Duration.EndOfTurn, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.BoostCreature); - this.staticText = "Target creature gets +3/+3 until end of turn. Another target creature gets -3/-3 until end of turn"; - } - - private RitesOfReapingEffect(final RitesOfReapingEffect effect) { - super(effect); - } - - @Override - public RitesOfReapingEffect copy() { - return new RitesOfReapingEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent != null) { - permanent.addPower(3); - permanent.addToughness(3); - } - permanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - if (permanent != null) { - permanent.addPower(-3); - permanent.addToughness(-3); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/r/RitualGuardian.java b/Mage.Sets/src/mage/cards/r/RitualGuardian.java index 4b0e08f5126..df4d4403494 100644 --- a/Mage.Sets/src/mage/cards/r/RitualGuardian.java +++ b/Mage.Sets/src/mage/cards/r/RitualGuardian.java @@ -1,15 +1,17 @@ package mage.cards.r; import mage.MageInt; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.common.CovenCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.hint.common.CovenHint; import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import java.util.UUID; @@ -27,14 +29,9 @@ public final class RitualGuardian extends CardImpl { this.toughness = new MageInt(2); // Coven — At the beginning of combat on your turn, if you control three or more creatures with different powers, Ritual Guardian gains lifelink until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - new GainAbilitySourceEffect( - LifelinkAbility.getInstance(), Duration.EndOfTurn - ) - ), CovenCondition.instance, "At the beginning of combat on your turn, if you control three " + - "or more creatures with different powers, {this} gains lifelink until end of turn." - ).addHint(CovenHint.instance).setAbilityWord(AbilityWord.COVEN)); + this.addAbility(new BeginningOfCombatTriggeredAbility(new GainAbilitySourceEffect( + LifelinkAbility.getInstance(), Duration.EndOfTurn + )).withInterveningIf(CovenCondition.instance).addHint(CovenHint.instance).setAbilityWord(AbilityWord.COVEN)); } private RitualGuardian(final RitualGuardian card) { diff --git a/Mage.Sets/src/mage/cards/r/RitualOfTheMachine.java b/Mage.Sets/src/mage/cards/r/RitualOfTheMachine.java index e53f1fd0d7a..f341cf356c1 100644 --- a/Mage.Sets/src/mage/cards/r/RitualOfTheMachine.java +++ b/Mage.Sets/src/mage/cards/r/RitualOfTheMachine.java @@ -13,6 +13,7 @@ import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; @@ -36,7 +37,7 @@ public final class RitualOfTheMachine extends CardImpl { this.getSpellAbility().addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE)); // Gain control of target nonartifact, nonblack creature. this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfGame)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private RitualOfTheMachine(final RitualOfTheMachine card) { diff --git a/Mage.Sets/src/mage/cards/r/Rivalry.java b/Mage.Sets/src/mage/cards/r/Rivalry.java index a65b63d7836..901ad55322b 100644 --- a/Mage.Sets/src/mage/cards/r/Rivalry.java +++ b/Mage.Sets/src/mage/cards/r/Rivalry.java @@ -1,7 +1,6 @@ package mage.cards.r; -import java.util.UUID; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; @@ -12,9 +11,10 @@ import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** * * @author Plopman @@ -87,6 +87,6 @@ class RivalryTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "At the beginning of each player's upkeep, if that player controls more lands than each other player, Rivalry deals 2 damage to them."; + return "At the beginning of each player's upkeep, if that player controls more lands than each other player, {this} deals 2 damage to them."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/r/RivalsDuel.java b/Mage.Sets/src/mage/cards/r/RivalsDuel.java index ce690c589b0..8e4851faec7 100644 --- a/Mage.Sets/src/mage/cards/r/RivalsDuel.java +++ b/Mage.Sets/src/mage/cards/r/RivalsDuel.java @@ -1,19 +1,23 @@ package mage.cards.r; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.filter.StaticFilters; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetCreaturePermanentWithDifferentTypes; +import mage.target.TargetPermanent; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; /** - * * @author LevelX2 */ public final class RivalsDuel extends CardImpl { @@ -22,9 +26,8 @@ public final class RivalsDuel extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}"); // Choose two target creatures that share no creature types. Those creatures fight each other. - this.getSpellAbility().addEffect(new RivalsDuelFightTargetsEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanentWithDifferentTypes(2, 2, StaticFilters.FILTER_PERMANENT_CREATURE, false)); - + this.getSpellAbility().addEffect(new RivalsDuelEffect()); + this.getSpellAbility().addTarget(new RivalsDuelTarget()); } private RivalsDuel(final RivalsDuel card) { @@ -37,42 +40,68 @@ public final class RivalsDuel extends CardImpl { } } -class RivalsDuelFightTargetsEffect extends OneShotEffect { +class RivalsDuelEffect extends OneShotEffect { - RivalsDuelFightTargetsEffect() { - super(Outcome.Damage); - staticText = "Choose two target creatures that share no creature types. " + - "Those creatures fight each other. (Each deals damage equal to its power to the other.)"; + RivalsDuelEffect() { + super(Outcome.Benefit); + staticText = "choose two target creatures that share no creature types. Those creatures fight each other"; } - private RivalsDuelFightTargetsEffect(final RivalsDuelFightTargetsEffect effect) { + private RivalsDuelEffect(final RivalsDuelEffect effect) { super(effect); } @Override - public boolean apply(Game game, Ability source) { - Permanent creature1 = null; - Permanent creature2 = null; - for (UUID targetId : getTargetPointer().getTargets(game, source)) { - if (creature1 == null) { - creature1 = game.getPermanent(targetId); - } else { - creature2 = game.getPermanent(targetId); - } - } - - // 20110930 - 701.10 - if (creature1 != null - && creature2 != null) { - creature1.damage(creature2.getPower().getValue(), creature2.getId(), source, game, false, true); - creature2.damage(creature1.getPower().getValue(), creature1.getId(), source, game, false, true); - return true; - } - return false; + public RivalsDuelEffect copy() { + return new RivalsDuelEffect(this); } @Override - public RivalsDuelFightTargetsEffect copy() { - return new RivalsDuelFightTargetsEffect(this); + public boolean apply(Game game, Ability source) { + List permanents = this + .getTargetPointer() + .getTargets(game, source) + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + System.out.println(permanents.size()); + System.out.println(permanents.get(0)); + System.out.println(permanents.get(1)); + return permanents.size() >= 2 && permanents.get(0).fight(permanents.get(1), source, game); + } +} + +class RivalsDuelTarget extends TargetPermanent { + + private static final FilterPermanent filter = new FilterCreaturePermanent("creatures that share no creature types"); + + RivalsDuelTarget() { + super(2, 2, filter, false); + } + + private RivalsDuelTarget(final RivalsDuelTarget target) { + super(target); + } + + @Override + public RivalsDuelTarget copy() { + return new RivalsDuelTarget(this); + } + + @Override + public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { + if (!super.canTarget(controllerId, id, source, game)) { + return false; + } + Permanent creature = game.getPermanent(id); + return creature != null + && this + .getTargets() + .stream() + .filter(uuid -> !id.equals(uuid)) + .map(game::getPermanent) + .filter(Objects::nonNull) + .noneMatch(permanent -> permanent.shareCreatureTypes(game, creature)); } } diff --git a/Mage.Sets/src/mage/cards/r/Rivendell.java b/Mage.Sets/src/mage/cards/r/Rivendell.java index 4a797a90182..2f0d377e354 100644 --- a/Mage.Sets/src/mage/cards/r/Rivendell.java +++ b/Mage.Sets/src/mage/cards/r/Rivendell.java @@ -12,7 +12,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; @@ -44,9 +43,7 @@ public final class Rivendell extends CardImpl { // {1}{U}, {T}: Scry 2. Activate only if you control a legendary creature. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new ScryEffect(2, false), - new ManaCostsImpl<>("{1}{U}"), condition + new ScryEffect(2, false), new ManaCostsImpl<>("{1}{U}"), condition ); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/r/RiverHeraldsBoon.java b/Mage.Sets/src/mage/cards/r/RiverHeraldsBoon.java index 947e3f67893..6ae8b33d170 100644 --- a/Mage.Sets/src/mage/cards/r/RiverHeraldsBoon.java +++ b/Mage.Sets/src/mage/cards/r/RiverHeraldsBoon.java @@ -1,36 +1,34 @@ - package mage.cards.r; -import java.util.UUID; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.FilterPermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.SecondTargetPointer; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class RiverHeraldsBoon extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent(SubType.MERFOLK, "Merfolk"); + public RiverHeraldsBoon(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); // Put a +1/+1 counter on target creature and a +1/+1 counter on up to one target Merfolk. this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); - effect.setTargetPointer(new SecondTargetPointer()); - effect.setText("and a +1/+1 counter on up to one target Merfolk"); - this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1, new FilterCreaturePermanent(SubType.MERFOLK, "Merfolk"), false)); - + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance()) + .setTargetPointer(new SecondTargetPointer()).setText("and a +1/+1 counter on up to one target Merfolk")); + this.getSpellAbility().addTarget(new TargetPermanent(0, 1, filter)); } private RiverHeraldsBoon(final RiverHeraldsBoon card) { diff --git a/Mage.Sets/src/mage/cards/r/RixMaadiGuildmage.java b/Mage.Sets/src/mage/cards/r/RixMaadiGuildmage.java index d1e671cd5fb..56e662f6d52 100644 --- a/Mage.Sets/src/mage/cards/r/RixMaadiGuildmage.java +++ b/Mage.Sets/src/mage/cards/r/RixMaadiGuildmage.java @@ -19,6 +19,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicate; import mage.game.Game; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; import mage.watchers.common.PlayerLostLifeWatcher; @@ -45,7 +46,7 @@ public final class RixMaadiGuildmage extends CardImpl { // {B}{R}: Target blocking creature gets -1/-1 until end of turn. SimpleActivatedAbility ability = new SimpleActivatedAbility(new BoostTargetEffect(-1, -1, Duration.EndOfTurn),new ManaCostsImpl<>("{B}{R}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // {B}{R}: Target player who lost life this turn loses 1 life. diff --git a/Mage.Sets/src/mage/cards/r/RoamingGhostlight.java b/Mage.Sets/src/mage/cards/r/RoamingGhostlight.java index 3eb1a648a1b..7a127b1ac3a 100644 --- a/Mage.Sets/src/mage/cards/r/RoamingGhostlight.java +++ b/Mage.Sets/src/mage/cards/r/RoamingGhostlight.java @@ -11,7 +11,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -38,7 +38,7 @@ public final class RoamingGhostlight extends CardImpl { // When Roaming Ghostlight enters the battlefield, return up to one target non-Spirit creature to its owner's hand. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()); - ability.addTarget(new TargetCreaturePermanent(0, 1, filter, false)); + ability.addTarget(new TargetPermanent(0, 1, filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RoaringPrimadox.java b/Mage.Sets/src/mage/cards/r/RoaringPrimadox.java index 48cadc0c2e3..2dae20f86ce 100644 --- a/Mage.Sets/src/mage/cards/r/RoaringPrimadox.java +++ b/Mage.Sets/src/mage/cards/r/RoaringPrimadox.java @@ -1,31 +1,32 @@ package mage.cards.r; -import java.util.UUID; import mage.MageInt; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.effects.common.ReturnToHandChosenControlledPermanentEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.game.events.GameEvent.EventType; + +import java.util.UUID; /** - * * @author North */ public final class RoaringPrimadox extends CardImpl { public RoaringPrimadox(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); this.subtype.add(SubType.BEAST); this.power = new MageInt(4); this.toughness = new MageInt(4); // At the beginning of your upkeep, return a creature you control to its owner's hand. - this.addAbility(new OnEventTriggeredAbility(EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", new ReturnToHandChosenControlledPermanentEffect(StaticFilters.FILTER_CONTROLLED_CREATURE))); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new ReturnToHandChosenControlledPermanentEffect(StaticFilters.FILTER_CONTROLLED_CREATURE) + )); } private RoaringPrimadox(final RoaringPrimadox card) { diff --git a/Mage.Sets/src/mage/cards/r/Roast.java b/Mage.Sets/src/mage/cards/r/Roast.java index 2a1f2d55e15..a030625ce49 100644 --- a/Mage.Sets/src/mage/cards/r/Roast.java +++ b/Mage.Sets/src/mage/cards/r/Roast.java @@ -10,6 +10,7 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class Roast extends CardImpl { // Roast deals 5 damage to target creature without flying. this.getSpellAbility().addEffect(new DamageTargetEffect(5)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private Roast(final Roast card) { diff --git a/Mage.Sets/src/mage/cards/r/RobberOfTheRich.java b/Mage.Sets/src/mage/cards/r/RobberOfTheRich.java index 2ab326cebe2..7bbfbffefe4 100644 --- a/Mage.Sets/src/mage/cards/r/RobberOfTheRich.java +++ b/Mage.Sets/src/mage/cards/r/RobberOfTheRich.java @@ -4,9 +4,12 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.decorator.ConditionalAsThoughEffect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; +import mage.abilities.effects.common.asthought.YouMaySpendManaAsAnyColorToCastTargetEffect; import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.ReachAbility; import mage.cards.Card; @@ -15,20 +18,20 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.game.Game; import mage.players.Player; +import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; import mage.watchers.common.AttackedThisTurnWatcher; + import java.util.Objects; import java.util.UUID; -import mage.abilities.decorator.ConditionalAsThoughEffect; -import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; -import mage.abilities.effects.common.asthought.YouMaySpendManaAsAnyColorToCastTargetEffect; -import mage.target.targetpointer.FixedTarget; /** * @author TheElk801 */ public final class RobberOfTheRich extends CardImpl { + private static final Hint hint = new ConditionHint(new RogueAttackedThisTurnCondition(null)); + public RobberOfTheRich(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); @@ -45,14 +48,9 @@ public final class RobberOfTheRich extends CardImpl { this.addAbility(HasteAbility.getInstance()); // Whenever Robber of the Rich attacks, if defending player has more cards in hand than you, exile the top card of their library. During any turn you attacked with a Rogue, you may cast that card and you may spend mana as though it were mana of any color to cast that spell. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility( - new RobberOfTheRichEffect(), false, "", SetTargetPointer.PLAYER - ), RobberOfTheRichAttacksCondition.instance, "Whenever {this} attacks, " + - "if defending player has more cards in hand than you, exile the top card of their library. " + - "During any turn you attacked with a Rogue, you may cast that card and " + - "you may spend mana as though it were mana of any color to cast that spell." - ).addHint(new ConditionHint(new RogueAttackedThisTurnCondition(null)))); + this.addAbility(new AttacksTriggeredAbility( + new RobberOfTheRichEffect(), false, "", SetTargetPointer.PLAYER + ).withInterveningIf(RobberOfTheRichAttacksCondition.instance).addHint(hint)); } private RobberOfTheRich(final RobberOfTheRich card) { @@ -72,16 +70,21 @@ enum RobberOfTheRichAttacksCondition implements Condition { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(game.getCombat().getDefendingPlayerId(source.getSourceId(), game)); - return controller != null - && player != null + return controller != null + && player != null && controller.getHand().size() < player.getHand().size(); } + + @Override + public String toString() { + return "defending player has more cards in hand than you"; + } } class RogueAttackedThisTurnCondition implements Condition { - + private Ability ability; - + RogueAttackedThisTurnCondition(Ability source) { this.ability = source; } @@ -108,7 +111,7 @@ class RogueAttackedThisTurnCondition implements Condition { @Override public String toString() { - return "During that turn you attacked with a Rogue"; + return "You attacked with a Rogue this turn"; } } @@ -116,6 +119,8 @@ class RobberOfTheRichEffect extends OneShotEffect { RobberOfTheRichEffect() { super(Outcome.Benefit); + staticText = "exile the top card of their library. During any turn you attacked with a Rogue, " + + "you may cast that card and you may spend mana as though it were mana of any color to cast that spell"; } private RobberOfTheRichEffect(final RobberOfTheRichEffect effect) { @@ -131,7 +136,7 @@ class RobberOfTheRichEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Player damagedPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); - if (controller == null + if (controller == null || damagedPlayer == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/r/RocCharger.java b/Mage.Sets/src/mage/cards/r/RocCharger.java index 7a7212decae..1dee9925353 100644 --- a/Mage.Sets/src/mage/cards/r/RocCharger.java +++ b/Mage.Sets/src/mage/cards/r/RocCharger.java @@ -14,6 +14,7 @@ import mage.constants.Duration; import mage.filter.common.FilterAttackingCreature; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -46,7 +47,7 @@ public final class RocCharger extends CardImpl { Duration.EndOfTurn ), false ); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RoccoCabarettiCaterer.java b/Mage.Sets/src/mage/cards/r/RoccoCabarettiCaterer.java index 16307357db7..a5cd42f5e3e 100644 --- a/Mage.Sets/src/mage/cards/r/RoccoCabarettiCaterer.java +++ b/Mage.Sets/src/mage/cards/r/RoccoCabarettiCaterer.java @@ -3,7 +3,6 @@ package mage.cards.r; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.cards.Card; @@ -42,16 +41,9 @@ public final class RoccoCabarettiCaterer extends CardImpl { this.toughness = new MageInt(1); // When Rocco, Cabaretti Caterer enters the battlefield, if you cast it, you may search your library for a creature card with mana value X or less, put it onto the battlefield, then shuffle. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility( - new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter)), - true - ), - CastFromEverywhereSourceCondition.instance, - "When {this} enters, " + - "if you cast it, you may search your library for a creature card with mana value X or less, " + - "put it onto the battlefield, then shuffle.") - ); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter)), true + ).withInterveningIf(CastFromEverywhereSourceCondition.instance)); } private RoccoCabarettiCaterer(final RoccoCabarettiCaterer card) { diff --git a/Mage.Sets/src/mage/cards/r/RockHydra.java b/Mage.Sets/src/mage/cards/r/RockHydra.java index dc794a77e46..d384833e68e 100644 --- a/Mage.Sets/src/mage/cards/r/RockHydra.java +++ b/Mage.Sets/src/mage/cards/r/RockHydra.java @@ -1,6 +1,5 @@ package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; @@ -8,7 +7,7 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.PreventionEffectImpl; import mage.abilities.effects.common.EntersBattlefieldWithXCountersEffect; import mage.abilities.effects.common.PreventDamageToSourceEffect; @@ -16,36 +15,43 @@ import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.PhaseStep; -import mage.constants.Zone; +import mage.constants.SubType; import mage.counters.CounterType; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author anonymous */ public final class RockHydra extends CardImpl { public RockHydra(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{X}{R}{R}"); - + this.subtype.add(SubType.HYDRA); this.power = new MageInt(0); this.toughness = new MageInt(0); - + // Rock Hydra enters the battlefield with X +1/+1 counters on it. this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.P1P1.createInstance()))); + // For each 1 damage that would be dealt to Rock Hydra, if it has a +1/+1 counter on it, remove a +1/+1 counter from it and prevent that 1 damage. this.addAbility(new SimpleStaticAbility(new RockHydraEffect())); + // {R}: Prevent the next 1 damage that would be dealt to Rock Hydra this turn. - this.addAbility(new SimpleActivatedAbility(new PreventDamageToSourceEffect(Duration.EndOfTurn, 1), new ManaCostsImpl<>("{R}"))); + this.addAbility(new SimpleActivatedAbility( + new PreventDamageToSourceEffect(Duration.EndOfTurn, 1), new ManaCostsImpl<>("{R}") + )); + // {R}{R}{R}: Put a +1/+1 counter on Rock Hydra. Activate this ability only during your upkeep. - this.addAbility(new ConditionalActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), new ManaCostsImpl<>("{R}{R}{R}"), new IsStepCondition(PhaseStep.UPKEEP), null)); + this.addAbility(new ActivateIfConditionActivatedAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), + new ManaCostsImpl<>("{R}{R}{R}"), IsStepCondition.getMyUpkeep() + )); } private RockHydra(final RockHydra card) { @@ -95,5 +101,4 @@ class RockHydraEffect extends PreventionEffectImpl { } return false; } - } diff --git a/Mage.Sets/src/mage/cards/r/RocketLauncher.java b/Mage.Sets/src/mage/cards/r/RocketLauncher.java index 810db5ba37f..f5fcb40b204 100644 --- a/Mage.Sets/src/mage/cards/r/RocketLauncher.java +++ b/Mage.Sets/src/mage/cards/r/RocketLauncher.java @@ -4,14 +4,13 @@ import mage.abilities.Ability; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DestroySourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetAnyTarget; @@ -27,9 +26,9 @@ public final class RocketLauncher extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // {2}: Rocket Launcher deals 1 damage to any target. Destroy Rocket Launcher at the beginning of the next end step. Activate this ability only if you've controlled Rocket Launcher continuously since the beginning of your most recent turn. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new DamageTargetEffect(1), - new GenericManaCost(2), RocketLauncherCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DamageTargetEffect(1), new GenericManaCost(2), RocketLauncherCondition.instance + ); ability.addTarget(new TargetAnyTarget()); ability.addEffect(new CreateDelayedTriggeredAbilityEffect( new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new DestroySourceEffect()) diff --git a/Mage.Sets/src/mage/cards/r/RoonOfTheHiddenRealm.java b/Mage.Sets/src/mage/cards/r/RoonOfTheHiddenRealm.java index b28621a44f0..16e517a6fd9 100644 --- a/Mage.Sets/src/mage/cards/r/RoonOfTheHiddenRealm.java +++ b/Mage.Sets/src/mage/cards/r/RoonOfTheHiddenRealm.java @@ -15,10 +15,13 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * @author LevelX2 */ @@ -39,7 +42,7 @@ public final class RoonOfTheHiddenRealm extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // {2}, {tap}: Exile another target creature. Return that card to the battlefield under its owner's control at the beginning of the next end step. Ability ability = new SimpleActivatedAbility(new ExileReturnBattlefieldNextEndStepTargetEffect(), new GenericManaCost(2)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/r/RoostOfDrakes.java b/Mage.Sets/src/mage/cards/r/RoostOfDrakes.java index ac97dd237b2..adbe06fb6b1 100644 --- a/Mage.Sets/src/mage/cards/r/RoostOfDrakes.java +++ b/Mage.Sets/src/mage/cards/r/RoostOfDrakes.java @@ -3,7 +3,6 @@ package mage.cards.r; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; @@ -26,11 +25,7 @@ public final class RoostOfDrakes extends CardImpl { this.addAbility(new KickerAbility("{2}{U}")); // When Roost of Drakes enters the battlefield, if it was kicked, create a 2/2 blue Drake creature token with flying. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new DrakeToken())), - KickedCondition.ONCE, "When {this} enters, if it was kicked, " + - "create a 2/2 blue Drake creature token with flying." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new DrakeToken())).withInterveningIf(KickedCondition.ONCE)); // Whenever you cast a kicked spell, create a 2/2 blue Drake creature token with flying. this.addAbility(new SpellCastControllerTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/r/RootKinAlly.java b/Mage.Sets/src/mage/cards/r/RootKinAlly.java index a3ae36850e9..f4e8e217bed 100644 --- a/Mage.Sets/src/mage/cards/r/RootKinAlly.java +++ b/Mage.Sets/src/mage/cards/r/RootKinAlly.java @@ -1,7 +1,5 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapTargetCost; @@ -10,26 +8,27 @@ import mage.abilities.keyword.ConvokeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author emerald000 */ public final class RootKinAlly extends CardImpl { - + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); + static { filter.add(TappedPredicate.UNTAPPED); } public RootKinAlly(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); this.subtype.add(SubType.ELEMENTAL); this.subtype.add(SubType.WARRIOR); this.power = new MageInt(3); @@ -37,9 +36,12 @@ public final class RootKinAlly extends CardImpl { // Convoke this.addAbility(new ConvokeAbility()); - + // Tap two untapped creatures you control: Root-Kin Ally gets +2/+2 until end of turn. - this.addAbility(new SimpleActivatedAbility(new BoostSourceEffect(2, 2, Duration.EndOfTurn), new TapTargetCost(new TargetControlledCreaturePermanent(2, 2, filter, true)))); + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(2, 2, Duration.EndOfTurn), + new TapTargetCost(2, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES) + )); } private RootKinAlly(final RootKinAlly card) { diff --git a/Mage.Sets/src/mage/cards/r/Roots.java b/Mage.Sets/src/mage/cards/r/Roots.java index de83cbf0074..d142c1bd402 100644 --- a/Mage.Sets/src/mage/cards/r/Roots.java +++ b/Mage.Sets/src/mage/cards/r/Roots.java @@ -38,7 +38,7 @@ public final class Roots extends CardImpl { this.subtype.add(SubType.AURA); // Enchant creature without flying - TargetPermanent auraTarget = new TargetCreaturePermanent(filter); + TargetPermanent auraTarget = new TargetPermanent(filter); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); this.addAbility(new EnchantAbility(auraTarget)); diff --git a/Mage.Sets/src/mage/cards/r/RoseCutthroatRaider.java b/Mage.Sets/src/mage/cards/r/RoseCutthroatRaider.java index 598e86ea29e..0144f57bf14 100644 --- a/Mage.Sets/src/mage/cards/r/RoseCutthroatRaider.java +++ b/Mage.Sets/src/mage/cards/r/RoseCutthroatRaider.java @@ -2,21 +2,16 @@ package mage.cards.r; import mage.MageInt; import mage.Mana; -import mage.abilities.Ability; import mage.abilities.common.EndOfCombatTriggeredAbility; import mage.abilities.common.SacrificePermanentTriggeredAbility; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.AttackedThisTurnOpponentsCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.mana.AddManaToManaPoolSourceControllerEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AbilityWord; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.constants.*; import mage.filter.FilterPermanent; import mage.game.permanent.token.JunkToken; import mage.watchers.common.PlayerAttackedWatcher; @@ -47,17 +42,14 @@ public final class RoseCutthroatRaider extends CardImpl { this.addAbility(FirstStrikeAbility.getInstance()); // Raid -- At end of combat on your turn, if you attacked this turn, create a Junk token for each opponent you attacked. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new EndOfCombatTriggeredAbility( - new CreateTokenEffect(new JunkToken(), AttackedThisTurnOpponentsCount.instance), false), RaidCondition.instance, - "At end of combat on your turn, if you attacked this turn, create a Junk token for each opponent you attacked."); - ability.setAbilityWord(AbilityWord.RAID); - ability.addHint(AttackedThisTurnOpponentsCount.getHint()); - ability.addWatcher(new PlayerAttackedWatcher()); - ability.addWatcher(new PlayersAttackedThisTurnWatcher()); - this.addAbility(ability); + this.addAbility(new EndOfCombatTriggeredAbility( + new CreateTokenEffect(new JunkToken(), AttackedThisTurnOpponentsCount.instance) + .setText("create a Junk token for each opponent you attacked"), + TargetController.YOU, false + ).withInterveningIf(RaidCondition.instance).setAbilityWord(AbilityWord.RAID).addHint(AttackedThisTurnOpponentsCount.getHint()), new PlayersAttackedThisTurnWatcher()); // Whenever you sacrifice a Junk, add {R}. - this.addAbility(new SacrificePermanentTriggeredAbility(new AddManaToManaPoolSourceControllerEffect(Mana.RedMana(1)), filter)); + this.addAbility(new SacrificePermanentTriggeredAbility(new AddManaToManaPoolSourceControllerEffect(Mana.RedMana(1)), filter), new PlayerAttackedWatcher()); } private RoseCutthroatRaider(final RoseCutthroatRaider card) { diff --git a/Mage.Sets/src/mage/cards/r/RoughTumble.java b/Mage.Sets/src/mage/cards/r/RoughTumble.java index fd631dc43d1..c1a815ec844 100644 --- a/Mage.Sets/src/mage/cards/r/RoughTumble.java +++ b/Mage.Sets/src/mage/cards/r/RoughTumble.java @@ -1,7 +1,6 @@ package mage.cards.r; -import java.util.UUID; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.keyword.FlyingAbility; @@ -13,6 +12,8 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; +import java.util.UUID; + /** * * @author LevelX2 @@ -33,13 +34,13 @@ public final class RoughTumble extends SplitCard { // Rough // Rough deals 2 damage to each creature without flying. Effect effect = new DamageAllEffect(2, filterWithoutFlying); - effect.setText("Rough deals 2 damage to each creature without flying"); + effect.setText("{this} deals 2 damage to each creature without flying"); getLeftHalfCard().getSpellAbility().addEffect(effect); // Tumble // Tumble deals 6 damage to each creature with flying. effect = new DamageAllEffect(6, filterFlying); - effect.setText("Tumble deals 6 damage to each creature with flying"); + effect.setText("{this} deals 6 damage to each creature with flying"); getRightHalfCard().getSpellAbility().addEffect(effect); } diff --git a/Mage.Sets/src/mage/cards/r/RoyalAssassin.java b/Mage.Sets/src/mage/cards/r/RoyalAssassin.java index f806d427d94..5f49fe6c56e 100644 --- a/Mage.Sets/src/mage/cards/r/RoyalAssassin.java +++ b/Mage.Sets/src/mage/cards/r/RoyalAssassin.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class RoyalAssassin extends CardImpl { this.toughness = new MageInt(1); Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RoyalDecree.java b/Mage.Sets/src/mage/cards/r/RoyalDecree.java index 1c0b51e1a83..f6777e24c23 100644 --- a/Mage.Sets/src/mage/cards/r/RoyalDecree.java +++ b/Mage.Sets/src/mage/cards/r/RoyalDecree.java @@ -1,7 +1,6 @@ package mage.cards.r; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.costs.mana.ManaCostsImpl; @@ -22,6 +21,8 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** * * @author L_J @@ -94,6 +95,6 @@ class RoyalDecreeAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever a Swamp, Mountain, black permanent, or red permanent becomes tapped, Royal Decree deals 1 damage to that permanent's controller."; + return "Whenever a Swamp, Mountain, black permanent, or red permanent becomes tapped, {this} deals 1 damage to that permanent's controller."; } } diff --git a/Mage.Sets/src/mage/cards/r/RubblebeltBraggart.java b/Mage.Sets/src/mage/cards/r/RubblebeltBraggart.java index c6a955abe55..b354f3fde00 100644 --- a/Mage.Sets/src/mage/cards/r/RubblebeltBraggart.java +++ b/Mage.Sets/src/mage/cards/r/RubblebeltBraggart.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.SuspectSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -29,11 +28,8 @@ public final class RubblebeltBraggart extends CardImpl { this.toughness = new MageInt(5); // Whenever Rubblebelt Braggart attacks, if it's not suspected, you may suspect it. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new SuspectSourceEffect(), true), - RubblebeltBraggartCondition.instance, "Whenever {this} attacks, " + - "if it's not suspected, you may suspect it." - )); + this.addAbility(new AttacksTriggeredAbility(new SuspectSourceEffect(), true) + .withInterveningIf(RubblebeltBraggartCondition.instance)); } private RubblebeltBraggart(final RubblebeltBraggart card) { @@ -53,7 +49,12 @@ enum RubblebeltBraggartCondition implements Condition { public boolean apply(Game game, Ability source) { return Optional .ofNullable(source.getSourcePermanentIfItStillExists(game)) - .map(permanent -> !permanent.isSuspected()) - .orElse(false); + .filter(permanent -> !permanent.isSuspected()) + .isPresent(); + } + + @Override + public String toString() { + return "it's not suspected"; } } diff --git a/Mage.Sets/src/mage/cards/r/RuinRaider.java b/Mage.Sets/src/mage/cards/r/RuinRaider.java index 80449a637c7..dee50a5af80 100644 --- a/Mage.Sets/src/mage/cards/r/RuinRaider.java +++ b/Mage.Sets/src/mage/cards/r/RuinRaider.java @@ -1,12 +1,10 @@ package mage.cards.r; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.RevealPutInHandLoseLifeEffect; import mage.abilities.hint.common.RaidHint; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; @@ -30,16 +28,8 @@ public final class RuinRaider extends CardImpl { this.toughness = new MageInt(2); // Raid — At the beginning of your end step, if you attacked this turn, reveal the top card of your library and put that card into your hand. You lose life equal to the card's converted mana cost. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - new RevealPutInHandLoseLifeEffect() - ), RaidCondition.instance, "At the beginning of your end step, " + - "if you attacked this turn, reveal the top card of your library " + - "and put that card into your hand. You lose life equal to the card's mana value." - ); - ability.setAbilityWord(AbilityWord.RAID); - ability.addHint(RaidHint.instance); - this.addAbility(ability, new PlayerAttackedWatcher()); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new RevealPutInHandLoseLifeEffect()) + .withInterveningIf(RaidCondition.instance).setAbilityWord(AbilityWord.RAID).addHint(RaidHint.instance), new PlayerAttackedWatcher()); } private RuinRaider(final RuinRaider card) { diff --git a/Mage.Sets/src/mage/cards/r/RuinsOfOranRief.java b/Mage.Sets/src/mage/cards/r/RuinsOfOranRief.java index b1890609b7b..5968ca5623d 100644 --- a/Mage.Sets/src/mage/cards/r/RuinsOfOranRief.java +++ b/Mage.Sets/src/mage/cards/r/RuinsOfOranRief.java @@ -16,6 +16,7 @@ import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorlessPredicate; import mage.filter.predicate.permanent.EnteredThisTurnPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class RuinsOfOranRief extends CardImpl { this.addAbility(new ColorlessManaAbility()); // {T}: Put a +1/+1 counter on target colorless creature that entered the battlefield this turn. Ability ability = new SimpleActivatedAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RunAwayTogether.java b/Mage.Sets/src/mage/cards/r/RunAwayTogether.java index 1c5857d2be3..d5107d33568 100644 --- a/Mage.Sets/src/mage/cards/r/RunAwayTogether.java +++ b/Mage.Sets/src/mage/cards/r/RunAwayTogether.java @@ -5,10 +5,11 @@ import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.Objects; import java.util.UUID; @@ -39,9 +40,9 @@ public final class RunAwayTogether extends CardImpl { } } -class RunAwayTogetherTarget extends TargetCreaturePermanent { +class RunAwayTogetherTarget extends TargetPermanent { - private static final FilterCreaturePermanent filter + private static final FilterPermanent filter = new FilterCreaturePermanent("creatures controlled by different players"); RunAwayTogetherTarget() { diff --git a/Mage.Sets/src/mage/cards/r/RunnersBane.java b/Mage.Sets/src/mage/cards/r/RunnersBane.java index 3de7e89bb96..03b3372293f 100644 --- a/Mage.Sets/src/mage/cards/r/RunnersBane.java +++ b/Mage.Sets/src/mage/cards/r/RunnersBane.java @@ -37,7 +37,7 @@ public final class RunnersBane extends CardImpl { // Enchant creature with power 3 or less - TargetPermanent auraTarget = new TargetCreaturePermanent(filter); + TargetPermanent auraTarget = new TargetPermanent(filter); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.UnboostCreature)); Ability ability = new EnchantAbility(auraTarget); diff --git a/Mage.Sets/src/mage/cards/r/Rupture.java b/Mage.Sets/src/mage/cards/r/Rupture.java index 3b495306b74..8e3dd87e62e 100644 --- a/Mage.Sets/src/mage/cards/r/Rupture.java +++ b/Mage.Sets/src/mage/cards/r/Rupture.java @@ -52,7 +52,7 @@ class RuptureEffect extends OneShotEffect { public RuptureEffect() { super(Outcome.Damage); - staticText = "Sacrifice a creature. Rupture deals damage equal to that creature's power to each creature without flying and each player"; + staticText = "Sacrifice a creature. {this} deals damage equal to that creature's power to each creature without flying and each player"; } private RuptureEffect(final RuptureEffect effect) { diff --git a/Mage.Sets/src/mage/cards/r/RushingTideZubera.java b/Mage.Sets/src/mage/cards/r/RushingTideZubera.java index 5e47d1b2895..059844fd1f5 100644 --- a/Mage.Sets/src/mage/cards/r/RushingTideZubera.java +++ b/Mage.Sets/src/mage/cards/r/RushingTideZubera.java @@ -1,23 +1,21 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.Optional; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class RushingTideZubera extends CardImpl { @@ -31,9 +29,7 @@ public final class RushingTideZubera extends CardImpl { this.toughness = new MageInt(3); // When Rushing-Tide Zubera dies, if 4 or more damage was dealt to it this turn, draw three cards. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(3)), new RushingTideZuberaCondition(), - "When {this} dies, if 4 or more damage was dealt to it this turn, draw three cards."); - this.addAbility(ability); + this.addAbility(new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(3)).withInterveningIf(RushingTideZuberaCondition.instance)); } private RushingTideZubera(final RushingTideZubera card) { @@ -46,14 +42,19 @@ public final class RushingTideZubera extends CardImpl { } } -class RushingTideZuberaCondition implements Condition { +enum RushingTideZuberaCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent == null) { - permanent = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD); - } - return permanent.getDamage() > 3; + return Optional + .ofNullable(source.getSourcePermanentOrLKI(game)) + .map(Permanent::getDamage) + .orElse(0) >= 4; + } + + @Override + public String toString() { + return "4 or more damage was dealt to it this turn"; } } diff --git a/Mage.Sets/src/mage/cards/r/RuthlessInstincts.java b/Mage.Sets/src/mage/cards/r/RuthlessInstincts.java index f71007635d8..5f8044691ef 100644 --- a/Mage.Sets/src/mage/cards/r/RuthlessInstincts.java +++ b/Mage.Sets/src/mage/cards/r/RuthlessInstincts.java @@ -18,6 +18,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.AttackingPredicate; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -48,7 +49,7 @@ public final class RuthlessInstincts extends CardImpl { effect = new UntapTargetEffect(); effect.setText("Untap it"); this.getSpellAbility().addEffect(effect); - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); this.getSpellAbility().addTarget(target); // * Target attacking creature gets +2/+2 and gains trample until end of turn. effect = new BoostTargetEffect(2,2,Duration.EndOfTurn); @@ -57,7 +58,7 @@ public final class RuthlessInstincts extends CardImpl { effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); effect.setText("and gains trample until end of turn"); mode.addEffect(effect); - mode.addTarget(new TargetCreaturePermanent(filterAttacking)); + mode.addTarget(new TargetPermanent(filterAttacking)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/r/RuthlessPredation.java b/Mage.Sets/src/mage/cards/r/RuthlessPredation.java index 16e460c17d2..fcbb3bf8a07 100644 --- a/Mage.Sets/src/mage/cards/r/RuthlessPredation.java +++ b/Mage.Sets/src/mage/cards/r/RuthlessPredation.java @@ -11,9 +11,12 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * * @author @stwalsh4118 @@ -33,7 +36,7 @@ public final class RuthlessPredation extends CardImpl { "(Each deals damage equal to its power to the other.)"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - Target target = new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL); + Target target = new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL); this.getSpellAbility().addTarget(target); } diff --git a/Mage.Sets/src/mage/cards/r/RyanSinclair.java b/Mage.Sets/src/mage/cards/r/RyanSinclair.java index ee997f3e9dc..acb6109df07 100644 --- a/Mage.Sets/src/mage/cards/r/RyanSinclair.java +++ b/Mage.Sets/src/mage/cards/r/RyanSinclair.java @@ -77,7 +77,7 @@ class RyanSinclairEffect extends OneShotEffect { if (card != null) { FilterCard filter = new FilterCard(); filter.add(new ManaValuePredicate( - ComparisonType.FEWER_THAN, + ComparisonType.OR_LESS, Optional.ofNullable(source.getSourcePermanentOrLKI(game)) .map(MageObject::getPower) .map(MageInt::getValue) diff --git a/Mage.Sets/src/mage/cards/s/SabertoothOutrider.java b/Mage.Sets/src/mage/cards/s/SabertoothOutrider.java index 3a1b47c49f9..6fed07a0aa6 100644 --- a/Mage.Sets/src/mage/cards/s/SabertoothOutrider.java +++ b/Mage.Sets/src/mage/cards/s/SabertoothOutrider.java @@ -1,28 +1,28 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.FormidableCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class SabertoothOutrider extends CardImpl { public SabertoothOutrider(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WARRIOR); this.power = new MageInt(4); @@ -32,12 +32,9 @@ public final class SabertoothOutrider extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Formidable — Whenever Sabertooth Outrider attacks, if creatures you control have total power 8 or greater, Sabertooth Outrider gains first strike until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn), false), - FormidableCondition.instance, - "Formidable — Whenever {this} attacks, if creatures you control have total power 8 or greater, {this} gains first strike until end of turn." - )); - + this.addAbility(new AttacksTriggeredAbility(new GainAbilitySourceEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn + )).withInterveningIf(FormidableCondition.instance).setAbilityWord(AbilityWord.FORMIDABLE)); } private SabertoothOutrider(final SabertoothOutrider card) { diff --git a/Mage.Sets/src/mage/cards/s/SacredWhiteDeer.java b/Mage.Sets/src/mage/cards/s/SacredWhiteDeer.java index d0d81b66d3e..a40e0766d37 100644 --- a/Mage.Sets/src/mage/cards/s/SacredWhiteDeer.java +++ b/Mage.Sets/src/mage/cards/s/SacredWhiteDeer.java @@ -1,34 +1,29 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.GainLifeEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.TargetController; -import mage.constants.Zone; -import mage.filter.FilterPermanent; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPlaneswalkerPermanent; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class SacredWhiteDeer extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("you control a Yanggu planeswalker"); - - static { - filter.add(TargetController.YOU.getControllerPredicate()); - filter.add(CardType.PLANESWALKER.getPredicate()); - filter.add(SubType.YANGGU.getPredicate()); - } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPlaneswalkerPermanent(SubType.YANGGU, "you control a Yanggu planeswalker") + ); public SacredWhiteDeer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); @@ -38,11 +33,8 @@ public final class SacredWhiteDeer extends CardImpl { this.toughness = new MageInt(2); // {3}{G}, {T}: You gain 4 life. Activate this ability only if you control a Yanggu planeswalker. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, - new GainLifeEffect(4), - new ManaCostsImpl<>("{3}{G}"), - new PermanentsOnTheBattlefieldCondition(filter) + Ability ability = new ActivateIfConditionActivatedAbility( + new GainLifeEffect(4), new ManaCostsImpl<>("{3}{G}"), condition ); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/SaddlebackLagac.java b/Mage.Sets/src/mage/cards/s/SaddlebackLagac.java index 2e1c3128667..d0d615ebdff 100644 --- a/Mage.Sets/src/mage/cards/s/SaddlebackLagac.java +++ b/Mage.Sets/src/mage/cards/s/SaddlebackLagac.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -14,8 +12,9 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SaddlebackLagac extends CardImpl { @@ -27,16 +26,15 @@ public final class SaddlebackLagac extends CardImpl { } public SaddlebackLagac(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); this.subtype.add(SubType.LIZARD); this.power = new MageInt(3); this.toughness = new MageInt(1); // When Saddleback Lagac enters the battlefield, support 2. Ability ability = new EntersBattlefieldTriggeredAbility(new SupportEffect(this, 2, true), false); - ability.addTarget(new TargetCreaturePermanent(0, 2, FILTER, false)); + ability.addTarget(new TargetCreaturePermanent(0, 2)); this.addAbility(ability); - } private SaddlebackLagac(final SaddlebackLagac card) { diff --git a/Mage.Sets/src/mage/cards/s/SailIntoTheWest.java b/Mage.Sets/src/mage/cards/s/SailIntoTheWest.java index 341955abcc5..60cca26267c 100644 --- a/Mage.Sets/src/mage/cards/s/SailIntoTheWest.java +++ b/Mage.Sets/src/mage/cards/s/SailIntoTheWest.java @@ -56,7 +56,7 @@ class SailIntoTheWestEffect extends OneShotEffect { super(Outcome.Benefit); staticText = "starting with you, each player votes for return or embark. " + "If return gets more votes, each player returns up to two cards from their graveyard " + - "to their hand, then you exile Sail into the West. " + + "to their hand, then you exile {this}. " + "If embark gets more votes or the vote is tied, each player may discard their hand and draw seven cards."; } diff --git a/Mage.Sets/src/mage/cards/s/SalvationSwan.java b/Mage.Sets/src/mage/cards/s/SalvationSwan.java index 18ede9d824b..9b5b56c967d 100644 --- a/Mage.Sets/src/mage/cards/s/SalvationSwan.java +++ b/Mage.Sets/src/mage/cards/s/SalvationSwan.java @@ -19,6 +19,7 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; @@ -26,7 +27,7 @@ import mage.filter.predicate.mageobject.AbilityPredicate; import mage.game.ExileZone; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.targetpointer.FixedTargets; import mage.util.CardUtil; @@ -39,8 +40,8 @@ public final class SalvationSwan extends CardImpl { static final String VALUE_PREFIX = "SalvationSwanExile"; - private static final FilterControlledPermanent filterBird = new FilterControlledPermanent(SubType.BIRD, "Bird you control"); - private static final FilterControlledCreaturePermanent filterWithoutFlying = new FilterControlledCreaturePermanent("creature you control without flying"); + private static final FilterPermanent filterBird = new FilterControlledPermanent(SubType.BIRD, "Bird you control"); + private static final FilterPermanent filterWithoutFlying = new FilterControlledCreaturePermanent("creature you control without flying"); static { filterWithoutFlying.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); @@ -64,7 +65,7 @@ public final class SalvationSwan extends CardImpl { Ability ability = new EntersBattlefieldThisOrAnotherTriggeredAbility( new SalvationSwanTargetEffect(), filterBird, false, false ); - ability.addTarget(new TargetControlledCreaturePermanent(0, 1, filterWithoutFlying, false)); + ability.addTarget(new TargetPermanent(0, 1, filterWithoutFlying)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SamiShipsEngineer.java b/Mage.Sets/src/mage/cards/s/SamiShipsEngineer.java new file mode 100644 index 00000000000..18e9fda5562 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SamiShipsEngineer.java @@ -0,0 +1,63 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.permanent.token.RobotToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SamiShipsEngineer extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("you control two or more tapped creatures"); + + static { + filter.add(TappedPredicate.TAPPED); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + private static final Hint hint = new ValueHint( + "Tapped creatures you control", new PermanentsOnBattlefieldCount(filter) + ); + + public SamiShipsEngineer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ARTIFICER); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // At the beginning of your end step, if you control two or more tapped creatures, create a tapped 2/2 colorless Robot artifact creature token. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new CreateTokenEffect(new RobotToken(), 1, true) + ).withInterveningIf(condition).addHint(hint)); + } + + private SamiShipsEngineer(final SamiShipsEngineer card) { + super(card); + } + + @Override + public SamiShipsEngineer copy() { + return new SamiShipsEngineer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SamutVoiceOfDissent.java b/Mage.Sets/src/mage/cards/s/SamutVoiceOfDissent.java index f3439375be3..965ab22d815 100644 --- a/Mage.Sets/src/mage/cards/s/SamutVoiceOfDissent.java +++ b/Mage.Sets/src/mage/cards/s/SamutVoiceOfDissent.java @@ -24,6 +24,7 @@ import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -65,7 +66,7 @@ public final class SamutVoiceOfDissent extends CardImpl { //W, Tap: Untap another target creature. Ability ability = new SimpleActivatedAbility(new UntapTargetEffect(), new ManaCostsImpl<>("{W}")); - ability.addTarget(new TargetCreaturePermanent(filter2)); + ability.addTarget(new TargetPermanent(filter2)); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/SanctuaryRaptor.java b/Mage.Sets/src/mage/cards/s/SanctuaryRaptor.java index d42dffaa0b3..864f67a28d2 100644 --- a/Mage.Sets/src/mage/cards/s/SanctuaryRaptor.java +++ b/Mage.Sets/src/mage/cards/s/SanctuaryRaptor.java @@ -5,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; @@ -30,16 +29,14 @@ import java.util.UUID; */ public final class SanctuaryRaptor extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent(); + private static final FilterPermanent filter = new FilterControlledPermanent("you control three or more tokens"); static { filter.add(TokenPredicate.TRUE); } - private static final Condition condition - = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 2); - private static final Hint hint - = new ValueHint("Tokens you control", new PermanentsOnBattlefieldCount(filter)); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 2); + private static final Hint hint = new ValueHint("Tokens you control", new PermanentsOnBattlefieldCount(filter)); public SanctuaryRaptor(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); @@ -52,13 +49,12 @@ public final class SanctuaryRaptor extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever Sanctuary Raptor attacks, if you control three or more tokens, Sanctuary Raptor gets +2/+0 and gains first strike until end of turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility( - new BoostSourceEffect(2, 0, Duration.EndOfTurn), false - ), condition, "Whenever {this} attacks, if you control three or more tokens, " + - "{this} gets +2/+0 and gains first strike until end of turn." - ); - ability.addEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn)); + Ability ability = new AttacksTriggeredAbility(new BoostSourceEffect( + 2, 0, Duration.EndOfTurn + ).setText("{this} gets +2/+0")).withInterveningIf(condition); + ability.addEffect(new GainAbilitySourceEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains first strike until end of turn")); this.addAbility(ability.addHint(hint)); } diff --git a/Mage.Sets/src/mage/cards/s/SanctumOfEternity.java b/Mage.Sets/src/mage/cards/s/SanctumOfEternity.java index 337759ea92b..1368f9d8c9a 100644 --- a/Mage.Sets/src/mage/cards/s/SanctumOfEternity.java +++ b/Mage.Sets/src/mage/cards/s/SanctumOfEternity.java @@ -6,13 +6,11 @@ import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.ReturnToHandTargetEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TargetController; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.CommanderPredicate; import mage.target.TargetPermanent; @@ -39,13 +37,12 @@ public final class SanctumOfEternity extends CardImpl { // {2}, {T}: Return target commander you own from the battlefield to your hand. Activate this ability only during your turn. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new ReturnToHandTargetEffect() - .setText("return target commander you own from the battlefield to your hand"), + new ReturnToHandTargetEffect() + .setText("return target commander you own from the battlefield to your hand"), new GenericManaCost(2), MyTurnCondition.instance ); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetPermanent(filter)); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SanctumOfShatteredHeights.java b/Mage.Sets/src/mage/cards/s/SanctumOfShatteredHeights.java index e12069ab73c..cfaafbf6305 100644 --- a/Mage.Sets/src/mage/cards/s/SanctumOfShatteredHeights.java +++ b/Mage.Sets/src/mage/cards/s/SanctumOfShatteredHeights.java @@ -12,7 +12,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; @@ -45,7 +44,7 @@ public final class SanctumOfShatteredHeights extends CardImpl { // {1}, Discard a land card or Shrine card: Sanctum of Shattered Heights deals X damage to target creature or planeswalker, where X is the number of Shrines you control. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(xValue) - .setText("Sanctum of Shattered Heights deals X damage to target creature or planeswalker, where X is the number of Shrines you control"), + .setText("{this} deals X damage to target creature or planeswalker, where X is the number of Shrines you control"), new ManaCostsImpl<>("{1}")) .addHint(new ValueHint("Shrines you control", xValue)); ability.addCost(new DiscardTargetCost(new TargetCardInHand(filter))); diff --git a/Mage.Sets/src/mage/cards/s/SandScout.java b/Mage.Sets/src/mage/cards/s/SandScout.java index 85f28effe3b..8011c5c3f82 100644 --- a/Mage.Sets/src/mage/cards/s/SandScout.java +++ b/Mage.Sets/src/mage/cards/s/SandScout.java @@ -5,7 +5,6 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.PutCardIntoGraveFromAnywhereAllTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.OpponentControlsMoreCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.cards.CardImpl; @@ -31,7 +30,7 @@ public final class SandScout extends CardImpl { filter.add(SubType.DESERT.getPredicate()); } - private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LAND); + private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS); public SandScout(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); @@ -42,11 +41,7 @@ public final class SandScout extends CardImpl { this.toughness = new MageInt(2); // When Sand Scout enters the battlefield, if an opponent controls more lands than you, search your library for a Desert card, put it onto the battlefield tapped, then shuffle. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( - new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true)), - condition, "When {this} enters, if an opponent controls more lands than you, " + - "search your library for a Desert card, put it onto the battlefield tapped, then shuffle." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true)).withInterveningIf(condition)); // Whenever one or more land cards are put into your graveyard from anywhere, create a 1/1 red, green, and white Sand Warrior creature token. This ability triggers only once each turn. this.addAbility(new PutCardIntoGraveFromAnywhereAllTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/s/SandStrangler.java b/Mage.Sets/src/mage/cards/s/SandStrangler.java index f6244134b8a..e3531ccdda5 100644 --- a/Mage.Sets/src/mage/cards/s/SandStrangler.java +++ b/Mage.Sets/src/mage/cards/s/SandStrangler.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DesertControlledOrGraveyardCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -27,11 +26,8 @@ public final class SandStrangler extends CardImpl { this.toughness = new MageInt(3); // When Sand Strangler enters the battlefield, if you control a Desert or there is a Desert card in your graveyard, you may have Sand Strangler deal 3 damage to target creature. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(3), true), - DesertControlledOrGraveyardCondition.instance, "When {this} enters, " + - "if you control a Desert or there is a Desert card in your graveyard, " + - "you may have {this} deal 3 damage to target creature."); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(3), true) + .withInterveningIf(DesertControlledOrGraveyardCondition.instance); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability.addHint(DesertControlledOrGraveyardCondition.getHint())); } diff --git a/Mage.Sets/src/mage/cards/s/Sandsower.java b/Mage.Sets/src/mage/cards/s/Sandsower.java index 6f66eef7c64..be864f27821 100644 --- a/Mage.Sets/src/mage/cards/s/Sandsower.java +++ b/Mage.Sets/src/mage/cards/s/Sandsower.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -11,33 +9,25 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class Sandsower extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); - - static { - filter.add(TappedPredicate.UNTAPPED); - } - public Sandsower(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.subtype.add(SubType.SPIRIT); this.power = new MageInt(1); this.toughness = new MageInt(3); // Tap three untapped creatures you control: Tap target creature. - Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new TapTargetCost(new TargetControlledCreaturePermanent(3, 3, filter, true))); + Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new TapTargetCost(3, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES)); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SandstalkerMoloch.java b/Mage.Sets/src/mage/cards/s/SandstalkerMoloch.java index c8ee8f4d377..a86566afa01 100644 --- a/Mage.Sets/src/mage/cards/s/SandstalkerMoloch.java +++ b/Mage.Sets/src/mage/cards/s/SandstalkerMoloch.java @@ -4,7 +4,7 @@ import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.keyword.FlashAbility; import mage.cards.CardImpl; @@ -39,17 +39,10 @@ public final class SandstalkerMoloch extends CardImpl { this.addAbility(FlashAbility.getInstance()); // When Sandstalker Moloch enters the battlefield, if an opponent cast a blue and/or black spell this turn, look at the top four cards of your library. You may reveal a permanent card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility( - new LookLibraryAndPickControllerEffect( - 4, 1, StaticFilters.FILTER_CARD_A_PERMANENT, - PutCards.HAND, PutCards.BOTTOM_RANDOM - ) - ), SandstalkerMolochWatcher::checkPlayer, "When {this} enters, " + - "if an opponent cast a blue and/or black spell this turn, look at the top four cards " + - "of your library. You may reveal a permanent card from among them and put it into your hand. " + - "Put the rest on the bottom of your library in a random order." - ), new SandstalkerMolochWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + 4, 1, StaticFilters.FILTER_CARD_A_PERMANENT, + PutCards.HAND, PutCards.BOTTOM_RANDOM + )).withInterveningIf(SandstalkerMolochCondition.instance), new SandstalkerMolochWatcher()); } private SandstalkerMoloch(final SandstalkerMoloch card) { @@ -62,6 +55,20 @@ public final class SandstalkerMoloch extends CardImpl { } } +enum SandstalkerMolochCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return SandstalkerMolochWatcher.checkPlayer(game, source); + } + + @Override + public String toString() { + return "an opponent cast a blue and/or black spell this turn"; + } +} + class SandstalkerMolochWatcher extends Watcher { private final Set players = new HashSet<>(); diff --git a/Mage.Sets/src/mage/cards/s/SanguineSpy.java b/Mage.Sets/src/mage/cards/s/SanguineSpy.java index 799e7640e67..d6d98268789 100644 --- a/Mage.Sets/src/mage/cards/s/SanguineSpy.java +++ b/Mage.Sets/src/mage/cards/s/SanguineSpy.java @@ -2,19 +2,18 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.DifferentManaValuesInGraveCondition; import mage.abilities.costs.common.PayLifeCost; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.keyword.SurveilEffect; import mage.abilities.hint.common.DifferentManaValuesInGraveHint; import mage.abilities.keyword.LifelinkAbility; import mage.abilities.keyword.MenaceAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -48,12 +47,9 @@ public final class SanguineSpy extends CardImpl { this.addAbility(ability); // At the beginning of your end step, if there are five or more mana values among cards in your graveyard, you may pay 2 life. If you do, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new PayLifeCost(2)) - ), DifferentManaValuesInGraveCondition.FIVE, "At the beginning of your end step, if there are " + - "five or more mana values among cards in your graveyard, you may pay 2 life. If you do, draw a card." - ).addHint(DifferentManaValuesInGraveHint.instance)); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new PayLifeCost(2)) + ).withInterveningIf(DifferentManaValuesInGraveCondition.FIVE).addHint(DifferentManaValuesInGraveHint.instance)); } private SanguineSpy(final SanguineSpy card) { diff --git a/Mage.Sets/src/mage/cards/s/SapphireCharm.java b/Mage.Sets/src/mage/cards/s/SapphireCharm.java index e62200aa6d5..25139ec272a 100644 --- a/Mage.Sets/src/mage/cards/s/SapphireCharm.java +++ b/Mage.Sets/src/mage/cards/s/SapphireCharm.java @@ -15,9 +15,12 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author fireshoes @@ -41,7 +44,7 @@ public final class SapphireCharm extends CardImpl { // or target creature an opponent controls phases out. mode = new Mode(new PhaseOutTargetEffect()); - mode.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + mode.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SapseepForest.java b/Mage.Sets/src/mage/cards/s/SapseepForest.java index e2e276aa3ab..da3cafae68b 100644 --- a/Mage.Sets/src/mage/cards/s/SapseepForest.java +++ b/Mage.Sets/src/mage/cards/s/SapseepForest.java @@ -1,27 +1,26 @@ - package mage.cards.s; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.mana.GreenManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; -import mage.constants.Zone; +import mage.constants.SubType; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class SapseepForest extends CardImpl { @@ -32,8 +31,10 @@ public final class SapseepForest extends CardImpl { filter.add(new ColorPredicate(ObjectColor.GREEN)); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); + public SapseepForest(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); this.subtype.add(SubType.FOREST); // ({tap}: Add {G}.) @@ -43,13 +44,9 @@ public final class SapseepForest extends CardImpl { this.addAbility(new EntersBattlefieldTappedAbility()); // {G}, {tap}: You gain 1 life. Activate this ability only if you control two or more green permanents. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new GainLifeEffect(1), - new ManaCostsImpl<>("{G}"), - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1)); + Ability ability = new ActivateIfConditionActivatedAbility(new GainLifeEffect(1), new ManaCostsImpl<>("{G}"), condition); ability.addCost(new TapSourceCost()); this.addAbility(ability); - } private SapseepForest(final SapseepForest card) { diff --git a/Mage.Sets/src/mage/cards/s/Sarcomancy.java b/Mage.Sets/src/mage/cards/s/Sarcomancy.java index e9d4b223a3e..5e5125e4d15 100644 --- a/Mage.Sets/src/mage/cards/s/Sarcomancy.java +++ b/Mage.Sets/src/mage/cards/s/Sarcomancy.java @@ -1,36 +1,39 @@ - package mage.cards.s; -import java.util.UUID; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DamageControllerEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.game.permanent.token.ZombieToken; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Sarcomancy extends CardImpl { - - public Sarcomancy(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{B}"); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterPermanent(SubType.ZOMBIE, "there are no Zombies on the battlefield"), + ComparisonType.EQUAL_TO, 0, false + ); + + public Sarcomancy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}"); // When Sarcomancy enters the battlefield, create a 2/2 black Zombie creature token. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ZombieToken(), 1), false)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ZombieToken()))); + // At the beginning of your upkeep, if there are no Zombies on the battlefield, Sarcomancy deals 1 damage to you. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new DamageControllerEffect(1)), - new PermanentsOnTheBattlefieldCondition(new FilterPermanent(SubType.ZOMBIE, "Zombies"), ComparisonType.EQUAL_TO, 0, false), - "At the beginning of your upkeep, if there are no Zombies on the battlefield, {this} deals 1 damage to you.")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DamageControllerEffect(1)).withInterveningIf(condition)); } private Sarcomancy(final Sarcomancy card) { diff --git a/Mage.Sets/src/mage/cards/s/SarevoksTome.java b/Mage.Sets/src/mage/cards/s/SarevoksTome.java index 75389d857b2..efde6300ace 100644 --- a/Mage.Sets/src/mage/cards/s/SarevoksTome.java +++ b/Mage.Sets/src/mage/cards/s/SarevoksTome.java @@ -40,7 +40,6 @@ public final class SarevoksTome extends CardImpl { // {T}: Add {C}. If you have the initiative, add {C}{C} instead. this.addAbility(new SimpleManaAbility( - Zone.BATTLEFIELD, new ConditionalManaEffect( new BasicManaEffect(Mana.ColorlessMana(2)), new BasicManaEffect(Mana.ColorlessMana(1)), @@ -51,8 +50,7 @@ public final class SarevoksTome extends CardImpl { // {3}, {T}: Exile cards from the top of your library until you exile a nonland card. You may cast that card without paying its mana cost. Activate only if you've completed a dungeon. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new SarevoksTomeEffect(), - new GenericManaCost(3), CompletedDungeonCondition.instance + new SarevoksTomeEffect(), new GenericManaCost(3), CompletedDungeonCondition.instance ); ability.addCost(new TapSourceCost()); this.addAbility(ability.addHint(CompletedDungeonCondition.getHint()), new CompletedDungeonWatcher()); diff --git a/Mage.Sets/src/mage/cards/s/SarulfRealmEater.java b/Mage.Sets/src/mage/cards/s/SarulfRealmEater.java index 739780fb50b..e54c2d68929 100644 --- a/Mage.Sets/src/mage/cards/s/SarulfRealmEater.java +++ b/Mage.Sets/src/mage/cards/s/SarulfRealmEater.java @@ -1,30 +1,28 @@ package mage.cards.s; import mage.MageInt; -import mage.MageItem; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.PutIntoGraveFromBattlefieldAllTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceHasCounterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.constants.*; import mage.counters.CounterType; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterNonlandPermanent; -import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import java.util.Objects; +import java.util.HashSet; +import java.util.List; import java.util.UUID; /** @@ -32,12 +30,6 @@ import java.util.UUID; */ public final class SarulfRealmEater extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("a permanent an opponent controls"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - private static final Condition condition = new SourceHasCounterCondition(CounterType.P1P1); public SarulfRealmEater(UUID ownerId, CardSetInfo setInfo) { @@ -50,18 +42,12 @@ public final class SarulfRealmEater extends CardImpl { // Whenever a permanent an opponent controls is put into a graveyard from the battlefield, put a +1/+1 counter on Sarulf, Realm Eater. this.addAbility(new PutIntoGraveFromBattlefieldAllTriggeredAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance()), - false, filter, false, false + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, + StaticFilters.FILTER_OPPONENTS_PERMANENT, false, false )); // At the beginning of your upkeep, if Sarulf has one or more +1/+1 counters on it, you may remove all of them. If you do, exile each other nonland permanent with converted mana cost less than or equal to the number of counters removed this way. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - new SarulfRealmEaterEffect(), true - ), condition, "At the beginning of your upkeep, if {this} has one or more +1/+1 counters on it, " + - "you may remove all of them. If you do, exile each other nonland permanent with mana value " + - "less than or equal to the number of counters removed this way." - )); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SarulfRealmEaterEffect(), true).withInterveningIf(condition)); } private SarulfRealmEater(final SarulfRealmEater card) { @@ -78,6 +64,8 @@ class SarulfRealmEaterEffect extends OneShotEffect { SarulfRealmEaterEffect() { super(Outcome.Benefit); + staticText = "remove all of them. If you do, exile each other nonland permanent with mana value " + + "less than or equal to the number of counters removed this way"; } private SarulfRealmEaterEffect(final SarulfRealmEaterEffect effect) { @@ -100,16 +88,10 @@ class SarulfRealmEaterEffect extends OneShotEffect { FilterPermanent filter = new FilterNonlandPermanent(); filter.add(new ManaValuePredicate(ComparisonType.OR_LESS, removedThisWay)); filter.add(AnotherPredicate.instance); - Cards cards = new CardsImpl(); - game.getBattlefield() - .getActivePermanents( - filter, source.getControllerId(), - source, game - ) - .stream() - .filter(Objects::nonNull) - .map(MageItem::getId) - .forEach(cards::add); - return player.moveCards(cards, Zone.EXILED, source, game); + List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); + if (!permanents.isEmpty()) { + player.moveCards(new HashSet<>(permanents), Zone.EXILED, source, game); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/s/SaruliGatekeepers.java b/Mage.Sets/src/mage/cards/s/SaruliGatekeepers.java index eb63c640225..d48f592f4a1 100644 --- a/Mage.Sets/src/mage/cards/s/SaruliGatekeepers.java +++ b/Mage.Sets/src/mage/cards/s/SaruliGatekeepers.java @@ -2,35 +2,21 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.YouControlTwoOrMoreGatesCondition; import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.common.GatesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.filter.common.FilterControlledPermanent; import java.util.UUID; /** * @author LevelX2 */ - - public final class SaruliGatekeepers extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent(); - - static { - filter.add(SubType.GATE.getPredicate()); - } - - private static final Condition gatesCondition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); - public SaruliGatekeepers(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); this.subtype.add(SubType.ELF); @@ -40,11 +26,8 @@ public final class SaruliGatekeepers extends CardImpl { this.toughness = new MageInt(4); // When Saruli Gatekeepers enters the battlefield, if you control two or more Gates, gain 7 life. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new GainLifeEffect(7)), - gatesCondition, - "When {this} enters, if you control two or more Gates, you gain 7 life.") - .addHint(new ConditionHint(gatesCondition, "You control two or more Gates"))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(7)) + .withInterveningIf(YouControlTwoOrMoreGatesCondition.instance).addHint(GatesYouControlHint.instance)); } private SaruliGatekeepers(final SaruliGatekeepers card) { diff --git a/Mage.Sets/src/mage/cards/s/SatyaAetherfluxGenius.java b/Mage.Sets/src/mage/cards/s/SatyaAetherfluxGenius.java index f0e2d33d364..cf7c2f0b135 100644 --- a/Mage.Sets/src/mage/cards/s/SatyaAetherfluxGenius.java +++ b/Mage.Sets/src/mage/cards/s/SatyaAetherfluxGenius.java @@ -23,7 +23,7 @@ import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.targetpointer.FixedTargets; import java.util.List; @@ -61,7 +61,7 @@ public final class SatyaAetherfluxGenius extends CardImpl { // Whenever Satya, Aetherflux Genius attacks, create a tapped and attacking token that's a copy of up to one other target nontoken creature you control. You get {E}{E}. At the beginning of the next end step, sacrifice that token unless you pay an amount of {E} equal to its mana value. Ability ability = new AttacksTriggeredAbility(new SatyaAetherfluxGeniusEffect()); - ability.addTarget(new TargetControlledCreaturePermanent(0, 1, filter, false)); + ability.addTarget(new TargetPermanent(0, 1, filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SatyrFiredancer.java b/Mage.Sets/src/mage/cards/s/SatyrFiredancer.java index 95ad9e5b92d..894acc8f25e 100644 --- a/Mage.Sets/src/mage/cards/s/SatyrFiredancer.java +++ b/Mage.Sets/src/mage/cards/s/SatyrFiredancer.java @@ -19,6 +19,7 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.TargetAdjuster; import mage.target.targetpointer.FixedTarget; @@ -136,7 +137,7 @@ enum SatyrFiredancerAdjuster implements TargetAdjuster { if (opponent != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent("creature controlled by " + opponent.getLogName()); filter.add(new ControllerIdPredicate(opponent.getId())); - ability.getTargets().add(new TargetCreaturePermanent(filter)); + ability.getTargets().add(new TargetPermanent(filter)); } } } diff --git a/Mage.Sets/src/mage/cards/s/SavageAlliance.java b/Mage.Sets/src/mage/cards/s/SavageAlliance.java index e63f2b86dd5..5f262f47e58 100644 --- a/Mage.Sets/src/mage/cards/s/SavageAlliance.java +++ b/Mage.Sets/src/mage/cards/s/SavageAlliance.java @@ -22,6 +22,7 @@ import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; @@ -59,7 +60,7 @@ public final class SavageAlliance extends CardImpl { Effect effect = new DamageTargetEffect(2); effect.setText("{this} deals 2 damage to target creature"); Mode mode = new Mode(effect); - mode.addTarget(new TargetCreaturePermanent(filterCreature).withChooseHint("deals 2 damage to")); + mode.addTarget(new TargetPermanent(filterCreature).withChooseHint("deals 2 damage to")); this.getSpellAbility().addMode(mode); // Savage Alliance deals 1 damage to each creature target opponent controls. diff --git a/Mage.Sets/src/mage/cards/s/SavageGorger.java b/Mage.Sets/src/mage/cards/s/SavageGorger.java index 39ddc7c630f..8dd50f9c39c 100644 --- a/Mage.Sets/src/mage/cards/s/SavageGorger.java +++ b/Mage.Sets/src/mage/cards/s/SavageGorger.java @@ -1,12 +1,11 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.common.OpponentsLostLifeCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.hint.common.OpponentsLostLifeHint; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -31,12 +30,8 @@ public final class SavageGorger extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // At the beginning of your upkeep, if an opponent lost life this turn, put a +1/+1 counter on Savage Gorger. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility(new AddCountersSourceEffect( - CounterType.P1P1.createInstance()) - ), OpponentsLostLifeCondition.instance, "At the beginning of your end step, " + - "if an opponent lost life this turn, put a +1/+1 counter on {this}." - ).addHint(OpponentsLostLifeHint.instance)); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())) + .withInterveningIf(OpponentsLostLifeCondition.instance).addHint(OpponentsLostLifeHint.instance)); } private SavageGorger(final SavageGorger card) { diff --git a/Mage.Sets/src/mage/cards/s/SavagePunch.java b/Mage.Sets/src/mage/cards/s/SavagePunch.java index d20283338f1..c9105cbb8a8 100644 --- a/Mage.Sets/src/mage/cards/s/SavagePunch.java +++ b/Mage.Sets/src/mage/cards/s/SavagePunch.java @@ -13,11 +13,14 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author LevelX2 */ @@ -39,7 +42,7 @@ public final class SavagePunch extends CardImpl { effect.setText("
Target creature you control fights target creature you don't control"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - Target target = new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL); + Target target = new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL); this.getSpellAbility().addTarget(target); } diff --git a/Mage.Sets/src/mage/cards/s/SavageSmash.java b/Mage.Sets/src/mage/cards/s/SavageSmash.java index 80892289ee5..0ceb8408337 100644 --- a/Mage.Sets/src/mage/cards/s/SavageSmash.java +++ b/Mage.Sets/src/mage/cards/s/SavageSmash.java @@ -7,11 +7,14 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author TheElk801 */ @@ -27,7 +30,7 @@ public final class SavageSmash extends CardImpl { " (Each deals damage equal to its power to the other.)") ); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); } private SavageSmash(final SavageSmash card) { diff --git a/Mage.Sets/src/mage/cards/s/SavageStomp.java b/Mage.Sets/src/mage/cards/s/SavageStomp.java index a054c9082f0..b1c8fed2f58 100644 --- a/Mage.Sets/src/mage/cards/s/SavageStomp.java +++ b/Mage.Sets/src/mage/cards/s/SavageStomp.java @@ -16,11 +16,14 @@ import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author TheElk801 */ @@ -47,7 +50,7 @@ public final class SavageStomp extends CardImpl { "(Each deals damage equal to its power to the other.)"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); } private SavageStomp(final SavageStomp card) { diff --git a/Mage.Sets/src/mage/cards/s/SavingGrasp.java b/Mage.Sets/src/mage/cards/s/SavingGrasp.java index 0c6ff824a9a..dffd345b392 100644 --- a/Mage.Sets/src/mage/cards/s/SavingGrasp.java +++ b/Mage.Sets/src/mage/cards/s/SavingGrasp.java @@ -8,6 +8,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -27,7 +28,7 @@ public final class SavingGrasp extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); // Return target creature you own to your hand. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new ReturnToHandTargetEffect().setText("return target creature you own to your hand")); // Flashback {W} this.addAbility(new FlashbackAbility(this, new ManaCostsImpl<>("{W}"))); diff --git a/Mage.Sets/src/mage/cards/s/ScabClanBerserker.java b/Mage.Sets/src/mage/cards/s/ScabClanBerserker.java index 52d19755c10..408833a25e4 100644 --- a/Mage.Sets/src/mage/cards/s/ScabClanBerserker.java +++ b/Mage.Sets/src/mage/cards/s/ScabClanBerserker.java @@ -1,33 +1,28 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SpellCastOpponentTriggeredAbility; import mage.abilities.condition.common.RenownedSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.RenownAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SetTargetPointer; import mage.constants.SubType; import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.stack.Spell; -import mage.target.targetpointer.FixedTarget; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author fireshoes */ public final class ScabClanBerserker extends CardImpl { public ScabClanBerserker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.BERSERKER); this.power = new MageInt(2); @@ -35,15 +30,16 @@ public final class ScabClanBerserker extends CardImpl { // Haste this.addAbility(HasteAbility.getInstance()); - + // Renown 1 this.addAbility(new RenownAbility(1)); - + // Whenever an opponent casts a noncreature spell, if Scab-Clan Berserker is renowned, Scab-Clan Berserker deals 2 damage to that player. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new ScabClanBerserkerTriggeredAbility(), - RenownedSourceCondition.instance, - "Whenever an opponent casts a noncreature spell, if Scab-Clan Berserker is renowned, Scab-Clan Berserker deals 2 damage to that player")); + this.addAbility(new SpellCastOpponentTriggeredAbility( + Zone.BATTLEFIELD, + new DamageTargetEffect(2, true, "that player"), + StaticFilters.FILTER_SPELL_A_NON_CREATURE, false, SetTargetPointer.PLAYER + ).withInterveningIf(RenownedSourceCondition.THIS)); } private ScabClanBerserker(final ScabClanBerserker card) { @@ -55,45 +51,3 @@ public final class ScabClanBerserker extends CardImpl { return new ScabClanBerserker(this); } } - -class ScabClanBerserkerTriggeredAbility extends TriggeredAbilityImpl { - - - public ScabClanBerserkerTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(2, true, "that player")); - } - - - private ScabClanBerserkerTriggeredAbility(final ScabClanBerserkerTriggeredAbility abiltity) { - super(abiltity); - } - - @Override - public ScabClanBerserkerTriggeredAbility copy() { - return new ScabClanBerserkerTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.SPELL_CAST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (game.getOpponents(controllerId).contains(event.getPlayerId())) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null && !spell.isCreature(game)){ - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getPlayerId())); - } - return true; - } - } - return false; - } - - @Override - public String getRule() { - return "Whenever an opponent casts a noncreature spell, if Scab-Clan Berserker is renowned, Scab-Clan Berserker deals 2 damage to that player"; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/ScabClanGiant.java b/Mage.Sets/src/mage/cards/s/ScabClanGiant.java index 7c85ea2260e..4781aa08854 100644 --- a/Mage.Sets/src/mage/cards/s/ScabClanGiant.java +++ b/Mage.Sets/src/mage/cards/s/ScabClanGiant.java @@ -11,10 +11,13 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * @author LevelX2 */ @@ -31,7 +34,7 @@ public final class ScabClanGiant extends CardImpl { // When Scab-Clan Giant enters the battlefield, it fights target creature an opponent controls chosen at random. Ability ability = new EntersBattlefieldTriggeredAbility(new FightTargetSourceEffect() .setText("it fights target creature an opponent controls chosen at random")); - Target target = new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE); + Target target = new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE); target.setRandom(true); ability.addTarget(target); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/ScaldingSalamander.java b/Mage.Sets/src/mage/cards/s/ScaldingSalamander.java index 3fca24508e9..029937ba992 100644 --- a/Mage.Sets/src/mage/cards/s/ScaldingSalamander.java +++ b/Mage.Sets/src/mage/cards/s/ScaldingSalamander.java @@ -1,21 +1,21 @@ package mage.cards.s; -import java.util.UUID; - import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.keyword.FlyingAbility; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPredicate; +import java.util.UUID; + /** * @author TheElk801 */ @@ -37,10 +37,7 @@ public final class ScaldingSalamander extends CardImpl { this.toughness = new MageInt(1); // Whenever Scalding Salamander attacks, you may have it deal 1 damage to each creature without flying defending player controls. - this.addAbility(new AttacksTriggeredAbility( - new DamageAllEffect(1, filter), true, - "Whenever Scalding Salamander attacks, you may have it deal 1 damage to each creature without flying defending player controls." - )); + this.addAbility(new AttacksTriggeredAbility(new DamageAllEffect(1, filter), true)); } private ScaldingSalamander(final ScaldingSalamander card) { diff --git a/Mage.Sets/src/mage/cards/s/ScaldingTongs.java b/Mage.Sets/src/mage/cards/s/ScaldingTongs.java index 9327ff8b01e..3e5edbf3a57 100644 --- a/Mage.Sets/src/mage/cards/s/ScaldingTongs.java +++ b/Mage.Sets/src/mage/cards/s/ScaldingTongs.java @@ -1,35 +1,32 @@ - package mage.cards.s; -import java.util.UUID; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.Ability; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInHandCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.target.common.TargetOpponentOrPlaneswalker; +import java.util.UUID; + /** * @author fireshoes */ public final class ScaldingTongs extends CardImpl { + private static final Condition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 4); + public ScaldingTongs(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // At the beginning of your upkeep, if you have three or fewer cards in hand, Scalding Tongs deals 1 damage to target opponent. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new DamageTargetEffect(1)); + Ability ability = new BeginningOfUpkeepTriggeredAbility(new DamageTargetEffect(1)).withInterveningIf(condition); ability.addTarget(new TargetOpponentOrPlaneswalker()); - CardsInHandCondition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 4); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - ability, condition, - "At the beginning of your upkeep, if you have three or fewer cards in hand, " - + "{this} deals 1 damage to target opponent or planeswalker." - )); + this.addAbility(ability); } private ScaldingTongs(final ScaldingTongs card) { diff --git a/Mage.Sets/src/mage/cards/s/ScalelordReckoner.java b/Mage.Sets/src/mage/cards/s/ScalelordReckoner.java index 3ff98c16e20..feba0f44bb2 100644 --- a/Mage.Sets/src/mage/cards/s/ScalelordReckoner.java +++ b/Mage.Sets/src/mage/cards/s/ScalelordReckoner.java @@ -1,6 +1,7 @@ package mage.cards.s; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.BecomesTargetAnyTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.FlyingAbility; @@ -9,22 +10,23 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SetTargetPointer; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterNonlandPermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; -import mage.game.events.GameEvent; import mage.target.TargetPermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; import java.util.UUID; /** - * * @author spjspj */ public final class ScalelordReckoner extends CardImpl { + private static final FilterPermanent filterDragon = new FilterControlledPermanent(SubType.DRAGON, "a Dragon you control"); + private static final FilterPermanent filterTarget = new FilterNonlandPermanent("nonland permanent that player controls"); + public ScalelordReckoner(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); @@ -36,7 +38,10 @@ public final class ScalelordReckoner extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever a Dragon you control becomes the target of a spell or ability an opponent controls, destroy target nonland permanent that player controls. - this.addAbility(new ScalelordReckonerTriggeredAbility()); + Ability ability = new BecomesTargetAnyTriggeredAbility(new DestroyTargetEffect(), filterDragon, StaticFilters.FILTER_SPELL_OR_ABILITY_OPPONENTS, SetTargetPointer.PLAYER, false); + ability.addTarget(new TargetPermanent(filterTarget)); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); + this.addAbility(ability); } private ScalelordReckoner(final ScalelordReckoner card) { @@ -48,39 +53,3 @@ public final class ScalelordReckoner extends CardImpl { return new ScalelordReckoner(this); } } - -class ScalelordReckonerTriggeredAbility extends BecomesTargetAnyTriggeredAbility { - - private static final FilterControlledPermanent filter = new FilterControlledPermanent("a Dragon you control"); - - static { - filter.add(SubType.DRAGON.getPredicate()); - } - - ScalelordReckonerTriggeredAbility() { - super(new DestroyTargetEffect().setText("destroy target nonland permanent that player controls"), - filter, StaticFilters.FILTER_SPELL_OR_ABILITY_OPPONENTS, SetTargetPointer.NONE, false); - } - - private ScalelordReckonerTriggeredAbility(final ScalelordReckonerTriggeredAbility ability) { - super(ability); - } - - @Override - public ScalelordReckonerTriggeredAbility copy() { - return new ScalelordReckonerTriggeredAbility(this); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (!super.checkTrigger(event, game)) { - return false; - } - FilterNonlandPermanent targetFilter = new FilterNonlandPermanent("nonland permanent that player controls"); - targetFilter.add(new ControllerIdPredicate(event.getPlayerId())); - this.getTargets().clear(); - this.addTarget(new TargetPermanent(targetFilter)); - return true; - } - -} diff --git a/Mage.Sets/src/mage/cards/s/Scapegoat.java b/Mage.Sets/src/mage/cards/s/Scapegoat.java index dc129403607..1cb7a414ed5 100644 --- a/Mage.Sets/src/mage/cards/s/Scapegoat.java +++ b/Mage.Sets/src/mage/cards/s/Scapegoat.java @@ -1,19 +1,16 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author emerald000 */ public final class Scapegoat extends CardImpl { @@ -25,10 +22,8 @@ public final class Scapegoat extends CardImpl { this.getSpellAbility().addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE)); // Return any number of target creatures you control to their owner's hand. - Effect effect = new ReturnToHandTargetEffect(); - effect.setText("Return any number of target creatures you control to their owner's hand"); - this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, new FilterControlledCreaturePermanent(), false)); + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect().setText("Return any number of target creatures you control to their owner's hand")); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE)); } private Scapegoat(final Scapegoat card) { diff --git a/Mage.Sets/src/mage/cards/s/ScepterOfEmpires.java b/Mage.Sets/src/mage/cards/s/ScepterOfEmpires.java index e28cb424043..b1811c63e75 100644 --- a/Mage.Sets/src/mage/cards/s/ScepterOfEmpires.java +++ b/Mage.Sets/src/mage/cards/s/ScepterOfEmpires.java @@ -1,7 +1,6 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; @@ -10,11 +9,12 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetPlayerOrPlaneswalker; +import java.util.UUID; + /** * @author nantuko */ @@ -43,7 +43,7 @@ class ScepterOfEmpiresEffect extends OneShotEffect { ScepterOfEmpiresEffect() { super(Outcome.PutCreatureInPlay); - staticText = "Scepter of Empires deals 1 damage to target player or planeswalker. It deals 3 damage instead if you control artifacts named Crown of Empires and Throne of Empires"; + staticText = "{this} deals 1 damage to target player or planeswalker. It deals 3 damage instead if you control artifacts named Crown of Empires and Throne of Empires"; } private ScepterOfEmpiresEffect(final ScepterOfEmpiresEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/ScepterOfFugue.java b/Mage.Sets/src/mage/cards/s/ScepterOfFugue.java index d5505d4b008..a5ca068724f 100644 --- a/Mage.Sets/src/mage/cards/s/ScepterOfFugue.java +++ b/Mage.Sets/src/mage/cards/s/ScepterOfFugue.java @@ -6,11 +6,9 @@ import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.discard.DiscardTargetEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.target.TargetPlayer; import java.util.UUID; @@ -23,12 +21,12 @@ public final class ScepterOfFugue extends CardImpl { public ScepterOfFugue(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{B}{B}"); - // {1}{B}, {T}: Target player discards a card. Activate this ability only during your turn. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new DiscardTargetEffect(1), new ManaCostsImpl<>("{1}{B}"), MyTurnCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DiscardTargetEffect(1), new ManaCostsImpl<>("{1}{B}"), MyTurnCondition.instance + ); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetPlayer()); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/Schismotivate.java b/Mage.Sets/src/mage/cards/s/Schismotivate.java index da6a4158968..f5236523498 100644 --- a/Mage.Sets/src/mage/cards/s/Schismotivate.java +++ b/Mage.Sets/src/mage/cards/s/Schismotivate.java @@ -1,44 +1,31 @@ - package mage.cards.s; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.other.AnotherTargetPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; /** - * * @author fireshoes */ public final class Schismotivate extends CardImpl { public Schismotivate(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}{R}"); // Target creature gets +4/+0 until end of turn. Another target creature gets -4/-0 until end of turn. - this.getSpellAbility().addEffect(new SchismotivateEffect()); - - FilterCreaturePermanent filter1 = new FilterCreaturePermanent("creature (gets +4/+0 until end of turn)"); - TargetCreaturePermanent target1 = new TargetCreaturePermanent(filter1); - target1.setTargetTag(1); - this.getSpellAbility().addTarget(target1); - - FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another creature (gets -4/-0 until end of turn)"); - filter2.add(new AnotherTargetPredicate(2)); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter2); - target2.setTargetTag(2); - this.getSpellAbility().addTarget(target2); + this.getSpellAbility().addEffect(new BoostTargetEffect(4, 0)); + this.getSpellAbility().addEffect(new BoostTargetEffect(-4, 0) + .setTargetPointer(new SecondTargetPointer()) + .setText("Another target creature gets -4/-0 until end of turn")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("+4/+0").setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2).withChooseHint("-4/-0").setTargetTag(2)); } private Schismotivate(final Schismotivate card) { @@ -50,33 +37,3 @@ public final class Schismotivate extends CardImpl { return new Schismotivate(this); } } - -class SchismotivateEffect extends ContinuousEffectImpl { - - SchismotivateEffect() { - super(Duration.EndOfTurn, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.BoostCreature); - this.staticText = "Target creature gets +4/+0 until end of turn. Another target creature gets -4/-0 until end of turn"; - } - - private SchismotivateEffect(final SchismotivateEffect effect) { - super(effect); - } - - @Override - public SchismotivateEffect copy() { - return new SchismotivateEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent != null) { - permanent.addPower(4); - } - permanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - if (permanent != null) { - permanent.addPower(-4); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/s/ScholarOfStars.java b/Mage.Sets/src/mage/cards/s/ScholarOfStars.java index 7b1a533be61..db4d8dea6e2 100644 --- a/Mage.Sets/src/mage/cards/s/ScholarOfStars.java +++ b/Mage.Sets/src/mage/cards/s/ScholarOfStars.java @@ -1,24 +1,26 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.constants.SubType; +import mage.abilities.hint.common.ArtifactYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.StaticFilters; +import mage.constants.SubType; +import mage.filter.common.FilterControlledArtifactPermanent; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class ScholarOfStars extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(new FilterControlledArtifactPermanent("you control an artifact")); + public ScholarOfStars(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); @@ -28,11 +30,8 @@ public final class ScholarOfStars extends CardImpl { this.toughness = new MageInt(2); // When Scholar of Stars enters the battlefield, if you control an artifact, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1), false), - new PermanentsOnTheBattlefieldCondition(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT), - "When {this} enters, if you control an artifact, draw a card." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .withInterveningIf(condition).addHint(ArtifactYouControlHint.instance)); } private ScholarOfStars(final ScholarOfStars card) { diff --git a/Mage.Sets/src/mage/cards/s/ScionOfVituGhazi.java b/Mage.Sets/src/mage/cards/s/ScionOfVituGhazi.java index 264c1a9efec..b0d117b8a67 100644 --- a/Mage.Sets/src/mage/cards/s/ScionOfVituGhazi.java +++ b/Mage.Sets/src/mage/cards/s/ScionOfVituGhazi.java @@ -1,12 +1,9 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromHandSourcePermanentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.PopulateEffect; import mage.cards.CardImpl; @@ -16,25 +13,25 @@ import mage.constants.SubType; import mage.game.permanent.token.BirdToken; import mage.watchers.common.CastFromHandWatcher; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ScionOfVituGhazi extends CardImpl { public ScionOfVituGhazi(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(4); this.toughness = new MageInt(4); //When Scion of Vitu-Ghazi enters the battlefield, if you cast it from your hand, create a 1/1 white Bird creature token with flying, then populate. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new BirdToken()), false); + Ability ability = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new BirdToken())) + .withInterveningIf(CastFromHandSourcePermanentCondition.instance); ability.addEffect(new PopulateEffect("then")); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, CastFromHandSourcePermanentCondition.instance, - "When {this} enters, if you cast it from your hand, create a 1/1 white Bird creature token with flying, then populate."), - new CastFromHandWatcher()); + this.addAbility(ability, new CastFromHandWatcher()); } private ScionOfVituGhazi(final ScionOfVituGhazi card) { diff --git a/Mage.Sets/src/mage/cards/s/ScorchRider.java b/Mage.Sets/src/mage/cards/s/ScorchRider.java index 06e8e6f2abd..466645927df 100644 --- a/Mage.Sets/src/mage/cards/s/ScorchRider.java +++ b/Mage.Sets/src/mage/cards/s/ScorchRider.java @@ -3,7 +3,6 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.KickerAbility; @@ -32,12 +31,9 @@ public final class ScorchRider extends CardImpl { this.addAbility(new KickerAbility("{1}{R}")); // When Scorch Rider enters the battlefield, if it was kicked, it gains haste until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new GainAbilitySourceEffect( - HasteAbility.getInstance(), Duration.EndOfTurn - )), KickedCondition.ONCE, "When {this} enters, " + - "if it was kicked, it gains haste until end of turn." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainAbilitySourceEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("it gains haste until end of turn")).withInterveningIf(KickedCondition.ONCE)); } private ScorchRider(final ScorchRider card) { diff --git a/Mage.Sets/src/mage/cards/s/ScorchingLava.java b/Mage.Sets/src/mage/cards/s/ScorchingLava.java index 3f732919af5..dd3143ad363 100644 --- a/Mage.Sets/src/mage/cards/s/ScorchingLava.java +++ b/Mage.Sets/src/mage/cards/s/ScorchingLava.java @@ -1,27 +1,21 @@ package mage.cards.s; -import java.util.UUID; -import mage.MageObjectReference; -import mage.abilities.Ability; import mage.abilities.condition.LockedInCondition; import mage.abilities.condition.common.KickedCondition; import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.ExileTargetIfDiesEffect; -import mage.abilities.effects.common.replacement.DiesReplacementEffect; import mage.abilities.effects.common.ruleModifying.CantRegenerateTargetEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Outcome; -import mage.game.Game; -import mage.game.permanent.Permanent; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** * * @author LoneFox @@ -37,8 +31,7 @@ public final class ScorchingLava extends CardImpl { // that creature can't be regenerated this turn and if it would die this turn, exile it instead. this.getSpellAbility().addEffect(new DamageTargetEffect(2)); this.getSpellAbility().addEffect(new ConditionalContinuousRuleModifyingEffect( - new CantRegenerateTargetEffect(Duration.EndOfTurn, "If Scorching Lava was kicked, " - + "\n" + "that creature "), + new CantRegenerateTargetEffect(Duration.EndOfTurn, "If {this} was kicked, that creature"), new LockedInCondition(KickedCondition.ONCE))); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new ExileTargetIfDiesEffect(), @@ -56,28 +49,3 @@ public final class ScorchingLava extends CardImpl { return new ScorchingLava(this); } } - -class ScorchingLavaEffect extends OneShotEffect { - - ScorchingLavaEffect() { - super(Outcome.Exile); - } - - private ScorchingLavaEffect(final ScorchingLavaEffect effect) { - super(effect); - } - - @Override - public ScorchingLavaEffect copy() { - return new ScorchingLavaEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (targetCreature != null) { - game.addEffect(new DiesReplacementEffect(new MageObjectReference(targetCreature, game), Duration.EndOfTurn), source); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/s/ScourgeOfTheSkyclaves.java b/Mage.Sets/src/mage/cards/s/ScourgeOfTheSkyclaves.java index f2af217e91f..79851881a51 100644 --- a/Mage.Sets/src/mage/cards/s/ScourgeOfTheSkyclaves.java +++ b/Mage.Sets/src/mage/cards/s/ScourgeOfTheSkyclaves.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -13,7 +12,10 @@ import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffec import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; import mage.game.Game; import mage.players.Player; @@ -36,10 +38,7 @@ public final class ScourgeOfTheSkyclaves extends CardImpl { this.addAbility(new KickerAbility("{4}{B}")); // When you cast this spell, if it was kicked, each player loses half their life, rounded up. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new CastSourceTriggeredAbility(new ScourgeOfTheSkyclavesEffect()), KickedCondition.ONCE, - "When you cast this spell, if it was kicked, each player loses half their life, rounded up." - )); + this.addAbility(new CastSourceTriggeredAbility(new ScourgeOfTheSkyclavesEffect()).withInterveningIf(KickedCondition.ONCE)); // Scourge of the Skyclaves's power and toughness are each equal to 20 minus the highest life total among players. this.addAbility(new SimpleStaticAbility( @@ -89,6 +88,7 @@ class ScourgeOfTheSkyclavesEffect extends OneShotEffect { ScourgeOfTheSkyclavesEffect() { super(Outcome.Benefit); + staticText = "each player loses half their life, rounded up"; } private ScourgeOfTheSkyclavesEffect(final ScourgeOfTheSkyclavesEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/ScourgeOfTheThrone.java b/Mage.Sets/src/mage/cards/s/ScourgeOfTheThrone.java index 6cec7f8d873..856ef512c5b 100644 --- a/Mage.Sets/src/mage/cards/s/ScourgeOfTheThrone.java +++ b/Mage.Sets/src/mage/cards/s/ScourgeOfTheThrone.java @@ -1,11 +1,9 @@ - package mage.cards.s; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.AttacksFirstTimeTriggeredAbility; import mage.abilities.condition.common.SourceAttackingPlayerWithMostLifeCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.AdditionalCombatPhaseEffect; import mage.abilities.effects.common.UntapAllControllerEffect; import mage.abilities.keyword.DethroneAbility; @@ -32,24 +30,19 @@ public final class ScourgeOfTheThrone extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); + // Dethrone (Whenever this creature attacks the player with the most life or tied for most life, put a +1/+1 counter on it.) this.addAbility(new DethroneAbility()); + // Whenever Scourge of the Throne attacks for the first time each turn, if it's attacking the player with the most life or tied for most life, untap all attacking creatures. After this phase, there is an additional combat phase. - TriggeredAbility ability = new AttacksFirstTimeTriggeredAbility( + Ability ability = new AttacksFirstTimeTriggeredAbility( new UntapAllControllerEffect( StaticFilters.FILTER_ATTACKING_CREATURES, "untap all attacking creatures" ), false - ); + ).withInterveningIf(SourceAttackingPlayerWithMostLifeCondition.instance); ability.addEffect(new AdditionalCombatPhaseEffect()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - ability, - SourceAttackingPlayerWithMostLifeCondition.instance, - "Whenever {this} attacks for the first time each turn, " - + "if it's attacking the player with the most life or tied for most life, " - + "untap all attacking creatures. After this phase, " - + "there is an additional combat phase." - )); + this.addAbility(ability); } private ScourgeOfTheThrone(final ScourgeOfTheThrone card) { @@ -60,4 +53,4 @@ public final class ScourgeOfTheThrone extends CardImpl { public ScourgeOfTheThrone copy() { return new ScourgeOfTheThrone(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/Scourglass.java b/Mage.Sets/src/mage/cards/s/Scourglass.java index e107d607581..1622b023215 100644 --- a/Mage.Sets/src/mage/cards/s/Scourglass.java +++ b/Mage.Sets/src/mage/cards/s/Scourglass.java @@ -1,23 +1,20 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DestroyAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.PhaseStep; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; +import java.util.UUID; + /** - * * @author Plopman */ public final class Scourglass extends CardImpl { @@ -25,15 +22,17 @@ public final class Scourglass extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("permanents except for artifacts and lands"); static { - filter.add(Predicates.not(Predicates.or(CardType.ARTIFACT.getPredicate(), CardType.LAND.getPredicate()))); + filter.add(Predicates.not(CardType.ARTIFACT.getPredicate())); + filter.add(Predicates.not(CardType.LAND.getPredicate())); } public Scourglass(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}{W}{W}"); // {T}, Sacrifice Scourglass: Destroy all permanents except for artifacts and lands. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new DestroyAllEffect(filter), new TapSourceCost(), new IsStepCondition(PhaseStep.UPKEEP)); + Ability ability = new ActivateIfConditionActivatedAbility( + new DestroyAllEffect(filter), new TapSourceCost(), IsStepCondition.getMyUpkeep() + ); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/ScoutingHawk.java b/Mage.Sets/src/mage/cards/s/ScoutingHawk.java index a718a1aca2d..e77d45c12f3 100644 --- a/Mage.Sets/src/mage/cards/s/ScoutingHawk.java +++ b/Mage.Sets/src/mage/cards/s/ScoutingHawk.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.OpponentControlsMoreCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -30,7 +29,7 @@ public final class ScoutingHawk extends CardImpl { filter.add(SubType.PLAINS.getPredicate()); } - private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LAND); + private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS); public ScoutingHawk(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); @@ -43,11 +42,9 @@ public final class ScoutingHawk extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Keen Sight — When Scouting Hawk enters the battlefield, if an opponent controls more lands than you, search your library for a basic Plains card, put it onto the battlefield tapped, then shuffle. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( - new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true)), - condition, "When {this} enters, if an opponent controls more lands than you, " + - "search your library for a basic Plains card, put it onto the battlefield tapped, then shuffle." - ).withFlavorWord("Keen Sight")); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true) + ).withInterveningIf(condition).withFlavorWord("Keen Sight")); } private ScoutingHawk(final ScoutingHawk card) { diff --git a/Mage.Sets/src/mage/cards/s/Scrapshooter.java b/Mage.Sets/src/mage/cards/s/Scrapshooter.java index ff8ecce344d..e222374435e 100644 --- a/Mage.Sets/src/mage/cards/s/Scrapshooter.java +++ b/Mage.Sets/src/mage/cards/s/Scrapshooter.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.GiftWasPromisedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.GiftAbility; import mage.abilities.keyword.ReachAbility; @@ -47,11 +46,7 @@ public final class Scrapshooter extends CardImpl { this.addAbility(ReachAbility.getInstance()); // When Scrapshooter enters, if the gift was promised, destroy target artifact or enchantment an opponent controls. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()), - GiftWasPromisedCondition.TRUE, "When {this} enters, if the gift was promised, " + - "destroy target artifact or enchantment an opponent controls." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()).withInterveningIf(GiftWasPromisedCondition.TRUE); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/ScreamingNemesis.java b/Mage.Sets/src/mage/cards/s/ScreamingNemesis.java index dcc1e1e2f98..af499a01b4a 100644 --- a/Mage.Sets/src/mage/cards/s/ScreamingNemesis.java +++ b/Mage.Sets/src/mage/cards/s/ScreamingNemesis.java @@ -17,7 +17,7 @@ import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetPermanentOrPlayer; import mage.target.targetpointer.FixedTarget; import java.util.UUID; @@ -45,7 +45,7 @@ public final class ScreamingNemesis extends CardImpl { // Whenever Screaming Nemesis is dealt damage, it deals that much damage to any other target. If a player is dealt damage this way, they can't gain life for the rest of the game. Ability ability = new DealtDamageToSourceTriggeredAbility(new ScreamingNemesisEffect(), false); - ability.addTarget(new TargetAnyTarget(filter)); + ability.addTarget(new TargetPermanentOrPlayer(filter)); this.addAbility(ability); } @@ -98,4 +98,4 @@ class ScreamingNemesisEffect extends OneShotEffect { } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/ScreechingSilcaw.java b/Mage.Sets/src/mage/cards/s/ScreechingSilcaw.java index a65526d9ab0..298bf6f41aa 100644 --- a/Mage.Sets/src/mage/cards/s/ScreechingSilcaw.java +++ b/Mage.Sets/src/mage/cards/s/ScreechingSilcaw.java @@ -1,10 +1,8 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.condition.common.MetalcraftCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.MillCardsTargetEffect; import mage.abilities.hint.common.MetalcraftHint; import mage.abilities.keyword.FlyingAbility; @@ -31,15 +29,9 @@ public final class ScreechingSilcaw extends CardImpl { this.addAbility(FlyingAbility.getInstance()); //"Metalcraft — Whenever Screeching Silcaw deals combat damage to a player, if you control three or more artifacts, that player puts the top four cards of their library into their graveyard. - TriggeredAbility conditional = new ConditionalInterveningIfTriggeredAbility( - new DealsCombatDamageToAPlayerTriggeredAbility( - new MillCardsTargetEffect(4), false, true - ), MetalcraftCondition.instance, "Whenever {this} " + - "deals combat damage to a player, if you control three or more artifacts, that player mills four cards." - ); - conditional.setAbilityWord(AbilityWord.METALCRAFT); - conditional.addHint(MetalcraftHint.instance); - this.addAbility(conditional); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new MillCardsTargetEffect(4), false, true + ).withInterveningIf(MetalcraftCondition.instance).setAbilityWord(AbilityWord.METALCRAFT).addHint(MetalcraftHint.instance)); } private ScreechingSilcaw(final ScreechingSilcaw card) { diff --git a/Mage.Sets/src/mage/cards/s/ScrollOfOrigins.java b/Mage.Sets/src/mage/cards/s/ScrollOfOrigins.java index 17d4a194423..ba99bbbd763 100644 --- a/Mage.Sets/src/mage/cards/s/ScrollOfOrigins.java +++ b/Mage.Sets/src/mage/cards/s/ScrollOfOrigins.java @@ -1,32 +1,36 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInHandCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; -import mage.constants.Zone; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class ScrollOfOrigins extends CardImpl { + private static final Condition condition = new CardsInHandCondition(ComparisonType.MORE_THAN, 6); + public ScrollOfOrigins(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // {2}, {tap}: Draw a card if you have seven or more cards in hand. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new GenericManaCost(2), - new CardsInHandCondition(ComparisonType.MORE_THAN, 6), - "{2}, {T}: Draw a card if you have seven or more cards in hand."); - ability.addCost(new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(new ConditionalOneShotEffect( + new DrawCardSourceControllerEffect(1), condition, + "draw a card if you have seven or more cards in hand" + ), new GenericManaCost(2)); + ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/ScroungingBandar.java b/Mage.Sets/src/mage/cards/s/ScroungingBandar.java index 6d9fb216110..108102b4edd 100644 --- a/Mage.Sets/src/mage/cards/s/ScroungingBandar.java +++ b/Mage.Sets/src/mage/cards/s/ScroungingBandar.java @@ -17,8 +17,11 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * * @author Styxo @@ -38,7 +41,7 @@ public final class ScroungingBandar extends CardImpl { // At the beginning of you upkeep, you may move any number of +1/+1 counters from Scrounging Bandar onto another target creature. Ability ability = new BeginningOfUpkeepTriggeredAbility(new ScroungingBandarEffect(), true); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/ScrybRanger.java b/Mage.Sets/src/mage/cards/s/ScrybRanger.java index 8f55de220dd..7ed87770afb 100644 --- a/Mage.Sets/src/mage/cards/s/ScrybRanger.java +++ b/Mage.Sets/src/mage/cards/s/ScrybRanger.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -15,13 +13,13 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterControlledLandPermanent; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Plopman */ public final class ScrybRanger extends CardImpl { @@ -42,12 +40,17 @@ public final class ScrybRanger extends CardImpl { // Flash this.addAbility(FlashAbility.getInstance()); + // Flying this.addAbility(FlyingAbility.getInstance()); + // protection from blue this.addAbility(ProtectionAbility.from(ObjectColor.BLUE)); + // Return a Forest you control to its owner's hand: Untap target creature. Activate this ability only once each turn. - Ability ability = new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new UntapTargetEffect(), new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(filterForest))); + Ability ability = new LimitedTimesPerTurnActivatedAbility( + new UntapTargetEffect(), new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(filterForest)) + ); ability.addTarget(new TargetCreaturePermanent(1)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/ScuttlingButler.java b/Mage.Sets/src/mage/cards/s/ScuttlingButler.java index ac709ef1e0a..b0016c9c068 100644 --- a/Mage.Sets/src/mage/cards/s/ScuttlingButler.java +++ b/Mage.Sets/src/mage/cards/s/ScuttlingButler.java @@ -1,32 +1,38 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; import mage.abilities.keyword.DoubleStrikeAbility; -import mage.constants.*; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.MulticoloredPredicate; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class ScuttlingButler extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("multicolored permanents"); + private static final FilterPermanent filter = new FilterPermanent("you control two or more multicolored permanents"); static { filter.add(MulticoloredPredicate.instance); } private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); + private static final Hint hint = new ValueHint("Multicolored permanents you control", new PermanentsOnBattlefieldCount(filter)); public ScuttlingButler(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); @@ -36,11 +42,9 @@ public final class ScuttlingButler extends CardImpl { this.toughness = new MageInt(1); // At the beginning of combat on your turn, if you control two or more multicolored permanents, Scuttling Butler gains double strike until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility(new GainAbilitySourceEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn)), - condition, - "At the beginning of combat on your turn, if you control two or more multicolored permanents, {this} gains double strike until end of turn." - )); + this.addAbility(new BeginningOfCombatTriggeredAbility(new GainAbilitySourceEffect( + DoubleStrikeAbility.getInstance(), Duration.EndOfTurn + )).withInterveningIf(condition)); } private ScuttlingButler(final ScuttlingButler card) { diff --git a/Mage.Sets/src/mage/cards/s/SeaGateWreckage.java b/Mage.Sets/src/mage/cards/s/SeaGateWreckage.java index bf4568f0ac9..d9460612177 100644 --- a/Mage.Sets/src/mage/cards/s/SeaGateWreckage.java +++ b/Mage.Sets/src/mage/cards/s/SeaGateWreckage.java @@ -1,34 +1,33 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.common.HellbentCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; + +import java.util.UUID; /** - * * @author fireshoes */ public final class SeaGateWreckage extends CardImpl { public SeaGateWreckage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // {T}: Add {C}. this.addAbility(new ColorlessManaAbility()); - + // {2}{C}, {T}: Draw a card. Activate this ability only if you have no cards in hand. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), - new ManaCostsImpl<>("{2}{C}"), HellbentCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{2}{C}"), HellbentCondition.instance + ); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SeaTroll.java b/Mage.Sets/src/mage/cards/s/SeaTroll.java index 84843e7340a..5234a2f2a4f 100644 --- a/Mage.Sets/src/mage/cards/s/SeaTroll.java +++ b/Mage.Sets/src/mage/cards/s/SeaTroll.java @@ -5,14 +5,13 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.RegenerateSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.WatcherScope; -import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -23,20 +22,21 @@ import java.util.Set; import java.util.UUID; /** - * * @author noahg */ public final class SeaTroll extends CardImpl { public SeaTroll(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); - + this.subtype.add(SubType.TROLL); this.power = new MageInt(2); this.toughness = new MageInt(1); // {U}: Regenerate Sea Troll. Activate this ability only if Sea Troll blocked or was blocked by a blue creature this turn. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl<>("{U}"), new SeaTrollCondition()); + Ability ability = new ActivateIfConditionActivatedAbility( + new RegenerateSourceEffect(), new ManaCostsImpl<>("{U}"), SeaTrollCondition.instance + ); ability.addWatcher(new SeaTrollWatcher()); this.addAbility(ability); } @@ -56,7 +56,7 @@ class SeaTrollWatcher extends Watcher { private final Set blockedOrBlockedByBlueThisTurnCreatures; public SeaTrollWatcher() { - super( WatcherScope.GAME); + super(WatcherScope.GAME); blockedOrBlockedByBlueThisTurnCreatures = new HashSet<>(); } @@ -65,10 +65,10 @@ class SeaTrollWatcher extends Watcher { if (event.getType() == GameEvent.EventType.BLOCKER_DECLARED) { MageObjectReference blocker = new MageObjectReference(event.getSourceId(), game); MageObjectReference attacker = new MageObjectReference(event.getTargetId(), game); - if (blocker.getPermanentOrLKIBattlefield(game).getColor(game).isBlue()){ + if (blocker.getPermanentOrLKIBattlefield(game).getColor(game).isBlue()) { blockedOrBlockedByBlueThisTurnCreatures.add(attacker); } - if (attacker.getPermanentOrLKIBattlefield(game).getColor(game).isBlue()){ + if (attacker.getPermanentOrLKIBattlefield(game).getColor(game).isBlue()) { blockedOrBlockedByBlueThisTurnCreatures.add(blocker); } } @@ -80,17 +80,18 @@ class SeaTrollWatcher extends Watcher { blockedOrBlockedByBlueThisTurnCreatures.clear(); } - public boolean blockedOrBlockedByBlueCreatureThisTurn(MageObjectReference creature){ + public boolean blockedOrBlockedByBlueCreatureThisTurn(MageObjectReference creature) { return blockedOrBlockedByBlueThisTurnCreatures.contains(creature); } } -class SeaTrollCondition implements Condition { +enum SeaTrollCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (sourcePermanent != null){ + if (sourcePermanent != null) { SeaTrollWatcher watcher = game.getState().getWatcher(SeaTrollWatcher.class); if (watcher != null) { return watcher.blockedOrBlockedByBlueCreatureThisTurn(new MageObjectReference(sourcePermanent, game)); @@ -103,4 +104,4 @@ class SeaTrollCondition implements Condition { public String toString() { return "{this} blocked or was blocked by a blue creature this turn"; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/SealOfDoom.java b/Mage.Sets/src/mage/cards/s/SealOfDoom.java index 64ca2f487eb..be3544f7a0b 100644 --- a/Mage.Sets/src/mage/cards/s/SealOfDoom.java +++ b/Mage.Sets/src/mage/cards/s/SealOfDoom.java @@ -10,8 +10,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * @author Loki */ @@ -21,7 +24,7 @@ public final class SealOfDoom extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{B}"); Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(true), new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + ability.addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SearingLight.java b/Mage.Sets/src/mage/cards/s/SearingLight.java index b1758315024..08bd54f8a41 100644 --- a/Mage.Sets/src/mage/cards/s/SearingLight.java +++ b/Mage.Sets/src/mage/cards/s/SearingLight.java @@ -9,6 +9,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.common.FilterAttackingOrBlockingCreature; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -27,7 +28,7 @@ public final class SearingLight extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{W}"); // Destroying target attacking or blocking creature with power 2 or less. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/s/SecondChance.java b/Mage.Sets/src/mage/cards/s/SecondChance.java index 5fd611b2534..5d142722089 100644 --- a/Mage.Sets/src/mage/cards/s/SecondChance.java +++ b/Mage.Sets/src/mage/cards/s/SecondChance.java @@ -1,11 +1,10 @@ package mage.cards.s; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.Ability; import mage.abilities.condition.common.FatefulHourCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.turn.AddExtraTurnControllerEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -13,19 +12,17 @@ import mage.constants.CardType; import java.util.UUID; /** - * * @author Plopman */ public final class SecondChance extends CardImpl { public SecondChance(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); // At the beginning of your upkeep, if you have 5 or less life, sacrifice Second Chance and take an extra turn after this one. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceEffect()); - ability.addEffect(new AddExtraTurnControllerEffect()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, FatefulHourCondition.instance, - "At the beginning of your upkeep, if you have 5 or less life, sacrifice {this} and take an extra turn after this one")); + Ability ability = new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceEffect()).withInterveningIf(FatefulHourCondition.instance); + ability.addEffect(new AddExtraTurnControllerEffect().concatBy("and")); + this.addAbility(ability); } private SecondChance(final SecondChance card) { @@ -36,6 +33,6 @@ public final class SecondChance extends CardImpl { public SecondChance copy() { return new SecondChance(this); } - + } diff --git a/Mage.Sets/src/mage/cards/s/Secretkeeper.java b/Mage.Sets/src/mage/cards/s/Secretkeeper.java index 6ab1105526c..9d3552fc942 100644 --- a/Mage.Sets/src/mage/cards/s/Secretkeeper.java +++ b/Mage.Sets/src/mage/cards/s/Secretkeeper.java @@ -34,7 +34,7 @@ public final class Secretkeeper extends CardImpl { Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( new BoostSourceEffect(2,2, Duration.WhileOnBattlefield), MoreCardsInHandThanOpponentsCondition.instance, - "As long as you have more cards in hand than each opponent, Secretkeeper gets +2/+2")); + "As long as you have more cards in hand than each opponent, {this} gets +2/+2")); ability.addEffect(new ConditionalContinuousEffect( new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield), MoreCardsInHandThanOpponentsCondition.instance, diff --git a/Mage.Sets/src/mage/cards/s/SedraxisAlchemist.java b/Mage.Sets/src/mage/cards/s/SedraxisAlchemist.java index d6f0ddcb1ec..4fc68da827e 100644 --- a/Mage.Sets/src/mage/cards/s/SedraxisAlchemist.java +++ b/Mage.Sets/src/mage/cards/s/SedraxisAlchemist.java @@ -1,38 +1,38 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetNonlandPermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class SedraxisAlchemist extends CardImpl { - - private static final FilterControlledPermanent filter = new FilterControlledPermanent("blue permanent"); + + private static final FilterPermanent filter = new FilterControlledPermanent("you control a blue permanent"); static { filter.add(new ColorPredicate(ObjectColor.BLUE)); } - - private static final String rule = "When {this} enters, if you control a blue permanent, return target nonland permanent to its owner's hand."; + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); public SedraxisAlchemist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.WIZARD); @@ -40,10 +40,9 @@ public final class SedraxisAlchemist extends CardImpl { this.toughness = new MageInt(2); // When Sedraxis Alchemist enters the battlefield, if you control a blue permanent, return target nonland permanent to its owner's hand. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), false); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), false).withInterveningIf(condition); ability.addTarget(new TargetNonlandPermanent()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new PermanentsOnTheBattlefieldCondition(filter), rule)); - + this.addAbility(ability); } private SedraxisAlchemist(final SedraxisAlchemist card) { diff --git a/Mage.Sets/src/mage/cards/s/SeeRed.java b/Mage.Sets/src/mage/cards/s/SeeRed.java index f0aa47dddde..23b5194723f 100644 --- a/Mage.Sets/src/mage/cards/s/SeeRed.java +++ b/Mage.Sets/src/mage/cards/s/SeeRed.java @@ -1,14 +1,10 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; @@ -16,24 +12,28 @@ import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.hint.common.RaidHint; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AttachmentType; import mage.constants.CardType; -import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.watchers.common.PlayerAttackedWatcher; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SeeRed extends CardImpl { + private static final Condition condition = new InvertCondition( + RaidCondition.instance, "you didn't attack with a creature this turn" + ); + public SeeRed(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); @@ -43,24 +43,18 @@ public final class SeeRed extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget)); // Enchanted creature gets +2/+1 and has first strike. - ability = new SimpleStaticAbility(new BoostEnchantedEffect(2, 1, Duration.WhileOnBattlefield)); - Effect effect = new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.AURA); - effect.setText("and has first strike"); - ability.addEffect(effect); + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(2, 1)); + ability.addEffect(new GainAbilityAttachedEffect( + FirstStrikeAbility.getInstance(), AttachmentType.AURA + ).setText("and has first strike")); this.addAbility(ability); // At the beginning of your end step, if you didn't attack with a creature this turn, sacrifice See Red. - ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility(new SacrificeSourceEffect()), - new InvertCondition(RaidCondition.instance), - "At the beginning of your end step, if you didn't attack with a creature this turn, sacrifice {this}." - ); - ability.addHint(RaidHint.instance); - this.addAbility(ability, new PlayerAttackedWatcher()); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new SacrificeSourceEffect()) + .withInterveningIf(condition).addHint(RaidHint.instance), new PlayerAttackedWatcher()); } private SeeRed(final SeeRed card) { diff --git a/Mage.Sets/src/mage/cards/s/SeekerOfInsight.java b/Mage.Sets/src/mage/cards/s/SeekerOfInsight.java index 55be104f1ba..5a5b24a3247 100644 --- a/Mage.Sets/src/mage/cards/s/SeekerOfInsight.java +++ b/Mage.Sets/src/mage/cards/s/SeekerOfInsight.java @@ -1,8 +1,5 @@ - package mage.cards.s; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -13,13 +10,12 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.game.Game; -import mage.game.stack.Spell; import mage.watchers.common.SpellsCastWatcher; +import java.util.UUID; + /** - * * @author anonymous */ public final class SeekerOfInsight extends CardImpl { @@ -33,12 +29,9 @@ public final class SeekerOfInsight extends CardImpl { this.toughness = new MageInt(3); // {T}: Draw a card, then discard a card. Activate this ability only if you've cast a noncreature spell this turn. - this.addAbility( - new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new DrawDiscardControllerEffect(), - new TapSourceCost(), - new CastNonCreatureSpellCondition())); + this.addAbility(new ActivateIfConditionActivatedAbility( + new DrawDiscardControllerEffect(), new TapSourceCost(), SeekerOfInsightCondition.instance + )); } private SeekerOfInsight(final SeekerOfInsight card) { @@ -51,22 +44,17 @@ public final class SeekerOfInsight extends CardImpl { } } -class CastNonCreatureSpellCondition implements Condition { +enum SeekerOfInsightCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { - SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); - if (watcher != null) { - List spellsCast = watcher.getSpellsCastThisTurn(source.getControllerId()); - if (spellsCast != null) { - for (Spell spell : spellsCast) { - if (!spell.isCreature(game)) { - return true; - } - } - } - } - return false; + return game + .getState() + .getWatcher(SpellsCastWatcher.class) + .getSpellsCastThisTurn(source.getControllerId()) + .stream() + .anyMatch(spell -> !spell.isCreature(game)); } @Override diff --git a/Mage.Sets/src/mage/cards/s/SeismicShift.java b/Mage.Sets/src/mage/cards/s/SeismicShift.java index be1b13ab3b4..d97740b83f6 100644 --- a/Mage.Sets/src/mage/cards/s/SeismicShift.java +++ b/Mage.Sets/src/mage/cards/s/SeismicShift.java @@ -1,20 +1,18 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.combat.CantBlockTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetLandPermanent; import mage.target.targetpointer.SecondTargetPointer; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SeismicShift extends CardImpl { @@ -28,7 +26,7 @@ public final class SeismicShift extends CardImpl { this.getSpellAbility().addEffect(new CantBlockTargetEffect(Duration.EndOfTurn) .setText("Up to two target creatures can't block this turn") .setTargetPointer(new SecondTargetPointer())); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2, StaticFilters.FILTER_PERMANENT_CREATURES, false)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2)); } private SeismicShift(final SeismicShift card) { diff --git a/Mage.Sets/src/mage/cards/s/SeizeTheSoul.java b/Mage.Sets/src/mage/cards/s/SeizeTheSoul.java index bffe087601a..d417ef78e77 100644 --- a/Mage.Sets/src/mage/cards/s/SeizeTheSoul.java +++ b/Mage.Sets/src/mage/cards/s/SeizeTheSoul.java @@ -12,6 +12,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.permanent.token.SpiritWhiteToken; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -34,13 +35,13 @@ public final class SeizeTheSoul extends CardImpl { // Destroy target nonwhite, nonblack creature. Put a 1/1 white Spirit creature token with flying onto the battlefield. this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addEffect(new CreateTokenEffect(new SpiritWhiteToken())); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Haunt // When the creature Seize the Soul haunts dies, destroy target nonwhite, nonblack creature. Put a 1/1 white Spirit creature token with flying onto the battlefield. Ability ability = new HauntAbility(this, new DestroyTargetEffect()); ability.addEffect(new CreateTokenEffect(new SpiritWhiteToken())); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SelectForInspection.java b/Mage.Sets/src/mage/cards/s/SelectForInspection.java index d5d7e8a0a81..350aaf21852 100644 --- a/Mage.Sets/src/mage/cards/s/SelectForInspection.java +++ b/Mage.Sets/src/mage/cards/s/SelectForInspection.java @@ -9,6 +9,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -28,7 +29,7 @@ public final class SelectForInspection extends CardImpl { // Return target tapped creature to its owner's hand. Scry 1. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new ScryEffect(1)); } diff --git a/Mage.Sets/src/mage/cards/s/SelesnyaCharm.java b/Mage.Sets/src/mage/cards/s/SelesnyaCharm.java index 2c996db5cc3..5e497797990 100644 --- a/Mage.Sets/src/mage/cards/s/SelesnyaCharm.java +++ b/Mage.Sets/src/mage/cards/s/SelesnyaCharm.java @@ -17,6 +17,7 @@ import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.game.permanent.token.KnightToken; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -46,7 +47,7 @@ public final class SelesnyaCharm extends CardImpl { // or exile target creature with power 5 or greater; Mode mode = new Mode(new ExileTargetEffect()); - mode.addTarget(new TargetCreaturePermanent(filter)); + mode.addTarget(new TargetPermanent(filter)); this.getSpellAbility().addMode(mode); // or create a 2/2 white Knight creature token with vigilance. diff --git a/Mage.Sets/src/mage/cards/s/SelesnyaEvangel.java b/Mage.Sets/src/mage/cards/s/SelesnyaEvangel.java index 228442bf655..759efd76f6e 100644 --- a/Mage.Sets/src/mage/cards/s/SelesnyaEvangel.java +++ b/Mage.Sets/src/mage/cards/s/SelesnyaEvangel.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -13,26 +11,18 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; +import mage.filter.StaticFilters; import mage.game.permanent.token.SaprolingToken; -import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author Loki */ public final class SelesnyaEvangel extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); - - static { - filter.add(TappedPredicate.UNTAPPED); - } - public SelesnyaEvangel(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{W}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.SHAMAN); @@ -42,7 +32,7 @@ public final class SelesnyaEvangel extends CardImpl { // {1}, {tap}, Tap an untapped creature you control: Create a 1/1 green Saproling creature token. Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new SaprolingToken()), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); - ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, true))); + ability.addCost(new TapTargetCost(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SelfDestruct.java b/Mage.Sets/src/mage/cards/s/SelfDestruct.java index fb3b01e108f..8e57a76ef4c 100644 --- a/Mage.Sets/src/mage/cards/s/SelfDestruct.java +++ b/Mage.Sets/src/mage/cards/s/SelfDestruct.java @@ -11,8 +11,8 @@ import mage.filter.predicate.other.AnotherTargetPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetAnyTarget; import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetPermanentOrPlayer; import mage.target.targetpointer.EachTargetPointer; import java.util.List; @@ -36,7 +36,7 @@ public final class SelfDestruct extends CardImpl { // Target creature you control deals X damage to any other target and X damage to itself, where X is its power. this.getSpellAbility().addEffect(new SelfDestructEffect()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent().setTargetTag(1)); - this.getSpellAbility().addTarget(new TargetAnyTarget(filter).setTargetTag(2)); + this.getSpellAbility().addTarget(new TargetPermanentOrPlayer(filter).setTargetTag(2)); } private SelfDestruct(final SelfDestruct card) { diff --git a/Mage.Sets/src/mage/cards/s/SelkieHedgeMage.java b/Mage.Sets/src/mage/cards/s/SelkieHedgeMage.java index ff49fea0ee2..49b6fc221ef 100644 --- a/Mage.Sets/src/mage/cards/s/SelkieHedgeMage.java +++ b/Mage.Sets/src/mage/cards/s/SelkieHedgeMage.java @@ -1,12 +1,11 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; @@ -14,29 +13,33 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.target.TargetPermanent; +import java.util.UUID; + /** * @author jeffwadsworth */ public final class SelkieHedgeMage extends CardImpl { - private static final FilterLandPermanent filter = new FilterLandPermanent("Forests"); - private static final FilterLandPermanent filter2 = new FilterLandPermanent("Islands"); - private static final FilterCreaturePermanent filter3 = new FilterCreaturePermanent("tapped creature"); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.FOREST, "you control two or more Forests"), + ComparisonType.MORE_THAN, 1 + ); + private static final Condition condition2 = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.ISLAND, "you control two or more Islands"), + ComparisonType.MORE_THAN, 1 + ); + private static final FilterPermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(SubType.FOREST.getPredicate()); - filter2.add(SubType.ISLAND.getPredicate()); - filter3.add(TappedPredicate.TAPPED); + filter.add(TappedPredicate.TAPPED); } - private static final String rule1 = "When {this} enters, if you control two or more Forests, you may gain 3 life."; - private static final String rule2 = "When {this} enters, if you control two or more Islands, you may return target tapped creature to its owner's hand."; - public SelkieHedgeMage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G/U}"); this.subtype.add(SubType.MERFOLK); @@ -48,14 +51,12 @@ public final class SelkieHedgeMage extends CardImpl { this.toughness = new MageInt(2); // When Selkie Hedge-Mage enters the battlefield, if you control two or more Forests, you may gain 3 life. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3), true), new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1), rule1); - this.addAbility(ability); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3), true).withInterveningIf(condition)); // When Selkie Hedge-Mage enters the battlefield, if you control two or more Islands, you may return target tapped creature to its owner's hand. - Ability ability2 = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true), new PermanentsOnTheBattlefieldCondition(filter2, ComparisonType.MORE_THAN, 1), rule2); - ability2.addTarget(new TargetPermanent(filter3)); - this.addAbility(ability2); - + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true).withInterveningIf(condition2); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); } private SelkieHedgeMage(final SelkieHedgeMage card) { diff --git a/Mage.Sets/src/mage/cards/s/SentinelsMark.java b/Mage.Sets/src/mage/cards/s/SentinelsMark.java index 6598b4ceaa6..faaaa248f20 100644 --- a/Mage.Sets/src/mage/cards/s/SentinelsMark.java +++ b/Mage.Sets/src/mage/cards/s/SentinelsMark.java @@ -4,7 +4,6 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.AddendumCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; @@ -37,23 +36,19 @@ public final class SentinelsMark extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget)); // Enchanted creature gets +1/+2 and has vigilance. - ability = new SimpleStaticAbility(new BoostEnchantedEffect(1, 2)); + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(1, 2)); ability.addEffect(new GainAbilityAttachedEffect( VigilanceAbility.getInstance(), AttachmentType.AURA ).setText("and has vigilance")); this.addAbility(ability); // Addendum — When Sentinel's Mark enters the battlefield, if you cast it during your main phase, enchanted creature gains lifelink until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new GainAbilityAttachedEffect( - LifelinkAbility.getInstance(), AttachmentType.AURA, Duration.EndOfTurn - )), AddendumCondition.instance, "
Addendum — When {this} enters, " + - "if you cast it during your main phase, enchanted creature gains lifelink until end of turn." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainAbilityAttachedEffect( + LifelinkAbility.getInstance(), AttachmentType.AURA, Duration.EndOfTurn + )).withInterveningIf(AddendumCondition.instance).setAbilityWord(AbilityWord.ADDENDUM)); } private SentinelsMark(final SentinelsMark card) { diff --git a/Mage.Sets/src/mage/cards/s/SenuKeenEyedProtector.java b/Mage.Sets/src/mage/cards/s/SenuKeenEyedProtector.java index 9d2dde61317..33f7e4756e8 100644 --- a/Mage.Sets/src/mage/cards/s/SenuKeenEyedProtector.java +++ b/Mage.Sets/src/mage/cards/s/SenuKeenEyedProtector.java @@ -7,7 +7,6 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.SourceInExileCondition; import mage.abilities.costs.common.ExileSourceCost; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.keyword.ScryEffect; @@ -17,8 +16,7 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -30,13 +28,6 @@ import java.util.UUID; */ public final class SenuKeenEyedProtector extends CardImpl { - private static final FilterPermanent filter = - new FilterControlledCreaturePermanent("a legendary creature you control"); - - static { - filter.add(SuperType.LEGENDARY.getPredicate()); - } - public SenuKeenEyedProtector(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); @@ -53,24 +44,15 @@ public final class SenuKeenEyedProtector extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // {T}, Exile Senu, Keen-Eyed Protector: You gain 2 life and scry 2. - Ability ability = new SimpleActivatedAbility( - new GainLifeEffect(2), - new TapSourceCost() - ); + Ability ability = new SimpleActivatedAbility(new GainLifeEffect(2), new TapSourceCost()); ability.addCost(new ExileSourceCost()); ability.addEffect(new ScryEffect(2).concatBy("and")); this.addAbility(ability); // When a legendary creature you control attacks and isn't blocked, if Senu is exiled, put it onto the battlefield attacking. - this.addAbility( - new ConditionalInterveningIfTriggeredAbility( - new AttacksAndIsNotBlockedAllTriggeredAbility( - Zone.EXILED, new SenuKeenEyedProtectorEffect(), filter - ), SourceInExileCondition.instance, - "When a legendary creature you control attacks and isn't blocked, " - + "if {this} is exiled, put it onto the battlefield attacking" - ) - ); + this.addAbility(new AttacksAndIsNotBlockedAllTriggeredAbility( + Zone.EXILED, new SenuKeenEyedProtectorEffect(), StaticFilters.FILTER_CONTROLLED_CREATURE_LEGENDARY + ).withInterveningIf(SourceInExileCondition.instance).setTriggerPhrase("When a legendary creature you control attacks and isn't blocked, ")); } private SenuKeenEyedProtector(final SenuKeenEyedProtector card) { @@ -113,5 +95,4 @@ class SenuKeenEyedProtectorEffect extends OneShotEffect { } return true; } - -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/SepulchralPrimordial.java b/Mage.Sets/src/mage/cards/s/SepulchralPrimordial.java index 40f47af3a78..412d01515fa 100644 --- a/Mage.Sets/src/mage/cards/s/SepulchralPrimordial.java +++ b/Mage.Sets/src/mage/cards/s/SepulchralPrimordial.java @@ -62,7 +62,7 @@ public final class SepulchralPrimordial extends CardImpl { class SepulchralPrimordialEffect extends OneShotEffect { SepulchralPrimordialEffect() { - super(Outcome.PutCreatureInPlay); + super(Outcome.GainControl); this.staticText = "for each opponent, you may put up to one target creature card from that player's graveyard onto the battlefield under your control"; } diff --git a/Mage.Sets/src/mage/cards/s/SerendibSorcerer.java b/Mage.Sets/src/mage/cards/s/SerendibSorcerer.java index 32afdb747a2..e52caae46cd 100644 --- a/Mage.Sets/src/mage/cards/s/SerendibSorcerer.java +++ b/Mage.Sets/src/mage/cards/s/SerendibSorcerer.java @@ -15,6 +15,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class SerendibSorcerer extends CardImpl { // {tap}: Target creature other than Serendib Sorcerer becomes 0/2 until end of turn. Ability ability = new SimpleActivatedAbility(new SetBasePowerToughnessTargetEffect(0, 2, Duration.EndOfTurn), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SereneMaster.java b/Mage.Sets/src/mage/cards/s/SereneMaster.java index 380d30a4f0d..6ad0063c779 100644 --- a/Mage.Sets/src/mage/cards/s/SereneMaster.java +++ b/Mage.Sets/src/mage/cards/s/SereneMaster.java @@ -18,6 +18,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -44,7 +45,7 @@ public final class SereneMaster extends CardImpl { // Whenever Serene Master blocks, exchange its power and the power of target creature it's blocking until end of combat. Ability ability = new BlocksSourceTriggeredAbility(new SereneMasterEffect()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/Serenity.java b/Mage.Sets/src/mage/cards/s/Serenity.java index ae237a58487..74a96e6cc80 100644 --- a/Mage.Sets/src/mage/cards/s/Serenity.java +++ b/Mage.Sets/src/mage/cards/s/Serenity.java @@ -1,31 +1,26 @@ - package mage.cards.s; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.common.OnEventTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DestroyAllEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; -import mage.game.events.GameEvent.EventType; + +import java.util.UUID; /** - * * @author Quercitron */ public final class Serenity extends CardImpl { public Serenity(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{W}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); // At the beginning of your upkeep, destroy all artifacts and enchantments. They can't be regenerated. - Effect effect = new DestroyAllEffect(StaticFilters.FILTER_PERMANENT_ARTIFACTS_AND_ENCHANTMENTS, true); - Ability ability = new OnEventTriggeredAbility(EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", effect, false); - this.addAbility(ability); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DestroyAllEffect( + StaticFilters.FILTER_PERMANENT_ARTIFACTS_AND_ENCHANTMENTS, true + ))); } private Serenity(final Serenity card) { diff --git a/Mage.Sets/src/mage/cards/s/SergeantAtArms.java b/Mage.Sets/src/mage/cards/s/SergeantAtArms.java index 2ef8849f74a..22ce6abd788 100644 --- a/Mage.Sets/src/mage/cards/s/SergeantAtArms.java +++ b/Mage.Sets/src/mage/cards/s/SergeantAtArms.java @@ -1,11 +1,8 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; @@ -14,8 +11,9 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.game.permanent.token.SoldierToken; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class SergeantAtArms extends CardImpl { @@ -32,9 +30,8 @@ public final class SergeantAtArms extends CardImpl { this.addAbility(new KickerAbility("{2}{W}")); // When Sergeant-at-Arms enters the battlefield, if it was kicked, create two 1/1 white soldier creature tokens. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new SoldierToken(), 2)), KickedCondition.ONCE, - "When {this} enters, if it was kicked, create two 1/1 white Soldier creature tokens.")); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new SoldierToken(), 2)) + .withInterveningIf(KickedCondition.ONCE)); } private SergeantAtArms(final SergeantAtArms card) { diff --git a/Mage.Sets/src/mage/cards/s/SerpentAssassin.java b/Mage.Sets/src/mage/cards/s/SerpentAssassin.java index 18d32d8794f..f8f668249c2 100644 --- a/Mage.Sets/src/mage/cards/s/SerpentAssassin.java +++ b/Mage.Sets/src/mage/cards/s/SerpentAssassin.java @@ -10,8 +10,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author fireshoes @@ -27,7 +30,7 @@ public final class SerpentAssassin extends CardImpl { // When Serpent Assassin enters the battlefield, you may destroy target nonblack creature. Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), true); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + ability.addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SerpentineSpike.java b/Mage.Sets/src/mage/cards/s/SerpentineSpike.java index 62841f30aad..b1eedebb8a7 100644 --- a/Mage.Sets/src/mage/cards/s/SerpentineSpike.java +++ b/Mage.Sets/src/mage/cards/s/SerpentineSpike.java @@ -1,9 +1,6 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.replacement.DealtDamageToCreatureBySourceDies; import mage.abilities.keyword.DevoidAbility; @@ -12,19 +9,29 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.other.AnotherTargetPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.watchers.common.DamagedByWatcher; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SerpentineSpike extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("another creature"); + + static { + filter.add(new AnotherTargetPredicate(3)); + } + public SerpentineSpike(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{5}{R}{R}"); @@ -33,26 +40,12 @@ public final class SerpentineSpike extends CardImpl { // Serpentine Spike deals 2 damage to target creature, 3 damage to another target creature, and 4 damage to a third target creature. If a creature dealt damage this way would die this turn, exile it instead. this.getSpellAbility().addEffect(new SerpentineSpikeEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("2 damage").setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2).withChooseHint("3 damage").setTargetTag(2)); + this.getSpellAbility().addTarget(new TargetPermanent(filter).withChooseHint("4 damage").setTargetTag(3)); - TargetCreaturePermanent target = new TargetCreaturePermanent(new FilterCreaturePermanent("creature (2 damage)")); - target.setTargetTag(1); - this.getSpellAbility().addTarget(target); - - FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature (3 damage)"); - filter.add(new AnotherTargetPredicate(2)); - target = new TargetCreaturePermanent(filter); - target.setTargetTag(2); - this.getSpellAbility().addTarget(target); - - filter = new FilterCreaturePermanent("another target creature (4 damage)"); - filter.add(new AnotherTargetPredicate(3)); - target = new TargetCreaturePermanent(filter); - target.setTargetTag(3); - this.getSpellAbility().addTarget(target); - - Effect effect = new DealtDamageToCreatureBySourceDies(this, Duration.EndOfTurn); - effect.setText("If a creature dealt damage this way would die this turn, exile it instead"); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(new DealtDamageToCreatureBySourceDies(this, Duration.EndOfTurn) + .setText("If a creature dealt damage this way would die this turn, exile it instead")); this.getSpellAbility().addWatcher(new DamagedByWatcher(false)); } diff --git a/Mage.Sets/src/mage/cards/s/SerraAdvocate.java b/Mage.Sets/src/mage/cards/s/SerraAdvocate.java index fedb8c4d002..9a3291dade6 100644 --- a/Mage.Sets/src/mage/cards/s/SerraAdvocate.java +++ b/Mage.Sets/src/mage/cards/s/SerraAdvocate.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterAttackingOrBlockingCreature; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -34,7 +35,7 @@ public final class SerraAdvocate extends CardImpl { // {tap}: Target attacking or blocking creature gets +2/+2 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(2, 2, Duration.EndOfTurn), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(new FilterAttackingOrBlockingCreature())); + ability.addTarget(new TargetPermanent(new FilterAttackingOrBlockingCreature())); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SerumCoreChimera.java b/Mage.Sets/src/mage/cards/s/SerumCoreChimera.java index d96b62c13d5..fcf29c2f18b 100644 --- a/Mage.Sets/src/mage/cards/s/SerumCoreChimera.java +++ b/Mage.Sets/src/mage/cards/s/SerumCoreChimera.java @@ -7,12 +7,10 @@ import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.costs.common.RemoveCountersSourceCost; import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.DoWhenCostPaid; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.FlyingAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -50,7 +48,7 @@ public class SerumCoreChimera extends CardImpl { reflexiveTriggeredAbility.addTarget(new TargetCreatureOrPlaneswalker()); activateAsSorceryActivatedAbility.addEffect(new DoWhenCostPaid(reflexiveTriggeredAbility, new DiscardCardCost(StaticFilters.FILTER_CARD_A_NON_LAND), "Discard nonland card?") - .setText("Then you may discard a nonland card. When you discard a card this way, Serum-Core Chimera " + + .setText("Then you may discard a nonland card. When you discard a card this way, {this} " + "deals 3 damage to target creature or planeswalker.")); this.addAbility(activateAsSorceryActivatedAbility); } diff --git a/Mage.Sets/src/mage/cards/s/ServantOfTheStinger.java b/Mage.Sets/src/mage/cards/s/ServantOfTheStinger.java index ce1d397992b..ebd6817ab4f 100644 --- a/Mage.Sets/src/mage/cards/s/ServantOfTheStinger.java +++ b/Mage.Sets/src/mage/cards/s/ServantOfTheStinger.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.condition.common.CommittedCrimeCondition; import mage.abilities.costs.common.SacrificeSourceCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.keyword.DeathtouchAbility; @@ -34,16 +33,9 @@ public final class ServantOfTheStinger extends CardImpl { this.addAbility(DeathtouchAbility.getInstance()); // Whenever Servant of the Stinger deals combat damage to a player, if you've committed a crime this turn, you may sacrifice Servant of the Stinger. If you do, search your library for a card, put it into your hand, then shuffle. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new DealsCombatDamageToAPlayerTriggeredAbility( - new DoIfCostPaid( - new SearchLibraryPutInHandEffect(new TargetCardInLibrary(), false), - new SacrificeSourceCost() - ), false - ), CommittedCrimeCondition.instance, "Whenever {this} deals combat damage to a player, " + - "if you've committed a crime this turn, you may sacrifice {this}. If you do, " + - "search your library for a card, put it into your hand, then shuffle." - ).addHint(CommittedCrimeCondition.getHint()), new CommittedCrimeWatcher()); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new DoIfCostPaid( + new SearchLibraryPutInHandEffect(new TargetCardInLibrary(), false), new SacrificeSourceCost() + )).withInterveningIf(CommittedCrimeCondition.instance).addHint(CommittedCrimeCondition.getHint()), new CommittedCrimeWatcher()); } private ServantOfTheStinger(final ServantOfTheStinger card) { diff --git a/Mage.Sets/src/mage/cards/s/SetessanTactics.java b/Mage.Sets/src/mage/cards/s/SetessanTactics.java index 9a2ab8bb6f9..63e244f25a1 100644 --- a/Mage.Sets/src/mage/cards/s/SetessanTactics.java +++ b/Mage.Sets/src/mage/cards/s/SetessanTactics.java @@ -15,6 +15,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -42,7 +43,7 @@ public final class SetessanTactics extends CardImpl { effect.setText("Until end of turn, any number of target creatures each get +1/+1"); this.getSpellAbility().addEffect(effect); Ability gainedAbility = new SimpleActivatedAbility(new FightTargetSourceEffect(), new TapSourceCost()); - gainedAbility.addTarget(new TargetCreaturePermanent(filter)); + gainedAbility.addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new GainAbilityTargetEffect(gainedAbility, Duration.EndOfTurn, "and gain \"{T}: This creature fights another target creature.\"")); } diff --git a/Mage.Sets/src/mage/cards/s/SettlementBlacksmith.java b/Mage.Sets/src/mage/cards/s/SettlementBlacksmith.java index 08e8d1b21a9..49d8c5862d6 100644 --- a/Mage.Sets/src/mage/cards/s/SettlementBlacksmith.java +++ b/Mage.Sets/src/mage/cards/s/SettlementBlacksmith.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; @@ -21,8 +20,10 @@ import java.util.UUID; */ public final class SettlementBlacksmith extends CardImpl { - private static final Condition condition = new PermanentsOnTheBattlefieldCondition(new FilterControlledPermanent(SubType.EQUIPMENT)); - private static final Hint hint = new ConditionHint(condition, "You control an Equipment"); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.EQUIPMENT, "you control an Equipment") + ); + private static final Hint hint = new ConditionHint(condition); public SettlementBlacksmith(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); @@ -33,10 +34,8 @@ public final class SettlementBlacksmith extends CardImpl { this.toughness = new MageInt(3); // When Settlement Blacksmith enters the battlefield, if you control an Equipment, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)), - condition, "When {this} enters, if you control an Equipment, draw a card." - ).addHint(hint)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .withInterveningIf(condition).addHint(hint)); } private SettlementBlacksmith(final SettlementBlacksmith card) { diff --git a/Mage.Sets/src/mage/cards/s/SeverSoul.java b/Mage.Sets/src/mage/cards/s/SeverSoul.java index 2bb08849296..80c1a99f6ea 100644 --- a/Mage.Sets/src/mage/cards/s/SeverSoul.java +++ b/Mage.Sets/src/mage/cards/s/SeverSoul.java @@ -12,8 +12,11 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author dustinconrad @@ -24,7 +27,7 @@ public final class SeverSoul extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}{B}"); // Destroy target nonblack creature. It can't be regenerated. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); // You gain life equal to its toughness. this.getSpellAbility().addEffect(new GainLifeEqualToToughnessEffect()); diff --git a/Mage.Sets/src/mage/cards/s/ShadowTheHedgehog.java b/Mage.Sets/src/mage/cards/s/ShadowTheHedgehog.java new file mode 100644 index 00000000000..cd92487b8a6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShadowTheHedgehog.java @@ -0,0 +1,83 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.DiesThisOrAnotherTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledSpellsEffect; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.SplitSecondAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterNonlandCard; +import mage.filter.predicate.Predicate; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.watchers.common.ManaPaidSourceWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ShadowTheHedgehog extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("creature you control with flash or haste"); + private static final FilterNonlandCard filter2 = new FilterNonlandCard(); + + static { + filter.add(Predicates.or( + new AbilityPredicate(FlashAbility.class), + new AbilityPredicate(HasteAbility.class) + )); + filter2.add(ShadowTheHedgehogPredicate.instance); + } + + public ShadowTheHedgehog(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{B}{R}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HEDGEHOG); + this.subtype.add(SubType.MERCENARY); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Whenever Shadow the Hedgehog or another creature you control with flash or haste dies, draw a card. + this.addAbility(new DiesThisOrAnotherTriggeredAbility(new DrawCardSourceControllerEffect(1), false, filter)); + + // Chaos Control -- Each spell you cast has split second if mana from an artifact was spent to cast it. + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledSpellsEffect(new SplitSecondAbility(), filter2) + .setText("each spell you cast has split second if mana from an artifact was spent to cast it")).withFlavorWord("Chaos Control")); + } + + private ShadowTheHedgehog(final ShadowTheHedgehog card) { + super(card); + } + + @Override + public ShadowTheHedgehog copy() { + return new ShadowTheHedgehog(this); + } +} + +enum ShadowTheHedgehogPredicate implements Predicate { + instance; + + @Override + public boolean apply(Card input, Game game) { + return input instanceof Spell && ManaPaidSourceWatcher.getArtifactPaid(input.getId(), game) > 0; + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShadowbornDemon.java b/Mage.Sets/src/mage/cards/s/ShadowbornDemon.java index 6afac6d2232..b4550127ce1 100644 --- a/Mage.Sets/src/mage/cards/s/ShadowbornDemon.java +++ b/Mage.Sets/src/mage/cards/s/ShadowbornDemon.java @@ -1,16 +1,15 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.CardsInControllerGraveyardCondition; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.SacrificeControllerEffect; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -18,13 +17,12 @@ import mage.constants.SubType; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; -import mage.game.Game; -import mage.players.Player; -import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ShadowbornDemon extends CardImpl { @@ -35,6 +33,11 @@ public final class ShadowbornDemon extends CardImpl { filter.add(Predicates.not(SubType.DEMON.getPredicate())); } + private static final Condition condition = new InvertCondition( + new CardsInControllerGraveyardCondition(6, StaticFilters.FILTER_CARD_CREATURE), + "there are fewer than six creature cards in your graveyard" + ); + public ShadowbornDemon(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); this.subtype.add(SubType.DEMON); @@ -44,18 +47,16 @@ public final class ShadowbornDemon extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); + // When Shadowborn Demon enters the battlefield, destroy target non-Demon creature. Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), false); - Target target = new TargetCreaturePermanent(filter); - ability.addTarget(target); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // At the beginning of your upkeep, if there are fewer than six creature cards in your graveyard, sacrifice a creature. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new SacrificeControllerEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 1, "")), - new InvertCondition(new CreatureCardsInControllerGraveyardCondition(6)), - "At the beginning of your upkeep, if there are fewer than six creature cards in your graveyard, sacrifice a creature")); - + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeControllerEffect( + StaticFilters.FILTER_PERMANENT_CREATURE, 1, "" + )).withInterveningIf(condition)); } private ShadowbornDemon(final ShadowbornDemon card) { @@ -67,21 +68,3 @@ public final class ShadowbornDemon extends CardImpl { return new ShadowbornDemon(this); } } - -class CreatureCardsInControllerGraveyardCondition implements Condition { - - private int value; - - public CreatureCardsInControllerGraveyardCondition(int value) { - this.value = value; - } - - @Override - public boolean apply(Game game, Ability source) { - Player p = game.getPlayer(source.getControllerId()); - if (p != null && p.getGraveyard().count(StaticFilters.FILTER_CARD_CREATURE, game) >= value) { - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/s/ShadowgrangeArchfiend.java b/Mage.Sets/src/mage/cards/s/ShadowgrangeArchfiend.java index b6d68eb9440..ede974a47e9 100644 --- a/Mage.Sets/src/mage/cards/s/ShadowgrangeArchfiend.java +++ b/Mage.Sets/src/mage/cards/s/ShadowgrangeArchfiend.java @@ -20,7 +20,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.ArrayList; import java.util.List; @@ -47,10 +47,14 @@ public final class ShadowgrangeArchfiend extends CardImpl { this.addAbility(madnessAbility); } - private ShadowgrangeArchfiend(final ShadowgrangeArchfiend card) { super(card); } + private ShadowgrangeArchfiend(final ShadowgrangeArchfiend card) { + super(card); + } @Override - public ShadowgrangeArchfiend copy() { return new ShadowgrangeArchfiend(this); } + public ShadowgrangeArchfiend copy() { + return new ShadowgrangeArchfiend(this); + } } class ShadowgrangeArchfiendEffect extends OneShotEffect { @@ -61,10 +65,14 @@ class ShadowgrangeArchfiendEffect extends OneShotEffect { "You gain life equal to the greatest power among creatures sacrificed this way"; } - private ShadowgrangeArchfiendEffect(final ShadowgrangeArchfiendEffect effect) { super(effect); } + private ShadowgrangeArchfiendEffect(final ShadowgrangeArchfiendEffect effect) { + super(effect); + } @Override - public ShadowgrangeArchfiendEffect copy() { return new ShadowgrangeArchfiendEffect(this); } + public ShadowgrangeArchfiendEffect copy() { + return new ShadowgrangeArchfiendEffect(this); + } @Override public boolean apply(Game game, Ability source) { @@ -77,10 +85,14 @@ class ShadowgrangeArchfiendEffect extends OneShotEffect { // Iterate through each opponent for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - if (!controller.hasOpponent(playerId, game)) { continue; } + if (!controller.hasOpponent(playerId, game)) { + continue; + } Player opponent = game.getPlayer(playerId); - if (opponent == null) { continue; } + if (opponent == null) { + continue; + } int greatestPower = Integer.MIN_VALUE; int numberOfCreatures = 0; @@ -102,7 +114,7 @@ class ShadowgrangeArchfiendEffect extends OneShotEffect { FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent( "creature to sacrifice with power equal to " + greatestPower); filter.add(new PowerPredicate(ComparisonType.EQUAL_TO, greatestPower)); - Target target = new TargetControlledCreaturePermanent(filter); + Target target = new TargetPermanent(filter); if (opponent.choose(outcome, target, source, game)) { creatureToSacrifice = game.getPermanent(target.getFirstTarget()); } diff --git a/Mage.Sets/src/mage/cards/s/ShadowsOfThePast.java b/Mage.Sets/src/mage/cards/s/ShadowsOfThePast.java index 6d87bf22b93..dc0c740887f 100644 --- a/Mage.Sets/src/mage/cards/s/ShadowsOfThePast.java +++ b/Mage.Sets/src/mage/cards/s/ShadowsOfThePast.java @@ -1,27 +1,28 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; -import mage.abilities.effects.Effect; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.abilities.effects.keyword.ScryEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ShadowsOfThePast extends CardImpl { + private static final Condition condition = new CardsInControllerGraveyardCondition(4, StaticFilters.FILTER_CARD_CREATURES); + public ShadowsOfThePast(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); @@ -29,11 +30,10 @@ public final class ShadowsOfThePast extends CardImpl { this.addAbility(new DiesCreatureTriggeredAbility(new ScryEffect(1), false)); // {4}{B}: Each opponent loses 2 life and you gain 2 life. Activate this ability only if there are four or more creature cards in your graveyard. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new LoseLifeOpponentsEffect(2), new ManaCostsImpl<>("{4}{B}"), new CardsInControllerGraveyardCondition(4, StaticFilters.FILTER_CARD_CREATURES)); - Effect effect = new GainLifeEffect(2); - effect.setText("and you gain 2 life"); - ability.addEffect(effect); + Ability ability = new ActivateIfConditionActivatedAbility( + new LoseLifeOpponentsEffect(2), new ManaCostsImpl<>("{4}{B}"), condition + ); + ability.addEffect(new GainLifeEffect(2).concatBy("and")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/ShaileDeanOfRadiance.java b/Mage.Sets/src/mage/cards/s/ShaileDeanOfRadiance.java index a825384c496..50e56b506c4 100644 --- a/Mage.Sets/src/mage/cards/s/ShaileDeanOfRadiance.java +++ b/Mage.Sets/src/mage/cards/s/ShaileDeanOfRadiance.java @@ -24,6 +24,7 @@ import mage.filter.predicate.Predicate; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.permanent.EnteredThisTurnPredicate; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -72,7 +73,7 @@ public final class ShaileDeanOfRadiance extends ModalDoubleFacedCard { // {T}: Put a +1/+1 counter on another target creature, then Embrose, Dean of Shadow deals 2 damage to that creature. Ability ability = new SimpleActivatedAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new TapSourceCost()); ability.addEffect(new DamageTargetEffect(2).concatBy(", then").setText("{this} deals 2 damage to that creature")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.getRightHalfCard().addAbility(ability); // Whenever a creature you control with a +1/+1 counter on it dies, draw a card. @@ -87,4 +88,4 @@ public final class ShaileDeanOfRadiance extends ModalDoubleFacedCard { public ShaileDeanOfRadiance copy() { return new ShaileDeanOfRadiance(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/ShamanOfForgottenWays.java b/Mage.Sets/src/mage/cards/s/ShamanOfForgottenWays.java index 0743bbb71b6..482e2c26527 100644 --- a/Mage.Sets/src/mage/cards/s/ShamanOfForgottenWays.java +++ b/Mage.Sets/src/mage/cards/s/ShamanOfForgottenWays.java @@ -1,14 +1,9 @@ - package mage.cards.s; -import java.util.UUID; import mage.ConditionalMana; import mage.MageInt; -import mage.MageObject; -import mage.Mana; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.condition.Condition; import mage.abilities.condition.common.FormidableCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -20,40 +15,36 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; -import mage.game.stack.Spell; import mage.players.Player; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ShamanOfForgottenWays extends CardImpl { public ShamanOfForgottenWays(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SHAMAN); - this.power = new MageInt( 2); + this.power = new MageInt(2); this.toughness = new MageInt(3); // {T}:Add two mana in any combination of colors. Spend this mana only to cast creature spells. this.addAbility(new ConditionalAnyColorManaAbility(2, new ShamanOfForgottenWaysManaBuilder())); - + // Formidable — {9}{G}{G},{T}:Each player's life total becomes the number of creatures they control. Activate the ability only if creatures you control have total power 8 or greater. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new ShamanOfForgottenWaysEffect(), - new ManaCostsImpl<>("{9}{G}{G}"), - FormidableCondition.instance); + new ShamanOfForgottenWaysEffect(), new ManaCostsImpl<>("{9}{G}{G}"), FormidableCondition.instance + ); ability.addCost(new TapSourceCost()); - ability.setAbilityWord(AbilityWord.FORMIDABLE); - this.addAbility(ability); + this.addAbility(ability.setAbilityWord(AbilityWord.FORMIDABLE)); } private ShamanOfForgottenWays(final ShamanOfForgottenWays card) { @@ -80,29 +71,29 @@ class ShamanOfForgottenWaysManaBuilder extends ConditionalManaBuilder { } class ShamanOfForgottenWaysEffect extends OneShotEffect { - + public ShamanOfForgottenWaysEffect() { super(Outcome.Benefit); this.staticText = "each player's life total becomes the number of creatures they control"; } - + private ShamanOfForgottenWaysEffect(final ShamanOfForgottenWaysEffect effect) { super(effect); } - + @Override public ShamanOfForgottenWaysEffect copy() { return new ShamanOfForgottenWaysEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { FilterPermanent filter = new FilterCreaturePermanent(); - for(UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); - if (player != null){ + if (player != null) { int numberCreatures = game.getBattlefield().getAllActivePermanents(filter, playerId, game).size(); player.setLife(numberCreatures, game, source); } diff --git a/Mage.Sets/src/mage/cards/s/ShamblingGoblin.java b/Mage.Sets/src/mage/cards/s/ShamblingGoblin.java index 4b6137c2fc8..1a474fb4edb 100644 --- a/Mage.Sets/src/mage/cards/s/ShamblingGoblin.java +++ b/Mage.Sets/src/mage/cards/s/ShamblingGoblin.java @@ -12,8 +12,11 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Duration; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -29,7 +32,7 @@ public final class ShamblingGoblin extends CardImpl { // When Shambling Goblin dies, target creature an opponent controls gets -1/-1 until end of turn. Ability ability = new DiesSourceTriggeredAbility(new BoostTargetEffect(-1,-1, Duration.EndOfTurn)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/ShardOfTheNightbringer.java b/Mage.Sets/src/mage/cards/s/ShardOfTheNightbringer.java index 084e52c4b16..04e66dc53b7 100644 --- a/Mage.Sets/src/mage/cards/s/ShardOfTheNightbringer.java +++ b/Mage.Sets/src/mage/cards/s/ShardOfTheNightbringer.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -34,12 +33,8 @@ public final class ShardOfTheNightbringer extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Drain Life -- When Shard of the Nightbringer enters the battlefield, if you cast it, target opponent loses half their life, rounded up. You gain life equal to the life lost this way. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ShardOfTheNightbringerEffect()), - CastFromEverywhereSourceCondition.instance, "When {this} enters, " + - "if you cast it, target opponent loses half their life, rounded up. " + - "You gain life equal to the life lost this way." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new ShardOfTheNightbringerEffect()) + .withInterveningIf(CastFromEverywhereSourceCondition.instance); ability.addTarget(new TargetOpponent()); this.addAbility(ability.withFlavorWord("Drain Life")); } @@ -58,6 +53,7 @@ class ShardOfTheNightbringerEffect extends OneShotEffect { ShardOfTheNightbringerEffect() { super(Outcome.Benefit); + staticText = "target opponent loses half their life, rounded up. You gain life equal to the life lost this way"; } private ShardOfTheNightbringerEffect(final ShardOfTheNightbringerEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/ShardPhoenix.java b/Mage.Sets/src/mage/cards/s/ShardPhoenix.java index 8fe4588d762..664775afc9b 100644 --- a/Mage.Sets/src/mage/cards/s/ShardPhoenix.java +++ b/Mage.Sets/src/mage/cards/s/ShardPhoenix.java @@ -1,13 +1,11 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; import mage.abilities.keyword.FlyingAbility; @@ -15,18 +13,18 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.PhaseStep; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; +import java.util.UUID; + /** - * * @author fireshoes */ public final class ShardPhoenix extends CardImpl { - + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature without flying"); static { @@ -34,20 +32,22 @@ public final class ShardPhoenix extends CardImpl { } public ShardPhoenix(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); this.subtype.add(SubType.PHOENIX); this.power = new MageInt(2); this.toughness = new MageInt(2); // Flying this.addAbility(FlyingAbility.getInstance()); - + // Sacrifice Shard Phoenix: Shard Phoenix deals 2 damage to each creature without flying. this.addAbility(new SimpleActivatedAbility(new DamageAllEffect(2, "it", filter), new SacrificeSourceCost())); - + // {R}{R}{R}: Return Shard Phoenix from your graveyard to your hand. Activate this ability only during your upkeep. - this.addAbility(new ConditionalActivatedAbility(Zone.GRAVEYARD, - new ReturnSourceFromGraveyardToHandEffect(), new ManaCostsImpl<>("{R}{R}{R}"), new IsStepCondition(PhaseStep.UPKEEP), null)); + this.addAbility(new ActivateIfConditionActivatedAbility( + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), + new ManaCostsImpl<>("{R}{R}{R}"), IsStepCondition.getMyUpkeep() + )); } private ShardPhoenix(final ShardPhoenix card) { diff --git a/Mage.Sets/src/mage/cards/s/SharedDiscovery.java b/Mage.Sets/src/mage/cards/s/SharedDiscovery.java index c3d2d72d5d7..4f30bdc11ca 100644 --- a/Mage.Sets/src/mage/cards/s/SharedDiscovery.java +++ b/Mage.Sets/src/mage/cards/s/SharedDiscovery.java @@ -1,36 +1,27 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.costs.common.TapTargetCost; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class SharedDiscovery extends CardImpl { - - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); - - static { - filter.add(TappedPredicate.UNTAPPED); - } public SharedDiscovery(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}"); // As an additional cost to cast Shared Discovery, tap four untapped creatures you control. + this.getSpellAbility().addCost(new TapTargetCost(4, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES)); + // Draw three cards. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(3)); - this.getSpellAbility().addCost(new TapTargetCost(new TargetControlledCreaturePermanent(4, 4, filter, true))); } private SharedDiscovery(final SharedDiscovery card) { diff --git a/Mage.Sets/src/mage/cards/s/SharkTyphoon.java b/Mage.Sets/src/mage/cards/s/SharkTyphoon.java index 97e6883c30a..5e853ee68c9 100644 --- a/Mage.Sets/src/mage/cards/s/SharkTyphoon.java +++ b/Mage.Sets/src/mage/cards/s/SharkTyphoon.java @@ -1,25 +1,20 @@ package mage.cards.s; import mage.abilities.Ability; +import mage.abilities.common.CycleTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; -import mage.abilities.common.ZoneChangeTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.CyclingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SetTargetPointer; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.token.SharkToken; import mage.game.stack.Spell; -import mage.game.stack.StackObject; -import mage.util.CardUtil; import java.util.UUID; @@ -42,7 +37,7 @@ public final class SharkTyphoon extends CardImpl { this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{X}{1}{U}"))); // When you cycle Shark Typhoon, create an X/X blue Shark creature token with flying. - this.addAbility(new SharkTyphoonTriggeredAbility()); + this.addAbility(new CycleTriggeredAbility(new SharkTyphoonCycleEffect())); } private SharkTyphoon(final SharkTyphoon card) { @@ -82,42 +77,29 @@ class SharkTyphoonCastEffect extends OneShotEffect { } } -class SharkTyphoonTriggeredAbility extends ZoneChangeTriggeredAbility { +class SharkTyphoonCycleEffect extends OneShotEffect { - SharkTyphoonTriggeredAbility() { - super(Zone.ALL, null, "", false); + SharkTyphoonCycleEffect() { + super(Outcome.Benefit); + staticText = "create an X/X blue Shark creature token with flying"; } - private SharkTyphoonTriggeredAbility(SharkTyphoonTriggeredAbility ability) { - super(ability); + private SharkTyphoonCycleEffect(final SharkTyphoonCycleEffect effect) { + super(effect); } @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY; + public SharkTyphoonCycleEffect copy() { + return new SharkTyphoonCycleEffect(this); } @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (!event.getSourceId().equals(this.getSourceId())) { - return false; + public boolean apply(Game game, Ability source) { + Object xValueObject = getValue("cycleXValue"); + int xValue = 0; + if (xValueObject instanceof Integer) { + xValue = (int) xValueObject; } - StackObject object = game.getStack().getStackObject(event.getSourceId()); - if (object == null || !(object.getStackAbility() instanceof CyclingAbility)) { - return false; - } - this.getEffects().clear(); - this.addEffect(new CreateTokenEffect(new SharkToken(CardUtil.getSourceCostsTag(game, object.getStackAbility(), "X", 0)))); - return true; - } - - @Override - public SharkTyphoonTriggeredAbility copy() { - return new SharkTyphoonTriggeredAbility(this); - } - - @Override - public String getRule() { - return "When you cycle this card, create an X/X blue Shark creature token with flying."; + return new SharkToken(xValue).putOntoBattlefield(1, game, source, source.getControllerId()); } } diff --git a/Mage.Sets/src/mage/cards/s/ShatteredWings.java b/Mage.Sets/src/mage/cards/s/ShatteredWings.java new file mode 100644 index 00000000000..f0a7826dad4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShatteredWings.java @@ -0,0 +1,52 @@ +package mage.cards.s; + +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ShatteredWings extends CardImpl { + + private static final FilterPermanent filter + = new FilterPermanent("artifact, enchantment, or creature with flying"); + + static { + filter.add(Predicates.or( + CardType.ARTIFACT.getPredicate(), + CardType.ENCHANTMENT.getPredicate(), + Predicates.and( + CardType.CREATURE.getPredicate(), + new AbilityPredicate(FlyingAbility.class) + ) + )); + } + + public ShatteredWings(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); + + // Destroy target artifact, enchantment, or creature with flying. Surveil 1. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + this.getSpellAbility().addEffect(new SurveilEffect(1)); + } + + private ShatteredWings(final ShatteredWings card) { + super(card); + } + + @Override + public ShatteredWings copy() { + return new ShatteredWings(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShatterskullCharger.java b/Mage.Sets/src/mage/cards/s/ShatterskullCharger.java index 626b8bac5a0..2ca8b1bde0f 100644 --- a/Mage.Sets/src/mage/cards/s/ShatterskullCharger.java +++ b/Mage.Sets/src/mage/cards/s/ShatterskullCharger.java @@ -1,18 +1,17 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.KickedCondition; import mage.abilities.condition.common.SourceHasCounterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnToHandSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.KickerAbility; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -26,8 +25,10 @@ import java.util.UUID; */ public final class ShatterskullCharger extends CardImpl { - private static final Condition condition - = new InvertCondition(new SourceHasCounterCondition(CounterType.P1P1, 1)); + private static final Condition condition = new InvertCondition( + new SourceHasCounterCondition(CounterType.P1P1), + "{this} doesn't have a +1/+1 counter on it" + ); public ShatterskullCharger(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); @@ -53,12 +54,8 @@ public final class ShatterskullCharger extends CardImpl { )); // At the beginning of your end step, if Shatterskull Charger doesn't have a +1/+1 counter on it, return it to its owner's hand. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - new ReturnToHandSourceEffect(true) - ), condition, "At the beginning of your end step, " + - "if {this} doesn't have a +1/+1 counter on it, return it to its owner's hand." - )); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new ReturnToHandSourceEffect(true) + .setText("return it to its owner's hand")).withInterveningIf(condition)); } private ShatterskullCharger(final ShatterskullCharger card) { diff --git a/Mage.Sets/src/mage/cards/s/ShaukusMinion.java b/Mage.Sets/src/mage/cards/s/ShaukusMinion.java index e5bf360d0ca..9fc8c2fdcec 100644 --- a/Mage.Sets/src/mage/cards/s/ShaukusMinion.java +++ b/Mage.Sets/src/mage/cards/s/ShaukusMinion.java @@ -16,6 +16,7 @@ import mage.constants.CardType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -41,7 +42,7 @@ public final class ShaukusMinion extends CardImpl { // {B}{R}, {tap}: Shauku's Minion deals 2 damage to target white creature. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2), new ManaCostsImpl<>("{B}{R}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SheerDrop.java b/Mage.Sets/src/mage/cards/s/SheerDrop.java index 105adfa8300..173031379d7 100644 --- a/Mage.Sets/src/mage/cards/s/SheerDrop.java +++ b/Mage.Sets/src/mage/cards/s/SheerDrop.java @@ -9,6 +9,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -28,7 +29,7 @@ public final class SheerDrop extends CardImpl { // Destroy target tapped creature. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Awaken 3-{5}{W} (If you cast this spell for {5}{W}, also put three +1/+1 counters on target land you control and it becomes a 0/0 Elemental creature with haste. It's still a land.) this.addAbility(new AwakenAbility(this, 3, "{5}{W}")); diff --git a/Mage.Sets/src/mage/cards/s/ShellSkulkin.java b/Mage.Sets/src/mage/cards/s/ShellSkulkin.java index 216337992b3..ba563ac5e19 100644 --- a/Mage.Sets/src/mage/cards/s/ShellSkulkin.java +++ b/Mage.Sets/src/mage/cards/s/ShellSkulkin.java @@ -17,6 +17,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -36,7 +37,7 @@ public final class ShellSkulkin extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(2); Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(ShroudAbility.getInstance(), Duration.EndOfTurn), new GenericManaCost(3)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/ShelteredValley.java b/Mage.Sets/src/mage/cards/s/ShelteredValley.java index dce04980f72..1b545262731 100644 --- a/Mage.Sets/src/mage/cards/s/ShelteredValley.java +++ b/Mage.Sets/src/mage/cards/s/ShelteredValley.java @@ -1,53 +1,53 @@ - package mage.cards.s; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.SacrificeAllCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.EnterBattlefieldPayCostOrPutGraveyardEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.mana.ColorlessManaAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.Zone; import mage.filter.FilterPermanent; -import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledLandPermanent; import mage.filter.predicate.mageobject.NamePredicate; +import java.util.UUID; + /** - * * @author anonymous */ public final class ShelteredValley extends CardImpl { - private static final FilterPermanent filterShelteredValley = new FilterPermanent("permanent named Sheltered Valley"); + private static final FilterPermanent filter = new FilterPermanent("permanent named Sheltered Valley"); static { - filterShelteredValley.add(new NamePredicate("Sheltered Valley")); + filter.add(new NamePredicate("Sheltered Valley")); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledLandPermanent("you control three or fewer lands"), + ComparisonType.FEWER_THAN, 4 + ); + public ShelteredValley(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // If Sheltered Valley would enter the battlefield, instead sacrifice each other permanent named Sheltered Valley you control, then put Sheltered Valley onto the battlefield. - Effect effect = new EnterBattlefieldPayCostOrPutGraveyardEffect(new SacrificeAllCost(filterShelteredValley)); - effect.setText("If {this} would enter the battlefield, instead sacrifice each other permanent named {this} you control, then put {this} onto the battlefield."); - Ability ability = new SimpleStaticAbility(Zone.ALL, effect); - this.addAbility(ability); + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new EnterBattlefieldPayCostOrPutGraveyardEffect(new SacrificeAllCost(filter)) + .setText("If {this} would enter, instead sacrifice each other permanent " + + "named Sheltered Valley you control, then put {this} onto the battlefield.") + )); // At the beginning of your upkeep, if you control three or fewer lands, you gain 1 life. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new GainLifeEffect(1)), - new PermanentsOnTheBattlefieldCondition(StaticFilters.FILTER_LANDS, ComparisonType.FEWER_THAN, 4), - "At the beginning of your upkeep, if you control three or fewer lands, you gain 1 life." - )); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new GainLifeEffect(1)).withInterveningIf(condition)); + // {tap}: Add {C}. this.addAbility(new ColorlessManaAbility()); } diff --git a/Mage.Sets/src/mage/cards/s/ShelteringAncient.java b/Mage.Sets/src/mage/cards/s/ShelteringAncient.java index a5c2d0743a8..7ecef3f4631 100644 --- a/Mage.Sets/src/mage/cards/s/ShelteringAncient.java +++ b/Mage.Sets/src/mage/cards/s/ShelteringAncient.java @@ -11,14 +11,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.TargetController; import mage.counters.CounterType; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; import java.util.UUID; @@ -52,12 +51,6 @@ public final class ShelteringAncient extends CardImpl { class ShelteringAncientCost extends CostImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - ShelteringAncientCost() { this.text = "Put a +1/+1 counter on a creature an opponent controls"; } @@ -70,7 +63,8 @@ class ShelteringAncientCost extends CostImpl { public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { - Target target = new TargetCreaturePermanent(1, 1, filter, true); + Target target = new TargetOpponentsCreaturePermanent(); + target.withNotTarget(true); if (target.choose(Outcome.BoostCreature, controllerId, source.getSourceId(), source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { @@ -85,7 +79,7 @@ class ShelteringAncientCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return game.getBattlefield().contains(filter, source, game, 1); + return game.getBattlefield().contains(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, source, game, 1); } @Override diff --git a/Mage.Sets/src/mage/cards/s/Sheoldred.java b/Mage.Sets/src/mage/cards/s/Sheoldred.java index 2f03cac8bcf..49f1aad0ef4 100644 --- a/Mage.Sets/src/mage/cards/s/Sheoldred.java +++ b/Mage.Sets/src/mage/cards/s/Sheoldred.java @@ -4,7 +4,7 @@ import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CardsInOpponentGraveyardCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.ExileAndReturnSourceEffect; import mage.abilities.effects.common.SacrificeOpponentsEffect; import mage.abilities.keyword.MenaceAbility; @@ -48,7 +48,7 @@ public final class Sheoldred extends CardImpl { // {4}{B}: Exile Sheoldred, then return it to the battlefield transformed under its owner's control. Activate only as a sorcery and only if an opponent has eight or more cards in their graveyard. this.addAbility(new TransformAbility()); - this.addAbility(new ConditionalActivatedAbility( + this.addAbility(new ActivateIfConditionActivatedAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED), new ManaCostsImpl<>("{4}{B}"), CardsInOpponentGraveyardCondition.EIGHT ).setTiming(TimingRule.SORCERY).addHint(CardsInOpponentGraveyardCondition.EIGHT.getHint())); diff --git a/Mage.Sets/src/mage/cards/s/ShieldBroker.java b/Mage.Sets/src/mage/cards/s/ShieldBroker.java index 57327cfb91b..b8589726155 100644 --- a/Mage.Sets/src/mage/cards/s/ShieldBroker.java +++ b/Mage.Sets/src/mage/cards/s/ShieldBroker.java @@ -17,6 +17,7 @@ import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CommanderPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -47,7 +48,7 @@ public class ShieldBroker extends CardImpl { gainControlEffect.setText("You gain control of that creature for as long as it has a shield counter on it. " + "(If it would be dealt damage or destroyed, remove a shield counter from it instead.)"); etbAbility.addEffect(gainControlEffect); - etbAbility.addTarget(new TargetCreaturePermanent(filter)); + etbAbility.addTarget(new TargetPermanent(filter)); this.addAbility(etbAbility); } diff --git a/Mage.Sets/src/mage/cards/s/ShiftingGrift.java b/Mage.Sets/src/mage/cards/s/ShiftingGrift.java index ac26c1d043b..b01634609ca 100644 --- a/Mage.Sets/src/mage/cards/s/ShiftingGrift.java +++ b/Mage.Sets/src/mage/cards/s/ShiftingGrift.java @@ -22,7 +22,6 @@ public final class ShiftingGrift extends CardImpl { public ShiftingGrift(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}{U}"); - // Spree this.addAbility(new SpreeAbility(this)); diff --git a/Mage.Sets/src/mage/cards/s/ShiftingWoodland.java b/Mage.Sets/src/mage/cards/s/ShiftingWoodland.java index b38ec519e59..666139b3a63 100644 --- a/Mage.Sets/src/mage/cards/s/ShiftingWoodland.java +++ b/Mage.Sets/src/mage/cards/s/ShiftingWoodland.java @@ -5,14 +5,13 @@ import mage.abilities.common.EntersBattlefieldTappedUnlessAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.condition.common.YouControlPermanentCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.mana.GreenManaAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.ModalDoubleFacedCard; import mage.constants.*; import mage.filter.FilterCard; import mage.filter.FilterPermanent; @@ -47,7 +46,7 @@ public final class ShiftingWoodland extends CardImpl { this.addAbility(new GreenManaAbility()); // Delirium -- {2}{G}{G}: Shifting Woodland becomes a copy of target permanent card in your graveyard until end of turn. Activate only if there are four or more card types among cards in your graveyard. - Ability ability = new ConditionalActivatedAbility( + Ability ability = new ActivateIfConditionActivatedAbility( new ShiftingWoodlandCopyEffect(), new ManaCostsImpl<>("{2}{G}{G}"), DeliriumCondition.instance @@ -97,4 +96,4 @@ class ShiftingWoodlandCopyEffect extends OneShotEffect { game.copyPermanent(Duration.EndOfTurn, blueprint, sourcePermanent.getId(), source, new EmptyCopyApplier()); return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/ShimianNightStalker.java b/Mage.Sets/src/mage/cards/s/ShimianNightStalker.java index 2dcf1f9f60c..8d841cf5656 100644 --- a/Mage.Sets/src/mage/cards/s/ShimianNightStalker.java +++ b/Mage.Sets/src/mage/cards/s/ShimianNightStalker.java @@ -43,7 +43,7 @@ public final class ShimianNightStalker extends CardImpl { // {B}, {T}: All damage that would be dealt to you this turn by target attacking creature is dealt to Shimian Night Stalker instead. Ability ability = new SimpleActivatedAbility(new ShimianNightStalkerRedirectDamageEffect(), new ManaCostsImpl<>("{B}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/ShimmerDragon.java b/Mage.Sets/src/mage/cards/s/ShimmerDragon.java index 9ae87af2f08..c081b3b5e3f 100644 --- a/Mage.Sets/src/mage/cards/s/ShimmerDragon.java +++ b/Mage.Sets/src/mage/cards/s/ShimmerDragon.java @@ -7,10 +7,9 @@ import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapTargetCost; import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; -import mage.abilities.hint.ValueHint; +import mage.abilities.hint.common.ArtifactYouControlHint; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HexproofAbility; import mage.cards.CardImpl; @@ -57,7 +56,7 @@ public final class ShimmerDragon extends CardImpl { new GainAbilitySourceEffect( HexproofAbility.getInstance(), Duration.WhileOnBattlefield ), condition, "as long as you control four or more artifacts, {this} has hexproof" - )).addHint(new ValueHint("Artifacts you control", new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT)))); + )).addHint(ArtifactYouControlHint.instance)); // Tap two untapped artifacts you control: Draw a card. this.addAbility(new SimpleActivatedAbility( diff --git a/Mage.Sets/src/mage/cards/s/ShinryuTranscendentRival.java b/Mage.Sets/src/mage/cards/s/ShinryuTranscendentRival.java index 8775979f768..712dfdb3e7d 100644 --- a/Mage.Sets/src/mage/cards/s/ShinryuTranscendentRival.java +++ b/Mage.Sets/src/mage/cards/s/ShinryuTranscendentRival.java @@ -16,6 +16,7 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetOpponent; +import mage.util.CardUtil; import java.util.Optional; import java.util.UUID; @@ -86,6 +87,7 @@ class ShinryuTranscendentRivalEffect extends ReplacementEffectImpl { } game.informPlayers(permanent.getName() + ": " + controller.getLogName() + " has chosen " + opponent.getLogName()); game.getState().setValue(permanent.getId() + "_" + permanent.getZoneChangeCounter(game) + "_opponent", opponent.getId()); + permanent.addInfo("chosen opponent", CardUtil.addToolTipMarkTags("Chosen Opponent " + opponent.getLogName()), game); return false; } diff --git a/Mage.Sets/src/mage/cards/s/ShipwreckLooter.java b/Mage.Sets/src/mage/cards/s/ShipwreckLooter.java index 6554a283d52..ea1566702b3 100644 --- a/Mage.Sets/src/mage/cards/s/ShipwreckLooter.java +++ b/Mage.Sets/src/mage/cards/s/ShipwreckLooter.java @@ -1,10 +1,8 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.abilities.hint.common.RaidHint; import mage.cards.CardImpl; @@ -30,12 +28,9 @@ public final class ShipwreckLooter extends CardImpl { this.toughness = new MageInt(1); // Raid - When Shipwreck Looter enters the battlefield,if you attacked this turn, you may draw a card. If you do, discard a card. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DrawDiscardControllerEffect(1, 1, true)), - RaidCondition.instance, "When {this} enters, if you attacked this turn, you may draw a card. If you do, discard a card."); - ability.setAbilityWord(AbilityWord.RAID); - ability.addHint(RaidHint.instance); - this.addAbility(ability, new PlayerAttackedWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new DrawDiscardControllerEffect(1, 1, true) + ).withInterveningIf(RaidCondition.instance).setAbilityWord(AbilityWord.RAID).addHint(RaidHint.instance), new PlayerAttackedWatcher()); } private ShipwreckLooter(final ShipwreckLooter card) { diff --git a/Mage.Sets/src/mage/cards/s/ShipwreckSinger.java b/Mage.Sets/src/mage/cards/s/ShipwreckSinger.java index f2c1eb321b2..8db43f3430b 100644 --- a/Mage.Sets/src/mage/cards/s/ShipwreckSinger.java +++ b/Mage.Sets/src/mage/cards/s/ShipwreckSinger.java @@ -16,8 +16,11 @@ import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -35,7 +38,7 @@ public final class ShipwreckSinger extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // {1}{U}: Target creature an opponent controls attacks this turn if able. Ability ability = new SimpleActivatedAbility(new AttacksIfAbleTargetEffect(Duration.EndOfTurn), new ManaCostsImpl<>("{1}{U}")); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); // {1}{B}, {T}: Attacking creatures get -1/-1 until end of turn. ability = new SimpleActivatedAbility(new BoostAllEffect(-1,-1, Duration.EndOfTurn, StaticFilters.FILTER_ATTACKING_CREATURES, false), new ManaCostsImpl<>("{1}{B}")); diff --git a/Mage.Sets/src/mage/cards/s/ShivanEmissary.java b/Mage.Sets/src/mage/cards/s/ShivanEmissary.java index 81b3324fd03..77c75594652 100644 --- a/Mage.Sets/src/mage/cards/s/ShivanEmissary.java +++ b/Mage.Sets/src/mage/cards/s/ShivanEmissary.java @@ -1,11 +1,9 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; @@ -13,17 +11,20 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; -/** - * - * @author LoneFox +import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + +/** + * @author LoneFox */ public final class ShivanEmissary extends CardImpl { public ShivanEmissary(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(1); @@ -31,11 +32,11 @@ public final class ShivanEmissary extends CardImpl { // Kicker {1}{B} this.addAbility(new KickerAbility("{1}{B}")); + // When Shivan Emissary enters the battlefield, if it was kicked, destroy target nonblack creature. It can't be regenerated. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(true)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.ONCE, - "When {this} enters, if it was kicked, destroy target nonblack creature. It can't be regenerated.")); + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(true)).withInterveningIf(KickedCondition.ONCE); + ability.addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.addAbility(ability); } private ShivanEmissary(final ShivanEmissary card) { diff --git a/Mage.Sets/src/mage/cards/s/ShorelineSalvager.java b/Mage.Sets/src/mage/cards/s/ShorelineSalvager.java index 38ad087b989..9270605cec6 100644 --- a/Mage.Sets/src/mage/cards/s/ShorelineSalvager.java +++ b/Mage.Sets/src/mage/cards/s/ShorelineSalvager.java @@ -1,42 +1,38 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.TargetController; -import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class ShorelineSalvager extends CardImpl { - private static final String rule = "Whenever Shoreline Salvager deals combat damage to a player, if you control an Island, you may draw a card."; - private static final FilterPermanent filter = new FilterPermanent("Island"); - - static { - filter.add(TargetController.YOU.getControllerPredicate()); - filter.add(SubType.ISLAND.getPredicate()); - } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.ISLAND, "you control an Island") + ); public ShorelineSalvager(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.subtype.add(SubType.SURRAKAR); this.power = new MageInt(3); this.toughness = new MageInt(3); // Whenever Shoreline Salvager deals combat damage to a player, if you control an Island, you may draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new DrawCardSourceControllerEffect(1), true), new PermanentsOnTheBattlefieldCondition(filter), rule)); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new DrawCardSourceControllerEffect(1), true + ).withInterveningIf(condition)); } private ShorelineSalvager(final ShorelineSalvager card) { diff --git a/Mage.Sets/src/mage/cards/s/Showstopper.java b/Mage.Sets/src/mage/cards/s/Showstopper.java index 8022d15ff01..23cad696a3b 100644 --- a/Mage.Sets/src/mage/cards/s/Showstopper.java +++ b/Mage.Sets/src/mage/cards/s/Showstopper.java @@ -12,8 +12,11 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -27,7 +30,7 @@ public final class Showstopper extends CardImpl { // Until end of turn, creatures you control gain "When this creature dies, it deals 2 damage to target creature an opponent controls." TriggeredAbility ability = new DiesSourceTriggeredAbility(new DamageTargetEffect(2, "it"), false); - Target target = new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE); + Target target = new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE); ability.addTarget(target); Effect effect = new GainAbilityControlledEffect(ability, Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES); effect.setText("Until end of turn, creatures you control gain \"When this creature dies, it deals 2 damage to target creature an opponent controls.\""); diff --git a/Mage.Sets/src/mage/cards/s/ShreddingWinds.java b/Mage.Sets/src/mage/cards/s/ShreddingWinds.java index dc1ac4f1751..90d61a2adb1 100644 --- a/Mage.Sets/src/mage/cards/s/ShreddingWinds.java +++ b/Mage.Sets/src/mage/cards/s/ShreddingWinds.java @@ -10,6 +10,7 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class ShreddingWinds extends CardImpl { // Shredding Winds deals 7 damage to target creature with flying. this.getSpellAbility().addEffect(new DamageTargetEffect(7)); - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); this.getSpellAbility().addTarget(target); } diff --git a/Mage.Sets/src/mage/cards/s/ShriekingAffliction.java b/Mage.Sets/src/mage/cards/s/ShriekingAffliction.java index 48f03a95d9a..13988100edf 100644 --- a/Mage.Sets/src/mage/cards/s/ShriekingAffliction.java +++ b/Mage.Sets/src/mage/cards/s/ShriekingAffliction.java @@ -1,9 +1,9 @@ package mage.cards.s; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInHandCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -19,18 +19,15 @@ import java.util.UUID; public final class ShriekingAffliction extends CardImpl { + private static final Condition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 2, TargetController.ACTIVE); + public ShriekingAffliction(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}"); // At the beginning of each opponent's upkeep, if that player has one or fewer cards in hand, they lose 3 life. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - Zone.BATTLEFIELD, TargetController.OPPONENT, new LoseLifeTargetEffect(3), - false - ), - new CardsInHandCondition(ComparisonType.FEWER_THAN, 2, TargetController.ACTIVE), - "At the beginning of each opponent's upkeep, if that player has one or fewer cards in hand, they lose 3 life." - )); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + Zone.BATTLEFIELD, TargetController.OPPONENT, new LoseLifeTargetEffect(3).setText("they lose 3 life"), false + ).withInterveningIf(condition)); } private ShriekingAffliction(final ShriekingAffliction card) { diff --git a/Mage.Sets/src/mage/cards/s/ShriekingGrotesque.java b/Mage.Sets/src/mage/cards/s/ShriekingGrotesque.java index 6838417befd..7a94f4e5de5 100644 --- a/Mage.Sets/src/mage/cards/s/ShriekingGrotesque.java +++ b/Mage.Sets/src/mage/cards/s/ShriekingGrotesque.java @@ -1,41 +1,37 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.ManaWasSpentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.ColoredManaSymbol; import mage.target.TargetPlayer; -/** - * - * @author LoneFox +import java.util.UUID; +/** + * @author LoneFox */ public final class ShriekingGrotesque extends CardImpl { public ShriekingGrotesque(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.GARGOYLE); this.power = new MageInt(2); this.toughness = new MageInt(1); // Flying this.addAbility(FlyingAbility.getInstance()); + // When Shrieking Grotesque enters the battlefield, if {B} was spent to cast it, target player discards a card. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(1), false); + Ability ability = new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(1)).withInterveningIf(ManaWasSpentCondition.BLACK); ability.addTarget(new TargetPlayer()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, ManaWasSpentCondition.BLACK, - "When {this} enters, if {B} was spent to cast it, target player discards a card.")); + this.addAbility(ability); } private ShriekingGrotesque(final ShriekingGrotesque card) { diff --git a/Mage.Sets/src/mage/cards/s/Shriekmaw.java b/Mage.Sets/src/mage/cards/s/Shriekmaw.java index f8d144380a1..ac0eea14dcb 100644 --- a/Mage.Sets/src/mage/cards/s/Shriekmaw.java +++ b/Mage.Sets/src/mage/cards/s/Shriekmaw.java @@ -17,6 +17,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -44,7 +45,7 @@ public final class Shriekmaw extends CardImpl { // When Shriekmaw enters the battlefield, destroy target nonartifact, nonblack creature. Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(),false); - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); ability.addTarget(target); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/ShrikeHarpy.java b/Mage.Sets/src/mage/cards/s/ShrikeHarpy.java index d42df20b9c5..56e650c90e5 100644 --- a/Mage.Sets/src/mage/cards/s/ShrikeHarpy.java +++ b/Mage.Sets/src/mage/cards/s/ShrikeHarpy.java @@ -1,12 +1,9 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.TributeNotPaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.SacrificeEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.TributeAbility; @@ -17,14 +14,15 @@ import mage.constants.SubType; import mage.filter.StaticFilters; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ShrikeHarpy extends CardImpl { public ShrikeHarpy(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); this.subtype.add(SubType.HARPY); this.power = new MageInt(2); @@ -37,10 +35,11 @@ public final class ShrikeHarpy extends CardImpl { this.addAbility(new TributeAbility(2)); // When Shrike Harpy enters the battlefield, if tribute wasn't paid, target opponent sacrifices a creature. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new SacrificeEffect(StaticFilters.FILTER_PERMANENT_A_CREATURE, 1, "target opponent"), false); + Ability ability = new EntersBattlefieldTriggeredAbility(new SacrificeEffect( + StaticFilters.FILTER_PERMANENT_A_CREATURE, 1, "target opponent" + )).withInterveningIf(TributeNotPaidCondition.instance); ability.addTarget(new TargetOpponent()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, TributeNotPaidCondition.instance, - "When {this} enters, if tribute wasn't paid, target opponent sacrifices a creature.")); + this.addAbility(ability); } private ShrikeHarpy(final ShrikeHarpy card) { diff --git a/Mage.Sets/src/mage/cards/s/ShuFarmer.java b/Mage.Sets/src/mage/cards/s/ShuFarmer.java index d3302121269..2c216554c1f 100644 --- a/Mage.Sets/src/mage/cards/s/ShuFarmer.java +++ b/Mage.Sets/src/mage/cards/s/ShuFarmer.java @@ -1,9 +1,6 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.MyTurnBeforeAttackersDeclaredCondition; import mage.abilities.costs.common.TapSourceCost; @@ -12,24 +9,24 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; + +import java.util.UUID; /** - * * @author fireshoes */ public final class ShuFarmer extends CardImpl { public ShuFarmer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.subtype.add(SubType.HUMAN); this.power = new MageInt(1); this.toughness = new MageInt(1); // {tap}: You gain 1 life. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new GainLifeEffect(1), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); - this.addAbility(ability); + this.addAbility(new ActivateIfConditionActivatedAbility( + new GainLifeEffect(1), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance + )); } private ShuFarmer(final ShuFarmer card) { diff --git a/Mage.Sets/src/mage/cards/s/SickAndTired.java b/Mage.Sets/src/mage/cards/s/SickAndTired.java index 84b789d74fd..d57f9a2e661 100644 --- a/Mage.Sets/src/mage/cards/s/SickAndTired.java +++ b/Mage.Sets/src/mage/cards/s/SickAndTired.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -9,15 +7,15 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Plopman */ public final class SickAndTired extends CardImpl { public SickAndTired(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); // Two target creatures each get -1/-1 until end of turn. this.getSpellAbility().addEffect(new BoostTargetEffect(-1, -1, Duration.EndOfTurn)); diff --git a/Mage.Sets/src/mage/cards/s/SickleDancer.java b/Mage.Sets/src/mage/cards/s/SickleDancer.java index ab3a5a2e01e..336cbb92189 100644 --- a/Mage.Sets/src/mage/cards/s/SickleDancer.java +++ b/Mage.Sets/src/mage/cards/s/SickleDancer.java @@ -1,32 +1,34 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterTeamPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class SickleDancer extends CardImpl { - private static final FilterTeamPermanent filter = new FilterTeamPermanent(SubType.WARRIOR, "Warrior creature"); + private static final FilterPermanent filter = new FilterTeamPermanent(SubType.WARRIOR, "your team controls another Warrior"); static { filter.add(AnotherPredicate.instance); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, false); + public SickleDancer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); @@ -36,11 +38,7 @@ public final class SickleDancer extends CardImpl { this.toughness = new MageInt(2); // Whenever Sickle Dancer attacks, if your team controls another Warrior, Sickle Dancer gets +1/+1 until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn), false), - new PermanentsOnTheBattlefieldCondition(filter), - "Whenever {this} attacks, if your team controls another Warrior, {this} gets +1/+1 until end of turn." - )); + this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn)).withInterveningIf(condition)); } private SickleDancer(final SickleDancer card) { diff --git a/Mage.Sets/src/mage/cards/s/SidarJabari.java b/Mage.Sets/src/mage/cards/s/SidarJabari.java index 9f8a8296c23..6793de24bf4 100644 --- a/Mage.Sets/src/mage/cards/s/SidarJabari.java +++ b/Mage.Sets/src/mage/cards/s/SidarJabari.java @@ -14,6 +14,7 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class SidarJabari extends CardImpl { // Whenever Sidar Jabari attacks, tap target creature defending player controls. Ability ability = new AttacksTriggeredAbility(new TapTargetEffect(), false); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SidarJabariOfZhalfir.java b/Mage.Sets/src/mage/cards/s/SidarJabariOfZhalfir.java index 4637e7c0c48..d9074173f7c 100644 --- a/Mage.Sets/src/mage/cards/s/SidarJabariOfZhalfir.java +++ b/Mage.Sets/src/mage/cards/s/SidarJabariOfZhalfir.java @@ -5,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.condition.common.SourceOnBattlefieldOrCommandZoneCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.keyword.FirstStrikeAbility; @@ -13,6 +12,8 @@ import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterCreaturePermanent; import mage.target.common.TargetCardInYourGraveyard; @@ -24,8 +25,8 @@ import java.util.UUID; */ public final class SidarJabariOfZhalfir extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.KNIGHT, "Knights"); - private static final FilterCreatureCard filter2 = new FilterCreatureCard("Knight creature card from your graveyard"); + private static final FilterPermanent filter = new FilterCreaturePermanent(SubType.KNIGHT, "Knights"); + private static final FilterCard filter2 = new FilterCreatureCard("Knight creature card from your graveyard"); static { filter2.add(SubType.KNIGHT.getPredicate()); @@ -40,15 +41,9 @@ public final class SidarJabariOfZhalfir extends CardImpl { // Eminence — Whenever you attack with one or more Knights, if Sidar Jabari of Zhalfir // is in the command zone or on the battlefield, draw a card, then discard a card. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksWithCreaturesTriggeredAbility( - Zone.ALL, new DrawDiscardControllerEffect(), 1, filter - ), SourceOnBattlefieldOrCommandZoneCondition.instance, - "Whenever you attack with one or more Knights, if {this} is in the command" + - " zone or on the battlefield, draw a card, then discard a card" - ); - ability.setAbilityWord(AbilityWord.EMINENCE); - this.addAbility(ability); + this.addAbility(new AttacksWithCreaturesTriggeredAbility( + Zone.ALL, new DrawDiscardControllerEffect(), 1, filter + ).withInterveningIf(SourceOnBattlefieldOrCommandZoneCondition.instance).setAbilityWord(AbilityWord.EMINENCE)); // Flying this.addAbility(FlyingAbility.getInstance()); @@ -58,7 +53,7 @@ public final class SidarJabariOfZhalfir extends CardImpl { // Whenever Sidar Jabari deals combat damage to a player, return target // Knight creature card from your graveyard to the battlefield. - ability = new DealsCombatDamageToAPlayerTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), false); + Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()); ability.addTarget(new TargetCardInYourGraveyard(filter2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SidequestPlayBlitzball.java b/Mage.Sets/src/mage/cards/s/SidequestPlayBlitzball.java index 394e1f3b6e4..8720da23746 100644 --- a/Mage.Sets/src/mage/cards/s/SidequestPlayBlitzball.java +++ b/Mage.Sets/src/mage/cards/s/SidequestPlayBlitzball.java @@ -48,7 +48,7 @@ public final class SidequestPlayBlitzball extends CardImpl { this.addAbility(new TransformAbility()); ability = new EndOfCombatTriggeredAbility( new TransformSourceEffect(), TargetController.YOU, false - ).withInterveningIf(SidequestPlayBlitzballCondition.instance); + ).withInterveningIf(SidequestPlayBlitzballCondition.instance).setTriggerPhrase("At the end of combat on your turn, "); ability.addEffect(new SidequestPlayBlitzballEffect()); this.addAbility(ability, new SidequestPlayBlitzballWatcher()); } diff --git a/Mage.Sets/src/mage/cards/s/SiegeGangLieutenant.java b/Mage.Sets/src/mage/cards/s/SiegeGangLieutenant.java index fafe03614a8..da67fce3a3d 100644 --- a/Mage.Sets/src/mage/cards/s/SiegeGangLieutenant.java +++ b/Mage.Sets/src/mage/cards/s/SiegeGangLieutenant.java @@ -67,6 +67,7 @@ class SiegeGangLieutenantEffect extends OneShotEffect { SiegeGangLieutenantEffect() { super(Outcome.Benefit); + staticText = "create two 1/1 red Goblin creature tokens. Those tokens gain haste until end of turn"; } private SiegeGangLieutenantEffect(final SiegeGangLieutenantEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/SiegeStriker.java b/Mage.Sets/src/mage/cards/s/SiegeStriker.java index b1c7b928e93..666755d2a1e 100644 --- a/Mage.Sets/src/mage/cards/s/SiegeStriker.java +++ b/Mage.Sets/src/mage/cards/s/SiegeStriker.java @@ -8,12 +8,14 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.DoubleStrikeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -34,10 +36,7 @@ public final class SiegeStriker extends CardImpl { this.addAbility(DoubleStrikeAbility.getInstance()); // Whenever Siege Striker attacks, you may tap any number of untapped creatures you control. Siege Striker gets +1/+1 until end of turn for each creature tapped this way. - this.addAbility(new AttacksTriggeredAbility( - new SiegeStrikerEffect(), true - )); - + this.addAbility(new AttacksTriggeredAbility(new SiegeStrikerEffect(), true)); } private SiegeStriker(final SiegeStriker card) { @@ -52,13 +51,6 @@ public final class SiegeStriker extends CardImpl { class SiegeStrikerEffect extends OneShotEffect { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("untapped creatures you control"); - - static { - filter.add(TargetController.YOU.getControllerPredicate()); - filter.add(TappedPredicate.UNTAPPED); - } - public SiegeStrikerEffect() { super(Outcome.GainLife); staticText = "you may tap any number of untapped creatures you control. " @@ -72,15 +64,13 @@ class SiegeStrikerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int tappedAmount = 0; - TargetCreaturePermanent target = new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, true); - if (target.canChoose(source.getControllerId(), source, game) - && target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), source, game)) { - for (UUID creatureId : target.getTargets()) { - Permanent creature = game.getPermanent(creatureId); - if (creature != null) { - creature.tap(source, game); - tappedAmount++; - } + TargetPermanent target = new TargetPermanent(0, Integer.MAX_VALUE, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES, true); + target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), source, game); + for (UUID creatureId : target.getTargets()) { + Permanent creature = game.getPermanent(creatureId); + if (creature != null) { + creature.tap(source, game); + tappedAmount++; } } if (tappedAmount > 0) { diff --git a/Mage.Sets/src/mage/cards/s/SigardaChampionOfLight.java b/Mage.Sets/src/mage/cards/s/SigardaChampionOfLight.java index cf5c3ded1d3..ddbd314d2b4 100644 --- a/Mage.Sets/src/mage/cards/s/SigardaChampionOfLight.java +++ b/Mage.Sets/src/mage/cards/s/SigardaChampionOfLight.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.CovenCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.hint.common.CovenHint; @@ -53,12 +52,9 @@ public final class SigardaChampionOfLight extends CardImpl { // Coven — Whenever Sigarda attacks, if you control three or more creatures with different powers, // look at the top five cards of your library. You may reveal a Human creature card from among them and put it into your hand. // Put the rest on the bottom of your library in a random order. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new LookLibraryAndPickControllerEffect(5, 1, filter2, PutCards.HAND, PutCards.BOTTOM_RANDOM)), CovenCondition.instance, "Whenever {this} attacks, " + - "if you control three or more creatures with different powers, look at the top five cards " + - "of your library. You may reveal a Human creature card from among them and put it into your hand. " + - "Put the rest on the bottom of your library in a random order." - ).addHint(CovenHint.instance).setAbilityWord(AbilityWord.COVEN)); + this.addAbility(new AttacksTriggeredAbility(new LookLibraryAndPickControllerEffect( + 5, 1, filter2, PutCards.HAND, PutCards.BOTTOM_RANDOM + )).withInterveningIf(CovenCondition.instance).addHint(CovenHint.instance).setAbilityWord(AbilityWord.COVEN)); } private SigardaChampionOfLight(final SigardaChampionOfLight card) { diff --git a/Mage.Sets/src/mage/cards/s/SigardianPriest.java b/Mage.Sets/src/mage/cards/s/SigardianPriest.java index 16ebf8d4d88..99fa919a016 100644 --- a/Mage.Sets/src/mage/cards/s/SigardianPriest.java +++ b/Mage.Sets/src/mage/cards/s/SigardianPriest.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -12,13 +10,13 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class SigardianPriest extends CardImpl { @@ -30,7 +28,7 @@ public final class SigardianPriest extends CardImpl { } public SigardianPriest(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); this.power = new MageInt(1); @@ -39,7 +37,7 @@ public final class SigardianPriest extends CardImpl { // {1}, {T}: Tap target non-Human creature. Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(1, 1, filter, false)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SigardianSavior.java b/Mage.Sets/src/mage/cards/s/SigardianSavior.java index 2537c68fe14..f7329c6df72 100644 --- a/Mage.Sets/src/mage/cards/s/SigardianSavior.java +++ b/Mage.Sets/src/mage/cards/s/SigardianSavior.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -42,12 +41,8 @@ public final class SigardianSavior extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Sigardian Savior enters the battlefield, if you cast it, return up to two target creature cards with mana value 2 or less from your graveyard to the battlefield. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()), - CastFromEverywhereSourceCondition.instance, "When {this} enters, " + - "if you cast it, return up to two target creature cards with mana value " + - "2 or less from your graveyard to the battlefield." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()) + .withInterveningIf(CastFromEverywhereSourceCondition.instance); ability.addTarget(new TargetCardInYourGraveyard(0, 2, filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SigilOfSleep.java b/Mage.Sets/src/mage/cards/s/SigilOfSleep.java index 7856263da01..eac14995734 100644 --- a/Mage.Sets/src/mage/cards/s/SigilOfSleep.java +++ b/Mage.Sets/src/mage/cards/s/SigilOfSleep.java @@ -39,7 +39,7 @@ public final class SigilOfSleep extends CardImpl { // Whenever enchanted creature deals damage to a player, return target creature that player controls to its owner's hand. Effect effect = new ReturnToHandTargetEffect(); ability = new DealsDamageToAPlayerAttachedTriggeredAbility(effect, "enchanted", false, true, false); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SigilTracer.java b/Mage.Sets/src/mage/cards/s/SigilTracer.java index 3d1ca28e199..39be752fe18 100644 --- a/Mage.Sets/src/mage/cards/s/SigilTracer.java +++ b/Mage.Sets/src/mage/cards/s/SigilTracer.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -12,27 +10,27 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.target.TargetSpell; -import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; /** * @author Loki */ public final class SigilTracer extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Wizards you control"); + private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent(SubType.WIZARD, "untapped Wizards you control"); static { filter.add(TappedPredicate.UNTAPPED); - filter.add(SubType.WIZARD.getPredicate()); } public SigilTracer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); this.subtype.add(SubType.MERFOLK); this.subtype.add(SubType.WIZARD); @@ -42,7 +40,7 @@ public final class SigilTracer extends CardImpl { // {1}{U}, Tap two untapped Wizards you control: Copy target instant or sorcery spell. You may choose new targets for the copy. Ability ability = new SimpleActivatedAbility(new CopyTargetStackObjectEffect(), new ManaCostsImpl<>("{1}{U}")); ability.addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY)); - ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(2, 2, filter, false))); + ability.addCost(new TapTargetCost(2, filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SignatureSlam.java b/Mage.Sets/src/mage/cards/s/SignatureSlam.java index 792a6f86a86..51fd55fb010 100644 --- a/Mage.Sets/src/mage/cards/s/SignatureSlam.java +++ b/Mage.Sets/src/mage/cards/s/SignatureSlam.java @@ -14,12 +14,15 @@ import mage.filter.predicate.permanent.ModifiedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.SecondTargetPointer; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author Susucr */ @@ -32,7 +35,7 @@ public final class SignatureSlam extends CardImpl { this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); this.getSpellAbility().addEffect(new SignatureSlamEffect().setTargetPointer(new SecondTargetPointer())); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); } private SignatureSlam(final SignatureSlam card) { diff --git a/Mage.Sets/src/mage/cards/s/SilumgarAssassin.java b/Mage.Sets/src/mage/cards/s/SilumgarAssassin.java index b5df7d8bec5..4e5536ac131 100644 --- a/Mage.Sets/src/mage/cards/s/SilumgarAssassin.java +++ b/Mage.Sets/src/mage/cards/s/SilumgarAssassin.java @@ -19,6 +19,7 @@ import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -49,7 +50,7 @@ public final class SilumgarAssassin extends CardImpl { // When Silumgar Assassin is turned face up, destroy target creature with power 3 or less an opponent controls. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new DestroyTargetEffect(), false); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SilversmoteGhoul.java b/Mage.Sets/src/mage/cards/s/SilversmoteGhoul.java index e9402b91165..2201dc939d1 100644 --- a/Mage.Sets/src/mage/cards/s/SilversmoteGhoul.java +++ b/Mage.Sets/src/mage/cards/s/SilversmoteGhoul.java @@ -2,17 +2,16 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.YouGainedLifeCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -26,7 +25,7 @@ import java.util.UUID; public final class SilversmoteGhoul extends CardImpl { private static final Condition condition = new YouGainedLifeCondition(ComparisonType.MORE_THAN, 2); - private static final Hint hint = new ConditionHint(condition, "You gained 3 or more life this turn"); + private static final Hint hint = new ConditionHint(condition); public SilversmoteGhoul(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); @@ -37,12 +36,10 @@ public final class SilversmoteGhoul extends CardImpl { this.toughness = new MageInt(1); // At the beginning of your end step, if you gained 3 or more life this turn, return Silversmote Ghoul from your graveyard to the battlefield tapped. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - Zone.GRAVEYARD, TargetController.YOU, new ReturnSourceFromGraveyardToBattlefieldEffect(true), - false, null - ), condition, "At the beginning of your end step, " + - "if you gained 3 or more life this turn, return {this} from your graveyard to the battlefield tapped." + this.addAbility(new BeginningOfEndStepTriggeredAbility( + Zone.GRAVEYARD, TargetController.YOU, + new ReturnSourceFromGraveyardToBattlefieldEffect(true), + false, condition ).addHint(hint), new PlayerGainedLifeWatcher()); // {1}{B}, Sacrifice Silversmote Ghoul: Draw a card. diff --git a/Mage.Sets/src/mage/cards/s/SimianSling.java b/Mage.Sets/src/mage/cards/s/SimianSling.java index a3bcb8ac777..a9e77100def 100644 --- a/Mage.Sets/src/mage/cards/s/SimianSling.java +++ b/Mage.Sets/src/mage/cards/s/SimianSling.java @@ -89,7 +89,7 @@ class SimianSlingTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever Simian Sling or equipped creature becomes blocked, it deals 1 damage to defending player."; + return "Whenever {this} or equipped creature becomes blocked, it deals 1 damage to defending player."; } } diff --git a/Mage.Sets/src/mage/cards/s/SimicBasilisk.java b/Mage.Sets/src/mage/cards/s/SimicBasilisk.java index 67e5997661d..1415f80933d 100644 --- a/Mage.Sets/src/mage/cards/s/SimicBasilisk.java +++ b/Mage.Sets/src/mage/cards/s/SimicBasilisk.java @@ -20,8 +20,11 @@ import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_A_CREATURE_P1P1; + /** * * @author JotaPeRL @@ -46,7 +49,7 @@ public final class SimicBasilisk extends CardImpl { new DealsDamageToACreatureTriggeredAbility(effect, true, false, true), Duration.EndOfTurn) .setText("Until end of turn, target creature with a +1/+1 counter on it gains \"Whenever this creature deals combat damage to a creature, destroy that creature at end of combat.\""), new ManaCostsImpl<>("{1}{G}")); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_A_CREATURE_P1P1)); + ability.addTarget(new TargetPermanent(FILTER_A_CREATURE_P1P1)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SimicManipulator.java b/Mage.Sets/src/mage/cards/s/SimicManipulator.java index 74b39998a51..1283e6f49c7 100644 --- a/Mage.Sets/src/mage/cards/s/SimicManipulator.java +++ b/Mage.Sets/src/mage/cards/s/SimicManipulator.java @@ -13,6 +13,7 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.PowerTargetAdjuster; @@ -47,7 +48,7 @@ public final class SimicManipulator extends CardImpl { // {T}, Remove one or more +1/+1 counters from Simic Manipulator: Gain control of target creature with power less than or equal to the number of +1/+1 counters removed this way. Ability ability = new SimpleActivatedAbility(new GainControlTargetEffect(Duration.Custom, true), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); ability.addCost(new RemoveVariableCountersSourceCost(CounterType.P1P1, 1, "Remove one or more +1/+1 counters from {this}")); ability.setTargetAdjuster(new PowerTargetAdjuster(GetXValue.instance, ComparisonType.OR_LESS)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/SimulacrumSynthesizer.java b/Mage.Sets/src/mage/cards/s/SimulacrumSynthesizer.java index f3df357df07..fbba2ad929b 100644 --- a/Mage.Sets/src/mage/cards/s/SimulacrumSynthesizer.java +++ b/Mage.Sets/src/mage/cards/s/SimulacrumSynthesizer.java @@ -1,6 +1,6 @@ package mage.cards.s; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.keyword.ScryEffect; @@ -9,7 +9,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.FilterPermanent; -import mage.filter.common.FilterArtifactPermanent; +import mage.filter.common.FilterControlledArtifactPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.permanent.token.KarnConstructToken; @@ -22,7 +22,7 @@ import java.util.UUID; public final class SimulacrumSynthesizer extends CardImpl { private static final FilterPermanent filter = - new FilterArtifactPermanent("another artifact with mana value 3 or greater"); + new FilterControlledArtifactPermanent("another artifact you control with mana value 3 or greater"); static { filter.add(AnotherPredicate.instance); @@ -36,9 +36,7 @@ public final class SimulacrumSynthesizer extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(2))); // Whenever another artifact with mana value 3 or more you control enters, create a 0/0 colorless Construct artifact creature token with "This creature gets +1/+1 for each artifact you control." - this.addAbility(new EntersBattlefieldControlledTriggeredAbility( - new CreateTokenEffect(new KarnConstructToken()), filter - )); + this.addAbility(new EntersBattlefieldAllTriggeredAbility(new CreateTokenEffect(new KarnConstructToken()), filter)); } private SimulacrumSynthesizer(final SimulacrumSynthesizer card) { diff --git a/Mage.Sets/src/mage/cards/s/SinewDancer.java b/Mage.Sets/src/mage/cards/s/SinewDancer.java index 558edffe5b3..6b6b3854987 100644 --- a/Mage.Sets/src/mage/cards/s/SinewDancer.java +++ b/Mage.Sets/src/mage/cards/s/SinewDancer.java @@ -1,23 +1,22 @@ package mage.cards.s; -import java.util.UUID; - import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.CorruptedCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.TapTargetEffect; -import mage.constants.AbilityWord; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.Zone; +import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * @author TheElk801 */ @@ -38,9 +37,8 @@ public final class SinewDancer extends CardImpl { this.addAbility(ability); // Corrupted -- {W}, {T}: Tap target creature. Activate only if an opponent has three or more poison counters. - ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new TapTargetEffect(), - new ManaCostsImpl<>("{W}"), CorruptedCondition.instance + ability = new ActivateIfConditionActivatedAbility( + new TapTargetEffect(), new ManaCostsImpl<>("{W}"), CorruptedCondition.instance ); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/s/SingularityRupture.java b/Mage.Sets/src/mage/cards/s/SingularityRupture.java new file mode 100644 index 00000000000..f978497f046 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SingularityRupture.java @@ -0,0 +1,36 @@ +package mage.cards.s; + +import mage.abilities.effects.common.DestroyAllEffect; +import mage.abilities.effects.common.MillHalfLibraryTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.TargetPlayer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SingularityRupture extends CardImpl { + + public SingularityRupture(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}{B}{B}"); + + // Destroy all creatures, then any number of target players each mill half their library, rounded down. + this.getSpellAbility().addEffect(new DestroyAllEffect(StaticFilters.FILTER_PERMANENT_CREATURES)); + this.getSpellAbility().addEffect(new MillHalfLibraryTargetEffect(false) + .setText(", then any number of target players each mill half their library, rounded down")); + this.getSpellAbility().addTarget(new TargetPlayer(0, Integer.MAX_VALUE, false)); + } + + private SingularityRupture(final SingularityRupture card) { + super(card); + } + + @Override + public SingularityRupture copy() { + return new SingularityRupture(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SirenOfTheFangedCoast.java b/Mage.Sets/src/mage/cards/s/SirenOfTheFangedCoast.java index fde54270672..32669c02d3b 100644 --- a/Mage.Sets/src/mage/cards/s/SirenOfTheFangedCoast.java +++ b/Mage.Sets/src/mage/cards/s/SirenOfTheFangedCoast.java @@ -1,30 +1,28 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.TributeNotPaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.TributeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SirenOfTheFangedCoast extends CardImpl { public SirenOfTheFangedCoast(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); this.subtype.add(SubType.SIREN); this.power = new MageInt(1); @@ -32,13 +30,16 @@ public final class SirenOfTheFangedCoast extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); + // Tribute 3 this.addAbility(new TributeAbility(3)); + // When Siren of the Fanged Coast enters the battlefield, if tribute wasn't paid, gain control of target creature. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new GainControlTargetEffect(Duration.EndOfGame, true), false); + Ability ability = new EntersBattlefieldTriggeredAbility( + new GainControlTargetEffect(Duration.EndOfGame, true) + ).withInterveningIf(TributeNotPaidCondition.instance); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, TributeNotPaidCondition.instance, - "When {this} enters, if tribute wasn't paid, gain control of target creature.")); + this.addAbility(ability); } private SirenOfTheFangedCoast(final SirenOfTheFangedCoast card) { diff --git a/Mage.Sets/src/mage/cards/s/SithAssassin.java b/Mage.Sets/src/mage/cards/s/SithAssassin.java index 1397decf45f..84f38e04fa8 100644 --- a/Mage.Sets/src/mage/cards/s/SithAssassin.java +++ b/Mage.Sets/src/mage/cards/s/SithAssassin.java @@ -1,22 +1,25 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.HateCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.watchers.common.LifeLossOtherFromCombatWatcher; +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** - * * @author Styxo */ public final class SithAssassin extends CardImpl { @@ -29,12 +32,9 @@ public final class SithAssassin extends CardImpl { this.toughness = new MageInt(2); // Hate — When Sith Assassin enters the battlefield, if opponent lost life from source other than combat damage this turn, you may destroy target nonblack creature. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), true), - HateCondition.instance, - "Hate — When {this} enters, if an opponent lost life from a source other than combat damage this turn, you may destroy target nonblack creature."); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); - this.addAbility(ability, new LifeLossOtherFromCombatWatcher()); + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), true).withInterveningIf(HateCondition.instance); + ability.addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.addAbility(ability.setAbilityWord(AbilityWord.HATE), new LifeLossOtherFromCombatWatcher()); } private SithAssassin(final SithAssassin card) { diff --git a/Mage.Sets/src/mage/cards/s/SithInquisitor.java b/Mage.Sets/src/mage/cards/s/SithInquisitor.java index e48e1af2e19..0c2c3782520 100644 --- a/Mage.Sets/src/mage/cards/s/SithInquisitor.java +++ b/Mage.Sets/src/mage/cards/s/SithInquisitor.java @@ -1,40 +1,36 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.HateCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; import mage.target.TargetPlayer; import mage.watchers.common.LifeLossOtherFromCombatWatcher; +import java.util.UUID; + /** - * * @author Styxo */ public final class SithInquisitor extends CardImpl { public SithInquisitor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SITH); this.power = new MageInt(5); this.toughness = new MageInt(1); // Hate — When Sith Assassin enters the battlefield, if opponent lost life from source other than combat damage this turn, target player discard a card at random. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(1, true)), - HateCondition.instance, - "Hate — When {this} enters, if an opponent lost life from a source other then combat damage this turn, target player discard a card at random."); + Ability ability = new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(1, true)).withInterveningIf(HateCondition.instance); ability.addTarget(new TargetPlayer()); - this.addAbility(ability, new LifeLossOtherFromCombatWatcher()); + this.addAbility(ability.setAbilityWord(AbilityWord.HATE), new LifeLossOtherFromCombatWatcher()); } private SithInquisitor(final SithInquisitor card) { diff --git a/Mage.Sets/src/mage/cards/s/SithMagic.java b/Mage.Sets/src/mage/cards/s/SithMagic.java index 989072d96ca..90cb27d82ad 100644 --- a/Mage.Sets/src/mage/cards/s/SithMagic.java +++ b/Mage.Sets/src/mage/cards/s/SithMagic.java @@ -1,13 +1,9 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.condition.common.HateCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.ReplacementEffectImpl; @@ -15,14 +11,11 @@ import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; @@ -34,8 +27,9 @@ import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; import mage.watchers.common.LifeLossOtherFromCombatWatcher; +import java.util.UUID; + /** - * * @author Styxo */ public final class SithMagic extends CardImpl { @@ -44,14 +38,10 @@ public final class SithMagic extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}{B}{R}"); // Hate — At the beggining of each combat, if opponent lost life from a source other than combat damage this turn, you may return target card from a graveyard to the battlefield under your control. It gains lifelink and haste. Exile it at the beginning of the next end step or if it would leave the battlefield. - TriggeredAbility triggeredAbility = new BeginningOfCombatTriggeredAbility(TargetController.ANY, new SithMagicEffect(), true); - triggeredAbility.addEffect(new SithMagicReplacementEffect()); - Ability ability = new ConditionalInterveningIfTriggeredAbility( - triggeredAbility, - HateCondition.instance, - "Hate — At the beggining of each combat, if opponent lost life from a source other than combat damage this turn, you may return target card from a graveyard to the battlefield under your control. It gains lifelink and haste. Exile it at the beginning of the next end step or if it would leave the battlefield."); + Ability ability = new BeginningOfCombatTriggeredAbility(TargetController.ANY, new SithMagicEffect(), true).withInterveningIf(HateCondition.instance); + ability.addEffect(new SithMagicReplacementEffect()); ability.addTarget(new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURE)); - this.addAbility(ability, new LifeLossOtherFromCombatWatcher()); + this.addAbility(ability.setAbilityWord(AbilityWord.HATE), new LifeLossOtherFromCombatWatcher()); } private SithMagic(final SithMagic card) { diff --git a/Mage.Sets/src/mage/cards/s/SithMarauder.java b/Mage.Sets/src/mage/cards/s/SithMarauder.java index 0f1f55859d7..1738795c9ff 100644 --- a/Mage.Sets/src/mage/cards/s/SithMarauder.java +++ b/Mage.Sets/src/mage/cards/s/SithMarauder.java @@ -1,22 +1,21 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.HateCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; import mage.target.common.TargetAnyTarget; import mage.watchers.common.LifeLossOtherFromCombatWatcher; +import java.util.UUID; + /** - * * @author Styxo */ public final class SithMarauder extends CardImpl { @@ -29,12 +28,9 @@ public final class SithMarauder extends CardImpl { this.toughness = new MageInt(4); // Hate — When Sith Marauder enters the battlefield, if an opponent lost life from a source other than combat damage this turn, Sith Marauder deals 3 damage to any target. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(3)), - HateCondition.instance, - "Hate — When {this} enters, if an opponent lost life from a source other than combat damage this turn, {this} deals 3 damage to any target"); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(3)).withInterveningIf(HateCondition.instance); ability.addTarget(new TargetAnyTarget()); - this.addAbility(ability, new LifeLossOtherFromCombatWatcher()); + this.addAbility(ability.setAbilityWord(AbilityWord.HATE), new LifeLossOtherFromCombatWatcher()); } private SithMarauder(final SithMarauder card) { diff --git a/Mage.Sets/src/mage/cards/s/SithMindseer.java b/Mage.Sets/src/mage/cards/s/SithMindseer.java index 34791594942..7d3b67c3cf3 100644 --- a/Mage.Sets/src/mage/cards/s/SithMindseer.java +++ b/Mage.Sets/src/mage/cards/s/SithMindseer.java @@ -1,32 +1,28 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.HateCondition; -import mage.abilities.condition.common.SourceRemainsInZoneCondition; -import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; import mage.watchers.common.LifeLossOtherFromCombatWatcher; +import java.util.UUID; + /** - * * @author Styxo */ public final class SithMindseer extends CardImpl { public SithMindseer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{U}{B}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{B}{R}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SITH); this.power = new MageInt(3); @@ -34,16 +30,12 @@ public final class SithMindseer extends CardImpl { // Hate — When Sith Mindseer enters the battlefield, if an opponent loses life from a source other than combat damage, // gain control of target creature for as long as Sith Mindseer remains on the battlefield. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ConditionalContinuousEffect( - new GainControlTargetEffect(Duration.Custom, true), - new SourceRemainsInZoneCondition(Zone.BATTLEFIELD), - "gain control of target creature for as long as {this} remains on the battlefield")), - HateCondition.instance, - "Hate — When {this} enters, if an opponent loses life from a source other than combat damage," - + " gain control of target creature for as long as {this} remains on the battlefield."); + Ability ability = new EntersBattlefieldTriggeredAbility( + new GainControlTargetEffect(Duration.UntilSourceLeavesBattlefield, true) + .setText("gain control of target creature for as long as {this} remains on the battlefield") + ).withInterveningIf(HateCondition.instance); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability, new LifeLossOtherFromCombatWatcher()); + this.addAbility(ability.setAbilityWord(AbilityWord.HATE), new LifeLossOtherFromCombatWatcher()); } private SithMindseer(final SithMindseer card) { diff --git a/Mage.Sets/src/mage/cards/s/SithSorcerer.java b/Mage.Sets/src/mage/cards/s/SithSorcerer.java index 97fad762a32..1b21d145d04 100644 --- a/Mage.Sets/src/mage/cards/s/SithSorcerer.java +++ b/Mage.Sets/src/mage/cards/s/SithSorcerer.java @@ -1,28 +1,27 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.HateCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.keyword.ScryEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; import mage.watchers.common.LifeLossOtherFromCombatWatcher; +import java.util.UUID; + /** - * * @author Styxo */ public final class SithSorcerer extends CardImpl { public SithSorcerer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SITH); this.power = new MageInt(2); @@ -32,12 +31,8 @@ public final class SithSorcerer extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(2))); // Hate — When Sith Sorcerer enters the battlefield, if an opponent lost life from a source other than combat damage this turn, draw a card. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(1)), - HateCondition.instance, - "Hate — When {this} dies, if an opponent lost life from a source other than combat damage this turn, draw a card."); - this.addAbility(ability, new LifeLossOtherFromCombatWatcher()); - + this.addAbility(new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .withInterveningIf(HateCondition.instance).setAbilityWord(AbilityWord.HATE), new LifeLossOtherFromCombatWatcher()); } private SithSorcerer(final SithSorcerer card) { diff --git a/Mage.Sets/src/mage/cards/s/SithThoughtseeker.java b/Mage.Sets/src/mage/cards/s/SithThoughtseeker.java index 433960db82f..b1dbe0fa425 100644 --- a/Mage.Sets/src/mage/cards/s/SithThoughtseeker.java +++ b/Mage.Sets/src/mage/cards/s/SithThoughtseeker.java @@ -1,41 +1,34 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.condition.common.HateCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; + +import java.util.UUID; /** - * * @author Styxo */ public final class SithThoughtseeker extends CardImpl { public SithThoughtseeker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SITH); this.power = new MageInt(2); this.toughness = new MageInt(1); // Hate — {2}{U}: Draw a card. Activate this ability only if an opponent lost life from source other than combat damage this turn. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, - new DrawCardSourceControllerEffect(1), - new ManaCostsImpl<>("{2}{U}"), - HateCondition.instance); - ability.setAbilityWord(AbilityWord.HATE); - this.addAbility(ability); + this.addAbility(new ActivateIfConditionActivatedAbility( + new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{2}{U}"), HateCondition.instance + ).setAbilityWord(AbilityWord.HATE)); } private SithThoughtseeker(final SithThoughtseeker card) { diff --git a/Mage.Sets/src/mage/cards/s/SkarrganFirebird.java b/Mage.Sets/src/mage/cards/s/SkarrganFirebird.java index dadce98393e..3397644e2bf 100644 --- a/Mage.Sets/src/mage/cards/s/SkarrganFirebird.java +++ b/Mage.Sets/src/mage/cards/s/SkarrganFirebird.java @@ -1,12 +1,10 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; import mage.abilities.keyword.BloodthirstAbility; import mage.abilities.keyword.FlyingAbility; @@ -18,14 +16,15 @@ import mage.constants.Zone; import mage.game.Game; import mage.watchers.common.BloodthirstWatcher; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SkarrganFirebird extends CardImpl { public SkarrganFirebird(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}{R}"); this.subtype.add(SubType.PHOENIX); this.power = new MageInt(3); @@ -33,15 +32,15 @@ public final class SkarrganFirebird extends CardImpl { // Bloodthirst 3 this.addAbility(new BloodthirstAbility(3)); + // Flying this.addAbility(FlyingAbility.getInstance()); + // {R}{R}{R}: Return Skarrgan Firebird from your graveyard to your hand. Activate this ability only if an opponent was dealt damage this turn. - this.addAbility(new ConditionalActivatedAbility( - Zone.GRAVEYARD, - new ReturnSourceFromGraveyardToHandEffect(), - new ManaCostsImpl<>("{R}{R}{R}"), - new OpponentWasDealtDamageCondition(), - null)); + this.addAbility(new ActivateIfConditionActivatedAbility( + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), + new ManaCostsImpl<>("{R}{R}{R}"), OpponentWasDealtDamageCondition.instance + )); } private SkarrganFirebird(final SkarrganFirebird card) { @@ -54,10 +53,8 @@ public final class SkarrganFirebird extends CardImpl { } } -class OpponentWasDealtDamageCondition implements Condition { - - public OpponentWasDealtDamageCondition() { - } +enum OpponentWasDealtDamageCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { @@ -67,6 +64,6 @@ class OpponentWasDealtDamageCondition implements Condition { @Override public String toString() { - return "if an opponent was dealt damage this turn"; + return "an opponent was dealt damage this turn"; } } diff --git a/Mage.Sets/src/mage/cards/s/SkarrganHellkite.java b/Mage.Sets/src/mage/cards/s/SkarrganHellkite.java index 0e312aca483..d25ce1933c4 100644 --- a/Mage.Sets/src/mage/cards/s/SkarrganHellkite.java +++ b/Mage.Sets/src/mage/cards/s/SkarrganHellkite.java @@ -2,9 +2,10 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamageMultiEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.RiotAbility; @@ -12,7 +13,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.target.common.TargetAnyTargetAmount; @@ -23,6 +23,8 @@ import java.util.UUID; */ public final class SkarrganHellkite extends CardImpl { + private static final Condition condition = new SourceHasCounterCondition(CounterType.P1P1); + public SkarrganHellkite(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); @@ -37,12 +39,9 @@ public final class SkarrganHellkite extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // {3}{R}: Skarrgan Hellkite deals 2 damage divided as you choose among one or two targets. Activate this ability only if Skarrgan Hellkite has a +1/+1 counter on it. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new DamageMultiEffect(), - new ManaCostsImpl<>("{3}{R}"), new SourceHasCounterCondition(CounterType.P1P1), - "{3}{R}: {this} deals 2 damage divided as you choose among one or two targets. " + - "Activate only if {this} has a +1/+1 counter on it." - ); + Ability ability = new ActivateIfConditionActivatedAbility( + new DamageMultiEffect(), new ManaCostsImpl<>("{3}{R}"), condition + ).withConditionText("activate only if {this} has a +1/+1 counter on it"); ability.addTarget(new TargetAnyTargetAmount(2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SkinInvasion.java b/Mage.Sets/src/mage/cards/s/SkinInvasion.java index 418c9d540bc..38647f13455 100644 --- a/Mage.Sets/src/mage/cards/s/SkinInvasion.java +++ b/Mage.Sets/src/mage/cards/s/SkinInvasion.java @@ -66,7 +66,7 @@ class SkinInvasionEffect extends OneShotEffect { SkinInvasionEffect() { super(Outcome.PutCardInPlay); - this.staticText = "return {this} to the battlefield transformed under your control"; + this.staticText = "return this card to the battlefield transformed under your control"; } private SkinInvasionEffect(final SkinInvasionEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/Skinthinner.java b/Mage.Sets/src/mage/cards/s/Skinthinner.java index dda8978f95e..43eebdb9d6d 100644 --- a/Mage.Sets/src/mage/cards/s/Skinthinner.java +++ b/Mage.Sets/src/mage/cards/s/Skinthinner.java @@ -12,8 +12,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author LoneFox @@ -30,7 +33,7 @@ public final class Skinthinner extends CardImpl { this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{3}{B}{B}"))); // When Skinthinner is turned face up, destroy target nonblack creature. It can't be regenerated. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new DestroyTargetEffect(true)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + ability.addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SkirkAlarmist.java b/Mage.Sets/src/mage/cards/s/SkirkAlarmist.java index 22acf7450c3..e389c7ec213 100644 --- a/Mage.Sets/src/mage/cards/s/SkirkAlarmist.java +++ b/Mage.Sets/src/mage/cards/s/SkirkAlarmist.java @@ -22,6 +22,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.card.FaceDownPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -52,7 +53,7 @@ public final class SkirkAlarmist extends CardImpl { // {tap}: Turn target face-down creature you control face up. At the beginning of the next end step, sacrifice it. Ability ability = new SimpleActivatedAbility(new TurnFaceUpTargetEffect(), new TapSourceCost()); ability.addEffect(new SkirkAlarmistEffect()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SkirsdagHighPriest.java b/Mage.Sets/src/mage/cards/s/SkirsdagHighPriest.java index b8df837ea25..7364d50e460 100644 --- a/Mage.Sets/src/mage/cards/s/SkirsdagHighPriest.java +++ b/Mage.Sets/src/mage/cards/s/SkirsdagHighPriest.java @@ -1,13 +1,11 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.MorbidCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapTargetCost; -import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.common.MorbidHint; import mage.cards.CardImpl; @@ -15,26 +13,18 @@ import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; +import mage.filter.StaticFilters; import mage.game.permanent.token.DemonToken; -import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author North */ public final class SkirsdagHighPriest extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); - - static { - filter.add(TappedPredicate.UNTAPPED); - } - public SkirsdagHighPriest(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); @@ -42,11 +32,11 @@ public final class SkirsdagHighPriest extends CardImpl { this.toughness = new MageInt(2); // Morbid — {tap}, Tap two untapped creatures you control: Create a 5/5 black Demon creature token with flying. Activate this ability only if a creature died this turn. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new DemonToken()), - new TapSourceCost(), MorbidCondition.instance); - ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(2, 2, filter, false))); - ability.setAbilityWord(AbilityWord.MORBID); - this.addAbility(ability.addHint(MorbidHint.instance)); + Ability ability = new ActivateIfConditionActivatedAbility( + new CreateTokenEffect(new DemonToken()), new TapSourceCost(), MorbidCondition.instance + ); + ability.addCost(new TapTargetCost(2, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES)); + this.addAbility(ability.setAbilityWord(AbilityWord.MORBID).addHint(MorbidHint.instance)); } private SkirsdagHighPriest(final SkirsdagHighPriest card) { diff --git a/Mage.Sets/src/mage/cards/s/SkitterbeamBattalion.java b/Mage.Sets/src/mage/cards/s/SkitterbeamBattalion.java index 97bcaebafba..e63232362d0 100644 --- a/Mage.Sets/src/mage/cards/s/SkitterbeamBattalion.java +++ b/Mage.Sets/src/mage/cards/s/SkitterbeamBattalion.java @@ -3,7 +3,6 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.CreateTokenCopySourceEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.PrototypeAbility; @@ -37,11 +36,8 @@ public final class SkitterbeamBattalion extends CardImpl { this.addAbility(HasteAbility.getInstance()); // When Skitterbeam Battalion enters the battlefield, if you cast it, create two tokens that are copies of it. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CreateTokenCopySourceEffect(2)), - CastFromEverywhereSourceCondition.instance, "When {this} enters, " + - "if you cast it, create two tokens that are copies of it." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenCopySourceEffect(2) + .setText("create two tokens that are copies of it")).withInterveningIf(CastFromEverywhereSourceCondition.instance)); } private SkitterbeamBattalion(final SkitterbeamBattalion card) { diff --git a/Mage.Sets/src/mage/cards/s/Skitterskin.java b/Mage.Sets/src/mage/cards/s/Skitterskin.java index 70676dd1b60..80e1d9f5ab8 100644 --- a/Mage.Sets/src/mage/cards/s/Skitterskin.java +++ b/Mage.Sets/src/mage/cards/s/Skitterskin.java @@ -1,11 +1,9 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.CantBlockAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.RegenerateSourceEffect; @@ -14,26 +12,29 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.mageobject.ColorlessPredicate; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.ColorlessPredicate; + +import java.util.UUID; /** - * * @author fireshoes */ public final class Skitterskin extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("you control another colorless creature"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("you control another colorless creature"); static { filter.add(AnotherPredicate.instance); filter.add(ColorlessPredicate.instance); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + public Skitterskin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.subtype.add(SubType.ELDRAZI); this.subtype.add(SubType.DRONE); this.power = new MageInt(4); @@ -46,11 +47,9 @@ public final class Skitterskin extends CardImpl { this.addAbility(new CantBlockAbility()); // {1}{B}: Regenerate Skitterskin. Activate this ability only if you control another colorless creature. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new RegenerateSourceEffect(), - new ManaCostsImpl<>("{1}{B}"), - new PermanentsOnTheBattlefieldCondition(filter)); - this.addAbility(ability); + this.addAbility(new ActivateIfConditionActivatedAbility( + new RegenerateSourceEffect(), new ManaCostsImpl<>("{1}{B}"), condition + )); } private Skitterskin(final Skitterskin card) { diff --git a/Mage.Sets/src/mage/cards/s/Skizzik.java b/Mage.Sets/src/mage/cards/s/Skizzik.java index ba22598c761..608f964e689 100644 --- a/Mage.Sets/src/mage/cards/s/Skizzik.java +++ b/Mage.Sets/src/mage/cards/s/Skizzik.java @@ -1,14 +1,14 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.KickerAbility; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -18,11 +18,12 @@ import mage.constants.TargetController; import java.util.UUID; /** - * * @author LevelX2 */ public final class Skizzik extends CardImpl { + private static final Condition condition = new InvertCondition(KickedCondition.ONCE, "{this} wasn't kicked"); + public Skizzik(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.subtype.add(SubType.ELEMENTAL); @@ -40,10 +41,8 @@ public final class Skizzik extends CardImpl { this.addAbility(HasteAbility.getInstance()); // At the beginning of the end step, if Skizzik wasn't kicked, sacrifice it. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility(TargetController.NEXT, new SacrificeSourceEffect(), false), - new InvertCondition(KickedCondition.ONCE), - "At the beginning of the end step, if {this} wasn't kicked, sacrifice it" + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.NEXT, new SacrificeSourceEffect().setText("sacrifice it"), false, condition )); } diff --git a/Mage.Sets/src/mage/cards/s/Skulduggery.java b/Mage.Sets/src/mage/cards/s/Skulduggery.java index 6241a7da838..a18dc256c48 100644 --- a/Mage.Sets/src/mage/cards/s/Skulduggery.java +++ b/Mage.Sets/src/mage/cards/s/Skulduggery.java @@ -14,10 +14,13 @@ import mage.constants.Outcome; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author TheElk801 @@ -30,7 +33,7 @@ public final class Skulduggery extends CardImpl { // Until end of turn, target creature you control gets +1/+1 and target creature an opponent controls gets -1/-1. this.getSpellAbility().addEffect(new SkulduggeryEffect()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); } private Skulduggery(final Skulduggery card) { diff --git a/Mage.Sets/src/mage/cards/s/SkyHussar.java b/Mage.Sets/src/mage/cards/s/SkyHussar.java index 296144143f6..8a4f3b235dd 100644 --- a/Mage.Sets/src/mage/cards/s/SkyHussar.java +++ b/Mage.Sets/src/mage/cards/s/SkyHussar.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -14,26 +12,32 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author emerald000 */ public final class SkyHussar extends CardImpl { - - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped white and/or blue creatures you control"); + + private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("untapped white and/or blue creatures you control"); + static { - filter.add(Predicates.or(new ColorPredicate(ObjectColor.WHITE), new ColorPredicate(ObjectColor.BLUE))); + filter.add(Predicates.or( + new ColorPredicate(ObjectColor.WHITE), + new ColorPredicate(ObjectColor.BLUE) + )); filter.add(TappedPredicate.UNTAPPED); } public SkyHussar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{U}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.KNIGHT); @@ -42,12 +46,17 @@ public final class SkyHussar extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // When Sky Hussar enters the battlefield, untap all creatures you control. - this.addAbility(new EntersBattlefieldTriggeredAbility(new UntapAllControllerEffect(new FilterControlledCreaturePermanent(), "untap all creatures you control"), false)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new UntapAllControllerEffect( + StaticFilters.FILTER_CONTROLLED_CREATURES, "untap all creatures you control" + ), false)); // Forecast - Tap two untapped white and/or blue creatures you control, Reveal Sky Hussar from your hand: Draw a card. - this.addAbility(new ForecastAbility(new DrawCardSourceControllerEffect(1), new TapTargetCost(new TargetControlledCreaturePermanent(2, 2, filter, true)))); + this.addAbility(new ForecastAbility( + new DrawCardSourceControllerEffect(1), + new TapTargetCost(2, filter) + )); } private SkyHussar(final SkyHussar card) { diff --git a/Mage.Sets/src/mage/cards/s/SkyWeaver.java b/Mage.Sets/src/mage/cards/s/SkyWeaver.java index d94cae2c327..1d745ca6288 100644 --- a/Mage.Sets/src/mage/cards/s/SkyWeaver.java +++ b/Mage.Sets/src/mage/cards/s/SkyWeaver.java @@ -18,6 +18,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -42,7 +43,7 @@ public final class SkyWeaver extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(1); Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), new GenericManaCost(2)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SkyclaveRelic.java b/Mage.Sets/src/mage/cards/s/SkyclaveRelic.java index cd303bd17a3..bfa00aa64cd 100644 --- a/Mage.Sets/src/mage/cards/s/SkyclaveRelic.java +++ b/Mage.Sets/src/mage/cards/s/SkyclaveRelic.java @@ -2,7 +2,6 @@ package mage.cards.s; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.CreateTokenCopySourceEffect; import mage.abilities.keyword.IndestructibleAbility; import mage.abilities.keyword.KickerAbility; @@ -28,11 +27,8 @@ public final class SkyclaveRelic extends CardImpl { this.addAbility(IndestructibleAbility.getInstance()); // When Skyclave Relic enters the battlefield, if it was kicked, create two tapped tokens that are copies of Skyclave Relic. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CreateTokenCopySourceEffect(2, true)), - KickedCondition.ONCE, "When {this} enters, if it was kicked, " + - "create two tapped tokens that are copies of {this}." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenCopySourceEffect(2, true)) + .withInterveningIf(KickedCondition.ONCE)); // {T}: Add one mana of any color. this.addAbility(new AnyColorManaAbility()); diff --git a/Mage.Sets/src/mage/cards/s/SkyclaveShade.java b/Mage.Sets/src/mage/cards/s/SkyclaveShade.java index 5b830fcf62a..3f984c77990 100644 --- a/Mage.Sets/src/mage/cards/s/SkyclaveShade.java +++ b/Mage.Sets/src/mage/cards/s/SkyclaveShade.java @@ -7,7 +7,6 @@ import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.LandfallAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.KickerAbility; @@ -45,12 +44,8 @@ public final class SkyclaveShade extends CardImpl { )); // Landfall — Whenever a land you control enters, if Skyclave Shade is in your graveyard and it's your turn, you may cast it from your graveyard this turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new LandfallAbility(Zone.GRAVEYARD, new SkyclaveShadeEffect(), false), - SkyclaveShadeCondition.instance, "Landfall — Whenever a land " + - "you control enters, if {this} is in your graveyard and it's your turn, " + - "you may cast it from your graveyard this turn." - )); + this.addAbility(new LandfallAbility(Zone.GRAVEYARD, new SkyclaveShadeEffect(), false) + .withInterveningIf(SkyclaveShadeCondition.instance)); } private SkyclaveShade(final SkyclaveShade card) { @@ -71,12 +66,18 @@ enum SkyclaveShadeCondition implements Condition { return game.getActivePlayerId().equals(source.getControllerId()) && game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD; } + + @Override + public String toString() { + return "this card is in your graveyard and it's your turn"; + } } class SkyclaveShadeEffect extends AsThoughEffectImpl { SkyclaveShadeEffect() { super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); + staticText = "you may cast it from your graveyard this turn"; } private SkyclaveShadeEffect(final SkyclaveShadeEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/SkylineCascade.java b/Mage.Sets/src/mage/cards/s/SkylineCascade.java index 65f3c2c43bb..df393a141c4 100644 --- a/Mage.Sets/src/mage/cards/s/SkylineCascade.java +++ b/Mage.Sets/src/mage/cards/s/SkylineCascade.java @@ -11,8 +11,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author fireshoes @@ -27,7 +30,7 @@ public final class SkylineCascade extends CardImpl { // When Skyline Cascade enters the battlefield, target creature an opponent controls doesn't untap during its controller's next untap step. Ability ability = new EntersBattlefieldTriggeredAbility(new DontUntapInControllersNextUntapStepTargetEffect(), false); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); // {T}: Add {U}. diff --git a/Mage.Sets/src/mage/cards/s/SkylineDespot.java b/Mage.Sets/src/mage/cards/s/SkylineDespot.java index d8d73074e96..99f89a1fa8c 100644 --- a/Mage.Sets/src/mage/cards/s/SkylineDespot.java +++ b/Mage.Sets/src/mage/cards/s/SkylineDespot.java @@ -1,14 +1,13 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.MonarchIsSourceControllerCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.BecomesMonarchSourceEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.common.MonarchHint; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -31,17 +30,13 @@ public final class SkylineDespot extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); + // When Skyline Despot enters the battlefield, you become the monarch. this.addAbility(new EntersBattlefieldTriggeredAbility(new BecomesMonarchSourceEffect()).addHint(MonarchHint.instance)); // At the beginning of your upkeep, if you're the monarch, put a 5/5 red Dragon creature token with flying onto the battlefield. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - new CreateTokenEffect(new DragonToken2()), false - ), MonarchIsSourceControllerCondition.instance, "At the beginning of your upkeep, " + - "if you're the monarch, create a 5/5 red Dragon creature token with flying." - )); - + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new DragonToken2())) + .withInterveningIf(MonarchIsSourceControllerCondition.instance)); } private SkylineDespot(final SkylineDespot card) { diff --git a/Mage.Sets/src/mage/cards/s/SkymarkRoc.java b/Mage.Sets/src/mage/cards/s/SkymarkRoc.java index b9bc17a294a..fb5be177dff 100644 --- a/Mage.Sets/src/mage/cards/s/SkymarkRoc.java +++ b/Mage.Sets/src/mage/cards/s/SkymarkRoc.java @@ -2,32 +2,38 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; -import mage.constants.Zone; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ToughnessPredicate; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class SkymarkRoc extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("creature defending player controls with toughness 2 or less"); + + static { + filter.add(new ToughnessPredicate(ComparisonType.OR_LESS, 2)); + } + public SkymarkRoc(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{U}"); this.subtype.add(SubType.BIRD); this.power = new MageInt(3); @@ -37,7 +43,10 @@ public final class SkymarkRoc extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever Skymark Roc attacks, you may return target creature defending player controls with toughness 2 or less to its owner's hand. - this.addAbility(new SkymarkRocAbility()); + Ability ability = new AttacksTriggeredAbility(new ReturnToHandTargetEffect(), true, null, SetTargetPointer.PLAYER); + ability.addTarget(new TargetPermanent(filter)); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); + this.addAbility(ability); } private SkymarkRoc(final SkymarkRoc card) { @@ -49,45 +58,3 @@ public final class SkymarkRoc extends CardImpl { return new SkymarkRoc(this); } } - -class SkymarkRocAbility extends TriggeredAbilityImpl { - - public SkymarkRocAbility() { - super(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), true); - } - - private SkymarkRocAbility(final SkymarkRocAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ATTACKER_DECLARED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getSourceId().equals(this.getSourceId())) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls with toughness 2 or less"); - UUID defenderId = game.getCombat().getDefendingPlayerId(sourceId, game); - filter.add(new ControllerIdPredicate(defenderId)); - filter.add(new ToughnessPredicate(ComparisonType.FEWER_THAN, 3)); - - this.getTargets().clear(); - TargetCreaturePermanent target = new TargetCreaturePermanent(filter); - this.addTarget(target); - return true; - } - return false; - } - - @Override - public String getRule() { - return "Whenever {this} attacks, you may return target creature defending player controls with toughness 2 or less to its owner's hand."; - } - - @Override - public SkymarkRocAbility copy() { - return new SkymarkRocAbility(this); - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SkyshroudArcher.java b/Mage.Sets/src/mage/cards/s/SkyshroudArcher.java index def019a5a0b..3a953a4d172 100644 --- a/Mage.Sets/src/mage/cards/s/SkyshroudArcher.java +++ b/Mage.Sets/src/mage/cards/s/SkyshroudArcher.java @@ -16,6 +16,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class SkyshroudArcher extends CardImpl { // {tap}: Target creature with flying gets -1/-1 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(-1, -1, Duration.EndOfTurn), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SkysovereignConsulFlagship.java b/Mage.Sets/src/mage/cards/s/SkysovereignConsulFlagship.java index a3cdb87498c..7b7ca74daf6 100644 --- a/Mage.Sets/src/mage/cards/s/SkysovereignConsulFlagship.java +++ b/Mage.Sets/src/mage/cards/s/SkysovereignConsulFlagship.java @@ -14,7 +14,7 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.TargetController; import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; -import mage.target.common.TargetCreatureOrPlaneswalker; +import mage.target.TargetPermanent; import java.util.UUID; @@ -41,7 +41,7 @@ public final class SkysovereignConsulFlagship extends CardImpl { // Whenever Skysovereign, Consul Flagship enters the battlefield or attacks, it deals 3 damage to target creature or planeswalker an opponent controls. Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new DamageTargetEffect(3, "it")); - ability.addTarget(new TargetCreatureOrPlaneswalker(1, 1, filter, false)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Crew 3 diff --git a/Mage.Sets/src/mage/cards/s/SkywayRobber.java b/Mage.Sets/src/mage/cards/s/SkywayRobber.java index 0c1833339c0..25e90be8490 100644 --- a/Mage.Sets/src/mage/cards/s/SkywayRobber.java +++ b/Mage.Sets/src/mage/cards/s/SkywayRobber.java @@ -19,7 +19,6 @@ import mage.filter.predicate.Predicates; import mage.game.ExileZone; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; import mage.target.common.TargetCardInExile; import mage.util.CardUtil; @@ -73,7 +72,7 @@ class SkywayRobberCastForFreeEffect extends OneShotEffect { public SkywayRobberCastForFreeEffect() { super(Outcome.PlayForFree); - this.staticText = "you may cast an artifact, instant, or sorcery spell from among cards exiled with Skyway Robber without paying its mana cost"; + this.staticText = "you may cast an artifact, instant, or sorcery spell from among cards exiled with {this} without paying its mana cost"; } private SkywayRobberCastForFreeEffect(final SkywayRobberCastForFreeEffect effect) { @@ -124,4 +123,4 @@ class SkywayRobberCastForFreeEffect extends OneShotEffect { public SkywayRobberCastForFreeEffect copy() { return new SkywayRobberCastForFreeEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/SkywhalersShot.java b/Mage.Sets/src/mage/cards/s/SkywhalersShot.java index 2feaca01741..96a767a2446 100644 --- a/Mage.Sets/src/mage/cards/s/SkywhalersShot.java +++ b/Mage.Sets/src/mage/cards/s/SkywhalersShot.java @@ -10,6 +10,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class SkywhalersShot extends CardImpl { // Destroy target creature with power 3 or greater. Scry 1. getSpellAbility().addEffect(new DestroyTargetEffect()); - getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + getSpellAbility().addTarget(new TargetPermanent(filter)); getSpellAbility().addEffect(new ScryEffect(1)); } diff --git a/Mage.Sets/src/mage/cards/s/Slaughter.java b/Mage.Sets/src/mage/cards/s/Slaughter.java index e7bfe3deaee..28d269eb55a 100644 --- a/Mage.Sets/src/mage/cards/s/Slaughter.java +++ b/Mage.Sets/src/mage/cards/s/Slaughter.java @@ -8,8 +8,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author Temba21 @@ -24,7 +27,7 @@ public final class Slaughter extends CardImpl { // Destroy target nonblack creature. It can't be regenerated. this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); } private Slaughter(final Slaughter card) { diff --git a/Mage.Sets/src/mage/cards/s/SlaughterPact.java b/Mage.Sets/src/mage/cards/s/SlaughterPact.java index 80ae58690b5..57761c98a1b 100644 --- a/Mage.Sets/src/mage/cards/s/SlaughterPact.java +++ b/Mage.Sets/src/mage/cards/s/SlaughterPact.java @@ -9,8 +9,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author Plopman @@ -23,7 +26,7 @@ public final class SlaughterPact extends CardImpl { this.color.setBlack(true); // Destroy target nonblack creature. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); // At the beginning of your next upkeep, pay {2}{B}. If you don't, you lose the game. this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new PactDelayedTriggeredAbility(new ManaCostsImpl<>("{2}{B}")),false)); diff --git a/Mage.Sets/src/mage/cards/s/SlaughterhouseBouncer.java b/Mage.Sets/src/mage/cards/s/SlaughterhouseBouncer.java index 8627abe95d4..317dd57d256 100644 --- a/Mage.Sets/src/mage/cards/s/SlaughterhouseBouncer.java +++ b/Mage.Sets/src/mage/cards/s/SlaughterhouseBouncer.java @@ -1,23 +1,21 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.condition.common.HellbentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class SlaughterhouseBouncer extends CardImpl { @@ -31,13 +29,10 @@ public final class SlaughterhouseBouncer extends CardImpl { this.toughness = new MageInt(3); // Hellbent - When Slaughterhouse Bouncer dies, if you have no cards in hand, target creature gets -3/-3 until end of turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new DiesSourceTriggeredAbility(new BoostTargetEffect(-3, -3, Duration.EndOfTurn)), - HellbentCondition.instance, - AbilityWord.HELLBENT.formatWord() + "When {this} dies, if you have no cards in hand, target creature gets -3/-3 until end of turn." - ); + Ability ability = new DiesSourceTriggeredAbility(new BoostTargetEffect(-3, -3, Duration.EndOfTurn)) + .withInterveningIf(HellbentCondition.instance); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability); + this.addAbility(ability.setAbilityWord(AbilityWord.HELLBENT)); } private SlaughterhouseBouncer(final SlaughterhouseBouncer card) { diff --git a/Mage.Sets/src/mage/cards/s/Slay.java b/Mage.Sets/src/mage/cards/s/Slay.java index f76c49fe73a..d27d8e9237e 100644 --- a/Mage.Sets/src/mage/cards/s/Slay.java +++ b/Mage.Sets/src/mage/cards/s/Slay.java @@ -10,6 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -28,7 +29,7 @@ public final class Slay extends CardImpl { // Destroy target green creature. It can't be regenerated. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); diff --git a/Mage.Sets/src/mage/cards/s/SlayerOfTheWicked.java b/Mage.Sets/src/mage/cards/s/SlayerOfTheWicked.java index d816915ae33..df5b5762239 100644 --- a/Mage.Sets/src/mage/cards/s/SlayerOfTheWicked.java +++ b/Mage.Sets/src/mage/cards/s/SlayerOfTheWicked.java @@ -12,6 +12,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class SlayerOfTheWicked extends CardImpl { // When Slayer of the Wicked enters the battlefield, you may destroy target Vampire, Werewolf, or Zombie. Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), true); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SlimefootThallidTransplant.java b/Mage.Sets/src/mage/cards/s/SlimefootThallidTransplant.java index 1f7150d6b7a..ff06adec65c 100644 --- a/Mage.Sets/src/mage/cards/s/SlimefootThallidTransplant.java +++ b/Mage.Sets/src/mage/cards/s/SlimefootThallidTransplant.java @@ -1,8 +1,7 @@ - package mage.cards.s; import mage.MageInt; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.DraftFromSpellbookEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -10,6 +9,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import java.util.Arrays; @@ -22,7 +22,7 @@ import java.util.UUID; */ public final class SlimefootThallidTransplant extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("a Swamp or Forest"); + private static final FilterPermanent filter = new FilterControlledPermanent("a Swamp or Forest you control"); static { filter.add(Predicates.or( @@ -49,7 +49,7 @@ public final class SlimefootThallidTransplant extends CardImpl { "Yavimaya Sapherd" )); - public SlimefootThallidTransplant (UUID ownerId, CardSetInfo setInfo) { + public SlimefootThallidTransplant(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{G}"); this.supertype.add(SuperType.LEGENDARY); @@ -58,9 +58,7 @@ public final class SlimefootThallidTransplant extends CardImpl { this.toughness = new MageInt(2); // Whenever a Swamp or Forest you control enters, draft a card from Slimefoot, Thallid Transplant’s spellbook. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility( - new DraftFromSpellbookEffect(spellbook), filter - )); + this.addAbility(new EntersBattlefieldAllTriggeredAbility(new DraftFromSpellbookEffect(spellbook), filter)); } private SlimefootThallidTransplant(final SlimefootThallidTransplant card) { diff --git a/Mage.Sets/src/mage/cards/s/SlingshotGoblin.java b/Mage.Sets/src/mage/cards/s/SlingshotGoblin.java index 16cd0477d76..71031f1e7b2 100644 --- a/Mage.Sets/src/mage/cards/s/SlingshotGoblin.java +++ b/Mage.Sets/src/mage/cards/s/SlingshotGoblin.java @@ -16,6 +16,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class SlingshotGoblin extends CardImpl { // {R}, {tap}: Slingshot Goblin deals 2 damage to target blue creature. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2), new ManaCostsImpl<>("{R}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SlinnVodaTheRisingDeep.java b/Mage.Sets/src/mage/cards/s/SlinnVodaTheRisingDeep.java index 69914bc1fce..598b4389652 100644 --- a/Mage.Sets/src/mage/cards/s/SlinnVodaTheRisingDeep.java +++ b/Mage.Sets/src/mage/cards/s/SlinnVodaTheRisingDeep.java @@ -1,11 +1,8 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnToHandFromBattlefieldAllEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; @@ -16,8 +13,9 @@ import mage.constants.SuperType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class SlinnVodaTheRisingDeep extends CardImpl { @@ -25,14 +23,11 @@ public final class SlinnVodaTheRisingDeep extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { - filter.add(Predicates.not( - Predicates.or( - SubType.KRAKEN.getPredicate(), - SubType.LEVIATHAN.getPredicate(), - SubType.OCTOPUS.getPredicate(), - SubType.MERFOLK.getPredicate(), - SubType.SERPENT.getPredicate()) - )); + filter.add(Predicates.not(SubType.MERFOLK.getPredicate())); + filter.add(Predicates.not(SubType.KRAKEN.getPredicate())); + filter.add(Predicates.not(SubType.LEVIATHAN.getPredicate())); + filter.add(Predicates.not(SubType.OCTOPUS.getPredicate())); + filter.add(Predicates.not(SubType.SERPENT.getPredicate())); } public SlinnVodaTheRisingDeep(UUID ownerId, CardSetInfo setInfo) { @@ -47,13 +42,11 @@ public final class SlinnVodaTheRisingDeep extends CardImpl { this.addAbility(new KickerAbility("{1}{U}")); // When Slinn Voda, the Rising Deep enters the battlefield, if it was kicked, return all creatures to their owners' hands except for Merfolk, Krakens, Leviathans, Octopuses, and Serpents. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ReturnToHandFromBattlefieldAllEffect(filter)), - KickedCondition.ONCE, - "when {this} enters, if it was kicked, " - + "return all creatures to their owners' hands except for " - + "Merfolk, Krakens, Leviathans, Octopuses, and Serpents." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new ReturnToHandFromBattlefieldAllEffect(filter) + .setText("return all creatures to their owners' hands except for " + + "Merfolk, Krakens, Leviathans, Octopuses, and Serpents") + ).withInterveningIf(KickedCondition.ONCE)); } private SlinnVodaTheRisingDeep(final SlinnVodaTheRisingDeep card) { diff --git a/Mage.Sets/src/mage/cards/s/SlipOnTheRing.java b/Mage.Sets/src/mage/cards/s/SlipOnTheRing.java index 236b405d3b2..98c80fc5587 100644 --- a/Mage.Sets/src/mage/cards/s/SlipOnTheRing.java +++ b/Mage.Sets/src/mage/cards/s/SlipOnTheRing.java @@ -9,6 +9,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -27,7 +28,7 @@ public final class SlipOnTheRing extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); // Exile target creature you own, then return it to the battlefield under your control. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new ExileThenReturnTargetEffect(true, false)); // The Ring tempts you. this.getSpellAbility().addEffect(new TheRingTemptsYouEffect()); diff --git a/Mage.Sets/src/mage/cards/s/SliverHive.java b/Mage.Sets/src/mage/cards/s/SliverHive.java index 3a6ecaf21d9..98cf77e5fb3 100644 --- a/Mage.Sets/src/mage/cards/s/SliverHive.java +++ b/Mage.Sets/src/mage/cards/s/SliverHive.java @@ -1,11 +1,11 @@ - package mage.cards.s; import mage.abilities.Ability; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.mana.ColorlessManaAbility; import mage.abilities.mana.ConditionalAnyColorManaAbility; @@ -14,7 +14,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterSpell; import mage.filter.common.FilterControlledPermanent; import mage.game.permanent.token.SliverToken; @@ -22,36 +21,36 @@ import mage.game.permanent.token.SliverToken; import java.util.UUID; /** - * * @author emerald000 */ public final class SliverHive extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("Sliver"); private static final FilterSpell filterSpell = new FilterSpell("a Sliver spell"); static { - } - - static { - filter.add(SubType.SLIVER.getPredicate()); filterSpell.add(SubType.SLIVER.getPredicate()); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.SLIVER, "you control a Sliver") + ); + public SliverHive(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // {T}: Add {C}. this.addAbility(new ColorlessManaAbility()); // {T}: Add one mana of any color. Spend this mana only to cast a Sliver spell. - this.addAbility(new ConditionalAnyColorManaAbility(new TapSourceCost(), 1, new ConditionalSpellManaBuilder(filterSpell), true)); + this.addAbility(new ConditionalAnyColorManaAbility( + new TapSourceCost(), 1, new ConditionalSpellManaBuilder(filterSpell), true + )); // {5}, {T}: Create a 1/1 colorless Sliver creature token. Activate this ability only if you control a Sliver. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new SliverToken()), new TapSourceCost(), - new PermanentsOnTheBattlefieldCondition(filter), - "{5}, {T}: Create a 1/1 colorless Sliver creature token. Activate only if you control a Sliver."); - ability.addCost(new GenericManaCost(5)); + Ability ability = new ActivateIfConditionActivatedAbility( + new CreateTokenEffect(new SliverToken()), new GenericManaCost(5), condition + ); + ability.addCost(new TapSourceCost()); this.addAbility(ability); } @@ -63,4 +62,4 @@ public final class SliverHive extends CardImpl { public SliverHive copy() { return new SliverHive(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/SmashToSmithereens.java b/Mage.Sets/src/mage/cards/s/SmashToSmithereens.java index 02829adafe0..883cac3e083 100644 --- a/Mage.Sets/src/mage/cards/s/SmashToSmithereens.java +++ b/Mage.Sets/src/mage/cards/s/SmashToSmithereens.java @@ -1,6 +1,5 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -13,6 +12,8 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; +import java.util.UUID; + /** * * @author jonubuu @@ -42,7 +43,7 @@ class SmashToSmithereensEffect extends OneShotEffect { SmashToSmithereensEffect() { super(Outcome.Detriment); - staticText = "Destroy target artifact. Smash to Smithereens deals 3 damage to that artifact's controller"; + staticText = "Destroy target artifact. {this} deals 3 damage to that artifact's controller"; } private SmashToSmithereensEffect(final SmashToSmithereensEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/SmellFear.java b/Mage.Sets/src/mage/cards/s/SmellFear.java index 61d944332fe..17427d15649 100644 --- a/Mage.Sets/src/mage/cards/s/SmellFear.java +++ b/Mage.Sets/src/mage/cards/s/SmellFear.java @@ -6,8 +6,8 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -27,7 +27,7 @@ public final class SmellFear extends CardImpl { "
Target creature you control fights up to one target creature you don't control" )); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1, StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL, false)); + this.getSpellAbility().addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); } private SmellFear(final SmellFear card) { diff --git a/Mage.Sets/src/mage/cards/s/SmeltWardGatekeepers.java b/Mage.Sets/src/mage/cards/s/SmeltWardGatekeepers.java index 1e74e613adc..61544fadbaa 100644 --- a/Mage.Sets/src/mage/cards/s/SmeltWardGatekeepers.java +++ b/Mage.Sets/src/mage/cards/s/SmeltWardGatekeepers.java @@ -3,39 +3,26 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.YouControlTwoOrMoreGatesCondition; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; -import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.common.GatesYouControlHint; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledPermanent; -import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.target.common.TargetOpponentsCreaturePermanent; import java.util.UUID; /** * @author LevelX2 */ - - public final class SmeltWardGatekeepers extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent(); - - static { - filter.add(SubType.GATE.getPredicate()); - } - - private static final Condition gatesCondition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); - public SmeltWardGatekeepers(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.subtype.add(SubType.HUMAN); @@ -45,16 +32,14 @@ public final class SmeltWardGatekeepers extends CardImpl { this.toughness = new MageInt(4); // When Smelt-Ward Gatekeepers enters the battlefield, if you control two or more Gates, gain control of target creature an opponent controls until end of turn. Untap that creature. That creature gains haste until end of turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new GainControlTargetEffect(Duration.EndOfTurn)), - gatesCondition, - "When {this} enters, if you control two or more Gates, gain control of target creature an opponent controls until end of turn. Untap that creature. It gains haste until end of turn."); - ability.addEffect(new UntapTargetEffect()); - ability.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn)); - Target target = new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE); - ability.addTarget(target); - ability.addHint(new ConditionHint(gatesCondition, "You control two or more Gates")); - this.addAbility(ability); + Ability ability = new EntersBattlefieldTriggeredAbility(new GainControlTargetEffect(Duration.EndOfTurn)) + .withInterveningIf(YouControlTwoOrMoreGatesCondition.instance); + ability.addEffect(new UntapTargetEffect().setText("untap that creature")); + ability.addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("It gains haste until end of turn")); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability.addHint(GatesYouControlHint.instance)); } private SmeltWardGatekeepers(final SmeltWardGatekeepers card) { diff --git a/Mage.Sets/src/mage/cards/s/SmeltWardIgnus.java b/Mage.Sets/src/mage/cards/s/SmeltWardIgnus.java index 2a7a7220155..1467a4a06b0 100644 --- a/Mage.Sets/src/mage/cards/s/SmeltWardIgnus.java +++ b/Mage.Sets/src/mage/cards/s/SmeltWardIgnus.java @@ -14,6 +14,7 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -48,7 +49,7 @@ public final class SmeltWardIgnus extends CardImpl { HasteAbility.getInstance(), Duration.EndOfTurn ).setText("It gains haste until end of turn")); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SmirkingSpelljacker.java b/Mage.Sets/src/mage/cards/s/SmirkingSpelljacker.java index 47a815e0176..c81d986891e 100644 --- a/Mage.Sets/src/mage/cards/s/SmirkingSpelljacker.java +++ b/Mage.Sets/src/mage/cards/s/SmirkingSpelljacker.java @@ -6,7 +6,6 @@ import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.MayCastTargetCardEffect; @@ -60,12 +59,7 @@ public final class SmirkingSpelljacker extends CardImpl { this.addAbility(ability); // Whenever Smirking Spelljacker attacks, if a card is exiled with it, you may cast the exiled card without paying its mana cost. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new SmirkingSpelljackerEffect()), - SmirkingSpelljackerCondition.instance, - "Whenever {this} attacks, if a card is exiled with it, " - + "you may cast the exiled card without paying its mana cost." - )); + this.addAbility(new AttacksTriggeredAbility(new SmirkingSpelljackerEffect()).withInterveningIf(SmirkingSpelljackerCondition.instance)); } private SmirkingSpelljacker(final SmirkingSpelljacker card) { @@ -90,7 +84,7 @@ enum SmirkingSpelljackerCondition implements Condition { @Override public String toString() { - return "if a card is exiled with it"; + return "a card is exiled with it"; } } @@ -126,4 +120,4 @@ class SmirkingSpelljackerEffect extends OneShotEffect { return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/Smite.java b/Mage.Sets/src/mage/cards/s/Smite.java index 442335ce236..e30744e8355 100644 --- a/Mage.Sets/src/mage/cards/s/Smite.java +++ b/Mage.Sets/src/mage/cards/s/Smite.java @@ -8,6 +8,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.BlockedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -27,7 +28,7 @@ public final class Smite extends CardImpl { // Destroy target blocked creature. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect(false)); } diff --git a/Mage.Sets/src/mage/cards/s/SmokeTeller.java b/Mage.Sets/src/mage/cards/s/SmokeTeller.java index 77efc054b4e..7ddaebac3f0 100644 --- a/Mage.Sets/src/mage/cards/s/SmokeTeller.java +++ b/Mage.Sets/src/mage/cards/s/SmokeTeller.java @@ -18,6 +18,7 @@ import mage.filter.predicate.card.FaceDownPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -44,7 +45,7 @@ public final class SmokeTeller extends CardImpl { // 1U: Look at target face-down creature. Ability ability = new SimpleActivatedAbility(new SmokeTellerLookFaceDownEffect(), new ManaCostsImpl<>("{1}{U}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/Smokestack.java b/Mage.Sets/src/mage/cards/s/Smokestack.java index 889eef8da55..eb3855151a7 100644 --- a/Mage.Sets/src/mage/cards/s/Smokestack.java +++ b/Mage.Sets/src/mage/cards/s/Smokestack.java @@ -2,9 +2,9 @@ package mage.cards.s; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -48,7 +48,7 @@ class SmokestackEffect extends OneShotEffect { SmokestackEffect() { super(Outcome.Sacrifice); - this.staticText = "that player sacrifices a permanent for each soot counter on Smokestack"; + this.staticText = "that player sacrifices a permanent of their choice for each soot counter on {this}"; } private SmokestackEffect(final SmokestackEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/Smother.java b/Mage.Sets/src/mage/cards/s/Smother.java index 05b6892795a..9c3b204c490 100644 --- a/Mage.Sets/src/mage/cards/s/Smother.java +++ b/Mage.Sets/src/mage/cards/s/Smother.java @@ -9,6 +9,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -27,7 +28,7 @@ public final class Smother extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}"); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); } diff --git a/Mage.Sets/src/mage/cards/s/SnakeOfTheGoldenGrove.java b/Mage.Sets/src/mage/cards/s/SnakeOfTheGoldenGrove.java index 0ce84366155..a7a4090dcf8 100644 --- a/Mage.Sets/src/mage/cards/s/SnakeOfTheGoldenGrove.java +++ b/Mage.Sets/src/mage/cards/s/SnakeOfTheGoldenGrove.java @@ -1,12 +1,8 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.TributeNotPaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.keyword.TributeAbility; import mage.cards.CardImpl; @@ -14,25 +10,25 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SnakeOfTheGoldenGrove extends CardImpl { public SnakeOfTheGoldenGrove(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); this.subtype.add(SubType.SNAKE); this.power = new MageInt(4); this.toughness = new MageInt(4); - // Tribute 3
+ // Tribute 3 this.addAbility(new TributeAbility(3)); + // When Snake of the Golden Grove enters the battlefield, if tribute wasn't paid, you gain 4 life. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new GainLifeEffect(4), false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, TributeNotPaidCondition.instance, - "When {this} enters, if tribute wasn't paid, you gain 4 life.")); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(4)).withInterveningIf(TributeNotPaidCondition.instance)); } private SnakeOfTheGoldenGrove(final SnakeOfTheGoldenGrove card) { diff --git a/Mage.Sets/src/mage/cards/s/SnarlingGorehound.java b/Mage.Sets/src/mage/cards/s/SnarlingGorehound.java index 56f5cc6ba15..bce9fa9c418 100644 --- a/Mage.Sets/src/mage/cards/s/SnarlingGorehound.java +++ b/Mage.Sets/src/mage/cards/s/SnarlingGorehound.java @@ -1,7 +1,7 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.keyword.SurveilEffect; import mage.abilities.keyword.MenaceAbility; import mage.cards.CardImpl; @@ -10,7 +10,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.PowerPredicate; @@ -22,7 +22,7 @@ import java.util.UUID; public final class SnarlingGorehound extends CardImpl { private static final FilterPermanent filter - = new FilterCreaturePermanent("another creature with power 2 or less"); + = new FilterControlledCreaturePermanent("another creature you control with power 2 or less"); static { filter.add(AnotherPredicate.instance); @@ -40,7 +40,7 @@ public final class SnarlingGorehound extends CardImpl { this.addAbility(new MenaceAbility(false)); // Whenever another creature with power 2 or less you control enters, surveil 1. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new SurveilEffect(1), filter)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility(new SurveilEffect(1), filter)); } private SnarlingGorehound(final SnarlingGorehound card) { diff --git a/Mage.Sets/src/mage/cards/s/SnarlingUndorak.java b/Mage.Sets/src/mage/cards/s/SnarlingUndorak.java index c9e393437e2..97b19a55261 100644 --- a/Mage.Sets/src/mage/cards/s/SnarlingUndorak.java +++ b/Mage.Sets/src/mage/cards/s/SnarlingUndorak.java @@ -15,6 +15,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class SnarlingUndorak extends CardImpl { // {2}{G}: Target Beast creature gets +1/+1 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(1, 1, Duration.EndOfTurn), new ManaCostsImpl<>("{2}{G}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Morph {1}{G}{G} this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{1}{G}{G}"))); diff --git a/Mage.Sets/src/mage/cards/s/SnowFortress.java b/Mage.Sets/src/mage/cards/s/SnowFortress.java index 1276c396fdf..7a45faf73e4 100644 --- a/Mage.Sets/src/mage/cards/s/SnowFortress.java +++ b/Mage.Sets/src/mage/cards/s/SnowFortress.java @@ -19,6 +19,7 @@ import mage.constants.Zone; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.filter.common.FilterCreatureAttackingYou; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -51,7 +52,7 @@ public final class SnowFortress extends CardImpl { // {3}: Snow Fortress deals 1 damage to target creature without flying that's attacking you. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new GenericManaCost(3)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SnowHound.java b/Mage.Sets/src/mage/cards/s/SnowHound.java index eafb9f224bb..3d61ad59192 100644 --- a/Mage.Sets/src/mage/cards/s/SnowHound.java +++ b/Mage.Sets/src/mage/cards/s/SnowHound.java @@ -1,52 +1,48 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.ReturnToHandSourceEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author fireshoes */ public final class SnowHound extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("green or blue creature"); + static { filter.add(Predicates.or( new ColorPredicate(ObjectColor.GREEN), - new ColorPredicate(ObjectColor.BLUE))); + new ColorPredicate(ObjectColor.BLUE) + )); } public SnowHound(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.DOG); this.power = new MageInt(1); this.toughness = new MageInt(1); // {1}, {tap}: Return Snow Hound and target green or blue creature you control to their owner's hand. - Effect effect = new ReturnToHandSourceEffect(true); - effect.setText("Return {this}"); - Ability ability = new SimpleActivatedAbility(effect, new ManaCostsImpl<>("{1}")); + Ability ability = new SimpleActivatedAbility(new ReturnToHandSourceEffect(true).setText("Return {this}"), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); - effect = new ReturnToHandTargetEffect(); - effect.setText("and target green or blue creature you control to their owner's hand"); - ability.addTarget(new TargetControlledCreaturePermanent(filter)); - ability.addEffect(effect); + ability.addEffect(new ReturnToHandTargetEffect().setText("and target green or blue creature you control to their owner's hand")); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SnuffOut.java b/Mage.Sets/src/mage/cards/s/SnuffOut.java index 2d22affd606..03a750a1f52 100644 --- a/Mage.Sets/src/mage/cards/s/SnuffOut.java +++ b/Mage.Sets/src/mage/cards/s/SnuffOut.java @@ -10,10 +10,13 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; import mage.filter.common.FilterLandPermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author LevelX2 @@ -36,7 +39,7 @@ public final class SnuffOut extends CardImpl { // // Destroy target nonblack creature. It can't be regenerated. this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); } private SnuffOut(final SnuffOut card) { diff --git a/Mage.Sets/src/mage/cards/s/SoShiny.java b/Mage.Sets/src/mage/cards/s/SoShiny.java index b93d68566e8..3dd86bde66f 100644 --- a/Mage.Sets/src/mage/cards/s/SoShiny.java +++ b/Mage.Sets/src/mage/cards/s/SoShiny.java @@ -5,7 +5,6 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.DontUntapInControllersUntapStepEnchantedEffect; import mage.abilities.effects.common.TapEnchantedEffect; @@ -31,14 +30,14 @@ import java.util.UUID; */ public final class SoShiny extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent(); + private static final FilterPermanent filter = new FilterControlledPermanent("you control a token"); static { filter.add(TokenPredicate.TRUE); } private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); - private static final Hint hint = new ConditionHint(condition, "You control a token"); + private static final Hint hint = new ConditionHint(condition); public SoShiny(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); @@ -49,16 +48,11 @@ public final class SoShiny extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget)); // When So Shiny enters the battlefield, if you control a token, tap enchanted creature, then scry 2. - ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new TapEnchantedEffect()), - condition, "When {this} enters, " + - "if you control a token, tap enchanted creature, then scry 2." - ); - ability.addEffect(new ScryEffect(2)); + Ability ability = new EntersBattlefieldTriggeredAbility(new TapEnchantedEffect()).withInterveningIf(condition); + ability.addEffect(new ScryEffect(2).concatBy(", then")); this.addAbility(ability.addHint(hint)); // Enchanted creature doesn't untap during its controller's untap step. diff --git a/Mage.Sets/src/mage/cards/s/SoaringLightbringer.java b/Mage.Sets/src/mage/cards/s/SoaringLightbringer.java index ffde788564e..388f6ca634b 100644 --- a/Mage.Sets/src/mage/cards/s/SoaringLightbringer.java +++ b/Mage.Sets/src/mage/cards/s/SoaringLightbringer.java @@ -2,7 +2,7 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.AttacksPlayerWithCreaturesTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -13,9 +13,7 @@ import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.token.GlimmerToken; -import mage.target.targetpointer.FixedTarget; import java.util.UUID; @@ -47,7 +45,7 @@ public final class SoaringLightbringer extends CardImpl { ))); // Whenever you attack a player, create a 1/1 white Glimmer enchantment creature token that's tapped and attacking that player. - this.addAbility(new SoaringLightbringerTriggeredAbility()); + this.addAbility(new AttacksPlayerWithCreaturesTriggeredAbility(new SoaringLightbringerEffect(), SetTargetPointer.PLAYER)); } private SoaringLightbringer(final SoaringLightbringer card) { @@ -60,37 +58,6 @@ public final class SoaringLightbringer extends CardImpl { } } -class SoaringLightbringerTriggeredAbility extends TriggeredAbilityImpl { - - SoaringLightbringerTriggeredAbility() { - super(Zone.BATTLEFIELD, new SoaringLightbringerEffect()); - setTriggerPhrase("Whenever you attack a player, "); - } - - private SoaringLightbringerTriggeredAbility(final SoaringLightbringerTriggeredAbility ability) { - super(ability); - } - - @Override - public SoaringLightbringerTriggeredAbility copy() { - return new SoaringLightbringerTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DEFENDER_ATTACKED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (!isControlledBy(event.getPlayerId()) || game.getPlayer(event.getTargetId()) == null) { - return false; - } - this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId())); - return true; - } -} - class SoaringLightbringerEffect extends OneShotEffect { SoaringLightbringerEffect() { diff --git a/Mage.Sets/src/mage/cards/s/SokenzanRenegade.java b/Mage.Sets/src/mage/cards/s/SokenzanRenegade.java index 18a06add7df..3383750f36d 100644 --- a/Mage.Sets/src/mage/cards/s/SokenzanRenegade.java +++ b/Mage.Sets/src/mage/cards/s/SokenzanRenegade.java @@ -1,25 +1,27 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.abilities.keyword.BushidoAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SokenzanRenegade extends CardImpl { @@ -36,12 +38,8 @@ public final class SokenzanRenegade extends CardImpl { // At the beginning of your upkeep, if a player has more cards in hand than each other player, // the player who has the most cards in hand gains control of Sokenzan Renegade. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new SokenzanRenegadeEffect()), - OnePlayerHasTheMostCards.instance, - "At the beginning of your upkeep, if a player has more cards in hand than each other player, the player who has the most cards in hand gains control of {this}" - )); - + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SokenzanRenegadeEffect()) + .withInterveningIf(OnePlayerHasTheMostCards.instance)); } private SokenzanRenegade(final SokenzanRenegade card) { diff --git a/Mage.Sets/src/mage/cards/s/SoldeviSentry.java b/Mage.Sets/src/mage/cards/s/SoldeviSentry.java index a6ce6342c42..d721d8dc604 100644 --- a/Mage.Sets/src/mage/cards/s/SoldeviSentry.java +++ b/Mage.Sets/src/mage/cards/s/SoldeviSentry.java @@ -32,7 +32,7 @@ public final class SoldeviSentry extends CardImpl { new DrawCardTargetEffect(1, true), false ), true) - .setText("Choose target opponent. Regenerate Soldevi Sentry. " + .setText("Choose target opponent. Regenerate {this}. " + "When it regenerates this way, that player may draw a card"), new GenericManaCost(1) ); @@ -48,4 +48,4 @@ public final class SoldeviSentry extends CardImpl { public SoldeviSentry copy() { return new SoldeviSentry(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/SoldierReplica.java b/Mage.Sets/src/mage/cards/s/SoldierReplica.java index 302d0c9aa97..f98e0f7b6cc 100644 --- a/Mage.Sets/src/mage/cards/s/SoldierReplica.java +++ b/Mage.Sets/src/mage/cards/s/SoldierReplica.java @@ -14,6 +14,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterAttackingOrBlockingCreature; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class SoldierReplica extends CardImpl { this.toughness = new MageInt(3); Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(3, "it"), new ManaCostsImpl<>("{1}{W}")); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(new FilterAttackingOrBlockingCreature())); + ability.addTarget(new TargetPermanent(new FilterAttackingOrBlockingCreature())); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SoltariVisionary.java b/Mage.Sets/src/mage/cards/s/SoltariVisionary.java index aef0cc4f2a6..1571fe604f3 100644 --- a/Mage.Sets/src/mage/cards/s/SoltariVisionary.java +++ b/Mage.Sets/src/mage/cards/s/SoltariVisionary.java @@ -1,32 +1,31 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToAPlayerTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.ShadowAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterEnchantmentPermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; import mage.target.TargetPermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class SoltariVisionary extends CardImpl { + private static final FilterPermanent filter = new FilterEnchantmentPermanent("enchantment that player controls"); + public SoltariVisionary(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); this.subtype.add(SubType.SOLTARI); this.subtype.add(SubType.CLERIC); @@ -37,7 +36,10 @@ public final class SoltariVisionary extends CardImpl { this.addAbility(ShadowAbility.getInstance()); // Whenever Soltari Visionary deals damage to a player, destroy target enchantment that player controls. - this.addAbility(new SoltariVisionaryTriggeredAbility()); + Ability ability = new DealsDamageToAPlayerTriggeredAbility(new DestroyTargetEffect(), false, true); + ability.addTarget(new TargetPermanent(filter)); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); + this.addAbility(ability); } private SoltariVisionary(final SoltariVisionary card) { @@ -49,43 +51,3 @@ public final class SoltariVisionary extends CardImpl { return new SoltariVisionary(this); } } - -class SoltariVisionaryTriggeredAbility extends TriggeredAbilityImpl { - - SoltariVisionaryTriggeredAbility() { - super(Zone.BATTLEFIELD, new DestroyTargetEffect(), false); - } - - private SoltariVisionaryTriggeredAbility(final SoltariVisionaryTriggeredAbility ability) { - super(ability); - } - - @Override - public SoltariVisionaryTriggeredAbility copy() { - return new SoltariVisionaryTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Permanent soltari = game.getPermanent(event.getSourceId()); - if (soltari != null && soltari.getId().equals(this.getSourceId())) { - FilterEnchantmentPermanent filter = new FilterEnchantmentPermanent("enchantment that player controls."); - filter.add(new ControllerIdPredicate(event.getPlayerId())); - filter.setMessage("enchantment controlled by " + game.getPlayer(event.getTargetId()).getLogName()); - this.getTargets().clear(); - this.addTarget(new TargetPermanent(filter)); - return true; - } - return false; - } - - @Override - public String getRule() { - return "Whenever {this} deals damage to a player, destroy target enchantment that player controls."; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SomberwaldStag.java b/Mage.Sets/src/mage/cards/s/SomberwaldStag.java index 3d3e33fda47..c308b1a6e1e 100644 --- a/Mage.Sets/src/mage/cards/s/SomberwaldStag.java +++ b/Mage.Sets/src/mage/cards/s/SomberwaldStag.java @@ -10,10 +10,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author LevelX2 */ @@ -29,7 +32,7 @@ public final class SomberwaldStag extends CardImpl { Effect effect = new FightTargetSourceEffect(); effect.setText("you may have it fight target creature you don't control"); Ability ability = new EntersBattlefieldTriggeredAbility(effect, true); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/Somnophore.java b/Mage.Sets/src/mage/cards/s/Somnophore.java index cca5c21f436..cf65ad0ca5f 100644 --- a/Mage.Sets/src/mage/cards/s/Somnophore.java +++ b/Mage.Sets/src/mage/cards/s/Somnophore.java @@ -23,6 +23,7 @@ import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -91,7 +92,7 @@ class SomnophoreTriggeredAbility extends TriggeredAbilityImpl { filter.add(new ControllerIdPredicate(opponent.getId())); this.getTargets().clear(); - this.addTarget(new TargetCreaturePermanent(filter)); + this.addTarget(new TargetPermanent(filter)); return true; } } diff --git a/Mage.Sets/src/mage/cards/s/Songstitcher.java b/Mage.Sets/src/mage/cards/s/Songstitcher.java index 6d5a8e93dd1..13cb7d6112d 100644 --- a/Mage.Sets/src/mage/cards/s/Songstitcher.java +++ b/Mage.Sets/src/mage/cards/s/Songstitcher.java @@ -15,6 +15,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.filter.common.FilterAttackingCreature; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class Songstitcher extends CardImpl { // {1}{W}: Prevent all combat damage that would be dealt this turn by target attacking creature with flying. Ability ability = new SimpleActivatedAbility(new PreventDamageByTargetEffect(Duration.EndOfTurn, true) .withTextOptions(true, false), new ManaCostsImpl<>("{1}{W}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SonicTheHedgehog.java b/Mage.Sets/src/mage/cards/s/SonicTheHedgehog.java new file mode 100644 index 00000000000..6007ee92063 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SonicTheHedgehog.java @@ -0,0 +1,72 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.DealtDamageAnyTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.game.permanent.token.TreasureToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SonicTheHedgehog extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("creature you control with flash or haste"); + + static { + filter.add(Predicates.or( + new AbilityPredicate(FlashAbility.class), + new AbilityPredicate(HasteAbility.class) + )); + } + + public SonicTheHedgehog(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{R}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HEDGEHOG); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Gotta Go Fast -- Whenever Sonic the Hedgehog attacks, put a +1/+1 counter on each creature you control with flash or haste. + this.addAbility(new AttacksTriggeredAbility( + new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter) + ).withFlavorWord("Gotta Go Fast")); + + // Whenever a creature you control with flash or haste is dealt damage, create a tapped Treasure token. + this.addAbility(new DealtDamageAnyTriggeredAbility( + new CreateTokenEffect(new TreasureToken(), 1, true), + filter, SetTargetPointer.NONE, false + )); + } + + private SonicTheHedgehog(final SonicTheHedgehog card) { + super(card); + } + + @Override + public SonicTheHedgehog copy() { + return new SonicTheHedgehog(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SootstokeKindler.java b/Mage.Sets/src/mage/cards/s/SootstokeKindler.java index c6cf8cf842a..d23d40e26e6 100644 --- a/Mage.Sets/src/mage/cards/s/SootstokeKindler.java +++ b/Mage.Sets/src/mage/cards/s/SootstokeKindler.java @@ -17,6 +17,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -46,7 +47,7 @@ public final class SootstokeKindler extends CardImpl { SimpleActivatedAbility ability = new SimpleActivatedAbility( new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SoratamiMirrorGuard.java b/Mage.Sets/src/mage/cards/s/SoratamiMirrorGuard.java index fad971a7a4b..7f888ef5bc4 100644 --- a/Mage.Sets/src/mage/cards/s/SoratamiMirrorGuard.java +++ b/Mage.Sets/src/mage/cards/s/SoratamiMirrorGuard.java @@ -20,6 +20,7 @@ import mage.filter.common.FilterControlledLandPermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; @@ -49,7 +50,7 @@ public final class SoratamiMirrorGuard extends CardImpl { // {2}, Return a land you control to its owner's hand: Target creature with power 2 or less can't be blocked this turn. Ability ability = new SimpleActivatedAbility(new CantBeBlockedTargetEffect(), new GenericManaCost(2)); ability.addCost(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(filter))); - ability.addTarget(new TargetCreaturePermanent(filterCreature)); + ability.addTarget(new TargetPermanent(filterCreature)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SorayaTheFalconer.java b/Mage.Sets/src/mage/cards/s/SorayaTheFalconer.java index 7548831e065..9727f7bdf80 100644 --- a/Mage.Sets/src/mage/cards/s/SorayaTheFalconer.java +++ b/Mage.Sets/src/mage/cards/s/SorayaTheFalconer.java @@ -18,8 +18,11 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.constants.SubType.BIRD; + /** * * @author L_J @@ -39,7 +42,7 @@ public final class SorayaTheFalconer extends CardImpl { // {1}{W}: Target Bird creature gains banding until end of turn. Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(BandingAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{1}{W}")); - ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent(SubType.BIRD, "Bird creature"))); + ability.addTarget(new TargetPermanent(new FilterCreaturePermanent(BIRD, "Bird creature"))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SorceressQueen.java b/Mage.Sets/src/mage/cards/s/SorceressQueen.java index 1c7f147aefe..21dacda5a1e 100644 --- a/Mage.Sets/src/mage/cards/s/SorceressQueen.java +++ b/Mage.Sets/src/mage/cards/s/SorceressQueen.java @@ -15,6 +15,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class SorceressQueen extends CardImpl { // {tap}: Target creature other than Sorceress Queen becomes 0/2 until end of turn. Ability ability = new SimpleActivatedAbility(new SetBasePowerToughnessTargetEffect(0, 2, Duration.EndOfTurn), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SorinOfHouseMarkov.java b/Mage.Sets/src/mage/cards/s/SorinOfHouseMarkov.java index 9064d66d8b2..ccbbb37b09e 100644 --- a/Mage.Sets/src/mage/cards/s/SorinOfHouseMarkov.java +++ b/Mage.Sets/src/mage/cards/s/SorinOfHouseMarkov.java @@ -1,17 +1,15 @@ package mage.cards.s; import mage.MageInt; -import mage.constants.Pronoun; -import mage.abilities.triggers.BeginningOfPostcombatMainTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.YouGainedLifeCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ExileAndReturnSourceEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; import mage.abilities.keyword.ExtortAbility; import mage.abilities.keyword.LifelinkAbility; import mage.abilities.keyword.TransformAbility; +import mage.abilities.triggers.BeginningOfPostcombatMainTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -24,8 +22,8 @@ import java.util.UUID; */ public final class SorinOfHouseMarkov extends CardImpl { - private static final Condition condition = new YouGainedLifeCondition(ComparisonType.OR_GREATER, 3); - private static final Hint hint = new ConditionHint(condition, "You gained 3 or more life this turn"); + private static final Condition condition = new YouGainedLifeCondition(ComparisonType.MORE_THAN, 2); + private static final Hint hint = new ConditionHint(condition); public SorinOfHouseMarkov(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); @@ -46,14 +44,9 @@ public final class SorinOfHouseMarkov extends CardImpl { // At the beginning of your postcombat main phase, if you gained 3 or more life this turn, exile Sorin of House Markov, then return him to the battlefield transformed under his owner's control. this.addAbility(new TransformAbility()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfPostcombatMainTriggeredAbility( - new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.SHE), - false - ), condition, "At the beginning of your postcombat main phase, " - + "if you gained 3 or more life this turn, exile {this}, " - + "then return him to the battlefield transformed under his owner's control." - ).addHint(hint), new PlayerGainedLifeWatcher()); + this.addAbility(new BeginningOfPostcombatMainTriggeredAbility( + new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.HE), false + ).withInterveningIf(condition).addHint(hint), new PlayerGainedLifeWatcher()); } private SorinOfHouseMarkov(final SorinOfHouseMarkov card) { diff --git a/Mage.Sets/src/mage/cards/s/SotheraTheSupervoid.java b/Mage.Sets/src/mage/cards/s/SotheraTheSupervoid.java new file mode 100644 index 00000000000..e4750c3fb71 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SotheraTheSupervoid.java @@ -0,0 +1,170 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.counters.Counters; +import mage.filter.StaticFilters; +import mage.game.ExileZone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInExile; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.util.CardUtil; +import mage.util.RandomUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SotheraTheSupervoid extends CardImpl { + + public SotheraTheSupervoid(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + + // Whenever a creature you control dies, each opponent chooses a creature they control and exiles it. + this.addAbility(new DiesCreatureTriggeredAbility( + new SotheraTheSupervoidExileEffect(), false, + StaticFilters.FILTER_CONTROLLED_A_CREATURE + )); + + // At the beginning of your end step, if a player controls no creatures, sacrifice Sothera, then put a creature card exiled with it onto the battlefield under your control with two additional +1/+1 counters on it. + Ability ability = new BeginningOfEndStepTriggeredAbility(new SacrificeSourceEffect()) + .withInterveningIf(SotheraTheSupervoidCondition.instance); + ability.addEffect(new SotheraTheSupervoidReturnEffect()); + this.addAbility(ability); + } + + private SotheraTheSupervoid(final SotheraTheSupervoid card) { + super(card); + } + + @Override + public SotheraTheSupervoid copy() { + return new SotheraTheSupervoid(this); + } +} + +enum SotheraTheSupervoidCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return game + .getState() + .getPlayersInRange(source.getControllerId(), game) + .stream() + .anyMatch(playerId -> !game.getBattlefield().contains( + StaticFilters.FILTER_CONTROLLED_CREATURE, playerId, source, game, 1 + )); + } + + @Override + public String toString() { + return "a player controls no creatures"; + } +} + +class SotheraTheSupervoidExileEffect extends OneShotEffect { + + SotheraTheSupervoidExileEffect() { + super(Outcome.Benefit); + staticText = "each opponent chooses a creature they control and exiles it"; + } + + private SotheraTheSupervoidExileEffect(final SotheraTheSupervoidExileEffect effect) { + super(effect); + } + + @Override + public SotheraTheSupervoidExileEffect copy() { + return new SotheraTheSupervoidExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID playerId : game.getOpponents(source.getControllerId())) { + Player player = game.getPlayer(playerId); + if (player == null || !game.getBattlefield().contains( + StaticFilters.FILTER_CONTROLLED_CREATURE, playerId, source, game, 1 + )) { + return false; + } + TargetPermanent target = new TargetControlledCreaturePermanent(); + target.withChooseHint("to exile"); + target.withNotTarget(true); + player.choose(Outcome.Exile, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent == null) { + continue; + } + player.moveCardsToExile( + permanent, source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); + } + return true; + } +} + +class SotheraTheSupervoidReturnEffect extends OneShotEffect { + + SotheraTheSupervoidReturnEffect() { + super(Outcome.Benefit); + staticText = ", then put a creature card exiled with it onto the battlefield " + + "under your control with two additional +1/+1 counters on it"; + } + + private SotheraTheSupervoidReturnEffect(final SotheraTheSupervoidReturnEffect effect) { + super(effect); + } + + @Override + public SotheraTheSupervoidReturnEffect copy() { + return new SotheraTheSupervoidReturnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + if (player == null || exileZone == null) { + return false; + } + Card card; + switch (exileZone.count(StaticFilters.FILTER_CARD_CREATURE, game)) { + case 0: + return false; + case 1: + card = RandomUtil.randomFromCollection(exileZone.getCards(StaticFilters.FILTER_CARD_CREATURE, game)); + break; + default: + TargetCard target = new TargetCardInExile(StaticFilters.FILTER_CARD_CREATURE, exileZone.getId()); + player.choose(outcome, target, source, game); + card = game.getCard(target.getFirstTarget()); + } + if (card == null) { + return false; + } + game.setEnterWithCounters(card.getId(), new Counters(CounterType.P1P1.createInstance(2))); + return player.moveCards(card, Zone.BATTLEFIELD, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SoulExchange.java b/Mage.Sets/src/mage/cards/s/SoulExchange.java index 5770ae38cda..a8882481600 100644 --- a/Mage.Sets/src/mage/cards/s/SoulExchange.java +++ b/Mage.Sets/src/mage/cards/s/SoulExchange.java @@ -1,6 +1,5 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.Cost; import mage.abilities.costs.common.ExileTargetCost; @@ -16,7 +15,9 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCardInYourGraveyard; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; /** * @author MarcoMarin @@ -27,12 +28,11 @@ public final class SoulExchange extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}{B}"); // As an additional cost to cast Soul Exchange, exile a creature you control. - Cost cost = new ExileTargetCost(new TargetControlledCreaturePermanent(StaticFilters.FILTER_CONTROLLED_A_CREATURE)); - this.getSpellAbility().addCost(cost); + this.getSpellAbility().addCost(new ExileTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_A_CREATURE))); + // Return target creature card from your graveyard to the battlefield. Put a +2/+2 counter on that creature if the exiled creature was a Thrull. this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().addEffect(new SoulExchangeEffect()); - } private SoulExchange(final SoulExchange card) { diff --git a/Mage.Sets/src/mage/cards/s/SoulReap.java b/Mage.Sets/src/mage/cards/s/SoulReap.java index 0a8ed8ac482..974447cffe7 100644 --- a/Mage.Sets/src/mage/cards/s/SoulReap.java +++ b/Mage.Sets/src/mage/cards/s/SoulReap.java @@ -18,6 +18,7 @@ import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.watchers.Watcher; @@ -39,7 +40,7 @@ public final class SoulReap extends CardImpl { // Destroy target nongreen creature. Its controller loses 3 life if you've cast another black spell this turn. this.getSpellAbility().addEffect(new SoulReapEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addWatcher(new SoulReapWatcher()); } diff --git a/Mage.Sets/src/mage/cards/s/SoulSeizer.java b/Mage.Sets/src/mage/cards/s/SoulSeizer.java index 43db8c735ff..5dc4a1fe428 100644 --- a/Mage.Sets/src/mage/cards/s/SoulSeizer.java +++ b/Mage.Sets/src/mage/cards/s/SoulSeizer.java @@ -2,7 +2,8 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.TransformAbility; @@ -11,15 +12,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; import java.util.UUID; @@ -41,7 +38,11 @@ public final class SoulSeizer extends CardImpl { // When Soul Seizer deals combat damage to a player, you may transform it. If you do, attach it to target creature that player controls. this.addAbility(new TransformAbility()); - this.addAbility(new SoulSeizerTriggeredAbility()); + TriggeredAbility ability = new DealsCombatDamageToAPlayerTriggeredAbility(new SoulSeizerEffect(), true, true); + ability.setTriggerPhrase("When {this} deals combat damage to a player, "); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE)); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); + this.addAbility(ability); } private SoulSeizer(final SoulSeizer card) { @@ -54,53 +55,11 @@ public final class SoulSeizer extends CardImpl { } } -class SoulSeizerTriggeredAbility extends TriggeredAbilityImpl { - - public SoulSeizerTriggeredAbility() { - super(Zone.BATTLEFIELD, new SoulSeizerEffect(), true); - } - - private SoulSeizerTriggeredAbility(final SoulSeizerTriggeredAbility ability) { - super(ability); - } - - @Override - public SoulSeizerTriggeredAbility copy() { - return new SoulSeizerTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; - if (damageEvent.isCombatDamage() && event.getSourceId().equals(this.getSourceId())) { - Player opponent = game.getPlayer(event.getPlayerId()); - if (opponent != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature " + opponent.getLogName() + " controls"); - filter.add(new ControllerIdPredicate(opponent.getId())); - - this.getTargets().clear(); - this.addTarget(new TargetCreaturePermanent(filter)); - return true; - } - } - return false; - } - - @Override - public String getRule() { - return "When {this} deals combat damage to a player, you may transform it. If you do, attach it to target creature that player controls"; - } -} - class SoulSeizerEffect extends OneShotEffect { SoulSeizerEffect() { super(Outcome.GainControl); + this.staticText = "you may transform it. If you do, attach it to target creature that player controls"; } private SoulSeizerEffect(final SoulSeizerEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/SoulShred.java b/Mage.Sets/src/mage/cards/s/SoulShred.java index 32bc68bb3de..c938ec8f5e7 100644 --- a/Mage.Sets/src/mage/cards/s/SoulShred.java +++ b/Mage.Sets/src/mage/cards/s/SoulShred.java @@ -7,8 +7,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author fireshoes @@ -20,7 +23,7 @@ public final class SoulShred extends CardImpl { // Soul Shred deals 3 damage to target nonblack creature. You gain 3 life. this.getSpellAbility().addEffect(new DamageTargetEffect(3)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.getSpellAbility().addEffect(new GainLifeEffect(3)); } diff --git a/Mage.Sets/src/mage/cards/s/SoulSnare.java b/Mage.Sets/src/mage/cards/s/SoulSnare.java index caa87d4258c..9e9bfb02baa 100644 --- a/Mage.Sets/src/mage/cards/s/SoulSnare.java +++ b/Mage.Sets/src/mage/cards/s/SoulSnare.java @@ -12,6 +12,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; import mage.filter.common.FilterCreatureAttackingYou; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -28,7 +29,7 @@ public final class SoulSnare extends CardImpl { Ability ability = new SimpleActivatedAbility( new ExileTargetEffect(), new ManaCostsImpl<>("{W}")); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(new FilterCreatureAttackingYou(true))); + ability.addTarget(new TargetPermanent(new FilterCreatureAttackingYou(true))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SoulSwallower.java b/Mage.Sets/src/mage/cards/s/SoulSwallower.java index 53a2b1ca105..a6968c90ef4 100644 --- a/Mage.Sets/src/mage/cards/s/SoulSwallower.java +++ b/Mage.Sets/src/mage/cards/s/SoulSwallower.java @@ -1,20 +1,20 @@ package mage.cards.s; -import java.util.UUID; - import mage.MageInt; -import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; +import java.util.UUID; + /** * @author fireshoes */ @@ -30,12 +30,8 @@ public final class SoulSwallower extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Delirium — At the beginning of your upkeep, if there are four or more card types among cards in your graveyard, put three +1/+1 counters on Soul Swallower. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(3))), - DeliriumCondition.instance, - "Delirium — At the beginning of your upkeep, if there are four or more card types among cards in your graveyard, " - + "put three +1/+1 counters on Soul Swallower.") - .addHint(CardTypesInGraveyardCount.YOU.getHint())); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(3))) + .withInterveningIf(DeliriumCondition.instance).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); } private SoulSwallower(final SoulSwallower card) { diff --git a/Mage.Sets/src/mage/cards/s/Soulblast.java b/Mage.Sets/src/mage/cards/s/Soulblast.java index 176acb76271..017e3f05fce 100644 --- a/Mage.Sets/src/mage/cards/s/Soulblast.java +++ b/Mage.Sets/src/mage/cards/s/Soulblast.java @@ -46,7 +46,7 @@ class SoulblastEffect extends OneShotEffect { SoulblastEffect() { super(Outcome.Benefit); - this.staticText = "Soulblast deals damage to any target equal to the total power of the sacrificed creatures"; + this.staticText = "{this} deals damage to any target equal to the total power of the sacrificed creatures"; } private SoulblastEffect(final SoulblastEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/Soulherder.java b/Mage.Sets/src/mage/cards/s/Soulherder.java index 57c5499b6a7..c26f70fec1c 100644 --- a/Mage.Sets/src/mage/cards/s/Soulherder.java +++ b/Mage.Sets/src/mage/cards/s/Soulherder.java @@ -2,10 +2,10 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.ZoneChangeTriggeredAbility; import mage.abilities.effects.common.ExileThenReturnTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -18,7 +18,7 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -41,7 +41,7 @@ public final class Soulherder extends CardImpl { Ability ability = new BeginningOfEndStepTriggeredAbility(TargetController.YOU, new ExileThenReturnTargetEffect(false, true), true ); - ability.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SoulhunterRakshasa.java b/Mage.Sets/src/mage/cards/s/SoulhunterRakshasa.java index d3b9c723caa..a1f38766859 100644 --- a/Mage.Sets/src/mage/cards/s/SoulhunterRakshasa.java +++ b/Mage.Sets/src/mage/cards/s/SoulhunterRakshasa.java @@ -4,18 +4,15 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.CantBlockAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.condition.common.CastFromHandSourcePermanentCondition; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; -import mage.game.Game; -import mage.players.Player; import mage.target.common.TargetOpponent; import mage.watchers.common.CastFromHandWatcher; @@ -26,6 +23,8 @@ import java.util.UUID; */ public final class SoulhunterRakshasa extends CardImpl { + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.SWAMP)); + public SoulhunterRakshasa(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); this.subtype.add(SubType.DEMON); @@ -37,10 +36,9 @@ public final class SoulhunterRakshasa extends CardImpl { this.addAbility(new CantBlockAbility()); // When Soulhunter Rakshasa enters the battlefield, if you cast it from your hand, it deals 1 damage to target opponent for each Swamp you control. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new SoulhunterRakshasaEffect()), - CastFromEverywhereSourceCondition.instance, - "When {this} enters, if you cast it from your hand, it deals 1 damage to target opponent for each Swamp you control."); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(xValue)) + .withInterveningIf(CastFromHandSourcePermanentCondition.instance) + .withRuleTextReplacement(true); ability.addTarget(new TargetOpponent()); this.addAbility(ability, new CastFromHandWatcher()); } @@ -54,35 +52,3 @@ public final class SoulhunterRakshasa extends CardImpl { return new SoulhunterRakshasa(this); } } - -class SoulhunterRakshasaEffect extends OneShotEffect { - - private static final FilterPermanent filter = new FilterControlledPermanent(SubType.SWAMP); - - public SoulhunterRakshasaEffect() { - super(Outcome.Damage); - this.staticText = "{this} deals 1 damage to target opponent for each Swamp you control."; - } - - private SoulhunterRakshasaEffect(final SoulhunterRakshasaEffect effect) { - super(effect); - } - - @Override - public SoulhunterRakshasaEffect copy() { - return new SoulhunterRakshasaEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - int amount = game.getBattlefield().count(filter, source.getControllerId(), source, game); - if (amount > 0) { - Player player = game.getPlayer(source.getFirstTarget()); - if (player != null) { - player.damage(amount, source.getSourceId(), source, game); - return true; - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SoulswornSpirit.java b/Mage.Sets/src/mage/cards/s/SoulswornSpirit.java index fbde9965605..145c1e407b8 100644 --- a/Mage.Sets/src/mage/cards/s/SoulswornSpirit.java +++ b/Mage.Sets/src/mage/cards/s/SoulswornSpirit.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -11,17 +9,17 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.StaticFilters; -import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class SoulswornSpirit extends CardImpl { - + public SoulswornSpirit(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); this.subtype.add(SubType.SPIRIT); this.power = new MageInt(2); @@ -29,12 +27,11 @@ public final class SoulswornSpirit extends CardImpl { // Soulsworn Spirit can't be blocked. this.addAbility(new CantBeBlockedSourceAbility()); - + // When Soulsworn Spirit enters the battlefield, detain target creature an opponent controls. //(Until your next turn, that creature can't attack or block and its activated abilities can't be activated.) Ability ability = new EntersBattlefieldTriggeredAbility(new DetainTargetEffect()); - TargetCreaturePermanent target = new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE); - ability.addTarget(target); + ability.addTarget(new TargetOpponentsCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SowingMycospawn.java b/Mage.Sets/src/mage/cards/s/SowingMycospawn.java index dc43d599d5f..ecdd609024b 100644 --- a/Mage.Sets/src/mage/cards/s/SowingMycospawn.java +++ b/Mage.Sets/src/mage/cards/s/SowingMycospawn.java @@ -3,7 +3,6 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CastSourceTriggeredAbility; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; @@ -44,11 +43,7 @@ public final class SowingMycospawn extends CardImpl { ))); // When you cast this spell, if it was kicked, exile target land. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new CastSourceTriggeredAbility(new ExileTargetEffect()), - KickedCondition.ONCE, "When you cast this spell, " + - "if it was kicked, exile target land." - ); + Ability ability = new CastSourceTriggeredAbility(new ExileTargetEffect()).withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetLandPermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SpaceMarineScout.java b/Mage.Sets/src/mage/cards/s/SpaceMarineScout.java index 4f87b52b5bf..ba9f9ba53b9 100644 --- a/Mage.Sets/src/mage/cards/s/SpaceMarineScout.java +++ b/Mage.Sets/src/mage/cards/s/SpaceMarineScout.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.OpponentControlsMoreCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.VigilanceAbility; @@ -46,12 +45,9 @@ public final class SpaceMarineScout extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // Concealed Position -- When Space Marine Scout enters the battlefield, if an opponent controls more lands than you, you may search your library for a Plains card, put it onto the battlefield tapped, then shuffle. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInPlayEffect( - new TargetCardInLibrary(filter), true - ), true), condition, "When {this} enters, if an opponent controls more lands " + - "than you, you may search your library for a Plains card, put it onto the battlefield tapped, then shuffle." - ).withFlavorWord("Concealed Position")); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true), true + ).withInterveningIf(condition).withFlavorWord("Concealed Position")); } private SpaceMarineScout(final SpaceMarineScout card) { diff --git a/Mage.Sets/src/mage/cards/s/SparkElemental.java b/Mage.Sets/src/mage/cards/s/SparkElemental.java index 890dafc2fc3..980f6de38b4 100644 --- a/Mage.Sets/src/mage/cards/s/SparkElemental.java +++ b/Mage.Sets/src/mage/cards/s/SparkElemental.java @@ -1,26 +1,25 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.events.GameEvent.EventType; +import mage.constants.TargetController; + +import java.util.UUID; /** - * * @author North */ public final class SparkElemental extends CardImpl { public SparkElemental(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(3); @@ -28,7 +27,9 @@ public final class SparkElemental extends CardImpl { this.addAbility(TrampleAbility.getInstance()); this.addAbility(HasteAbility.getInstance()); - this.addAbility(new OnEventTriggeredAbility(EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new SacrificeSourceEffect())); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.NEXT, new SacrificeSourceEffect(), false + )); } private SparkElemental(final SparkElemental card) { diff --git a/Mage.Sets/src/mage/cards/s/SparkFiend.java b/Mage.Sets/src/mage/cards/s/SparkFiend.java index 6d72318f696..0f66d2bf910 100644 --- a/Mage.Sets/src/mage/cards/s/SparkFiend.java +++ b/Mage.Sets/src/mage/cards/s/SparkFiend.java @@ -50,7 +50,7 @@ class SparkFiendEffect extends OneShotEffect { SparkFiendEffect() { super(Outcome.Sacrifice); - this.staticText = "roll two six-sided dice. If you rolled 2, 3, or 12, sacrifice Spark Fiend. If you rolled 7 or 11, don't roll dice for Spark Fiend during any of your following upkeeps. If you rolled any other total, note that total"; + this.staticText = "roll two six-sided dice. If you rolled 2, 3, or 12, sacrifice {this}. If you rolled 7 or 11, don't roll dice for {this} during any of your following upkeeps. If you rolled any other total, note that total"; } private SparkFiendEffect(final SparkFiendEffect effect) { @@ -93,7 +93,7 @@ class SparkFiendUpkeepEffect extends OneShotEffect { SparkFiendUpkeepEffect() { super(Outcome.Sacrifice); - this.staticText = "roll two six-sided dice. If you rolled 7, sacrifice Spark Fiend. If you roll the noted total, don't roll dice for Spark Fiend during any of your following upkeeps. Otherwise, do nothing"; + this.staticText = "roll two six-sided dice. If you rolled 7, sacrifice {this}. If you roll the noted total, don't roll dice for {this} during any of your following upkeeps. Otherwise, do nothing"; } private SparkFiendUpkeepEffect(final SparkFiendUpkeepEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/SpeakerOfTheHeavens.java b/Mage.Sets/src/mage/cards/s/SpeakerOfTheHeavens.java index 2ced7bd3b9f..2fcfaa3cfb0 100644 --- a/Mage.Sets/src/mage/cards/s/SpeakerOfTheHeavens.java +++ b/Mage.Sets/src/mage/cards/s/SpeakerOfTheHeavens.java @@ -12,7 +12,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TimingRule; -import mage.constants.Zone; import mage.game.permanent.token.AngelToken; import java.util.UUID; @@ -38,10 +37,8 @@ public final class SpeakerOfTheHeavens extends CardImpl { // {T}: Create a 4/4 white Angel creature token with flying. Activate only if you have at least 7 more life than your starting life total and only as a sorcery. this.addAbility(new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new CreateTokenEffect(new AngelToken()), - new TapSourceCost(), MoreThanStartingLifeTotalCondition.SEVEN, - TimingRule.SORCERY - )); + new CreateTokenEffect(new AngelToken()), new TapSourceCost(), MoreThanStartingLifeTotalCondition.SEVEN + ).setTiming(TimingRule.SORCERY)); } private SpeakerOfTheHeavens(final SpeakerOfTheHeavens card) { @@ -52,4 +49,4 @@ public final class SpeakerOfTheHeavens extends CardImpl { public SpeakerOfTheHeavens copy() { return new SpeakerOfTheHeavens(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/SpearOfHeliod.java b/Mage.Sets/src/mage/cards/s/SpearOfHeliod.java index 9222b5f5eaa..85de10c7bbd 100644 --- a/Mage.Sets/src/mage/cards/s/SpearOfHeliod.java +++ b/Mage.Sets/src/mage/cards/s/SpearOfHeliod.java @@ -17,6 +17,7 @@ import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.other.DamagedPlayerThisTurnPredicate; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -44,7 +45,7 @@ public final class SpearOfHeliod extends CardImpl { // {1}{W}{W}, {T}: Destroy target creature that dealt damage to you this turn. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{1}{W}{W}")); ability.addCost(new TapSourceCost()); - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); ability.addTarget(target); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SpearbreakerBehemoth.java b/Mage.Sets/src/mage/cards/s/SpearbreakerBehemoth.java index 6c1c66b5f8d..ecbc1fc64d5 100644 --- a/Mage.Sets/src/mage/cards/s/SpearbreakerBehemoth.java +++ b/Mage.Sets/src/mage/cards/s/SpearbreakerBehemoth.java @@ -16,6 +16,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -43,7 +44,7 @@ public final class SpearbreakerBehemoth extends CardImpl { SimpleActivatedAbility ability = new SimpleActivatedAbility( new GainAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{1}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SpellboundDragon.java b/Mage.Sets/src/mage/cards/s/SpellboundDragon.java index 6e7b4347b4e..b23d4187dfe 100644 --- a/Mage.Sets/src/mage/cards/s/SpellboundDragon.java +++ b/Mage.Sets/src/mage/cards/s/SpellboundDragon.java @@ -1,7 +1,6 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; @@ -12,14 +11,16 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetDiscard; +import java.util.UUID; + /** * * @author jeffwadsworth @@ -54,7 +55,7 @@ class SpellboundDragonEffect extends OneShotEffect { SpellboundDragonEffect() { super(Outcome.BoostCreature); - staticText = "draw a card, then discard a card. Spellbound Dragon gets +X/+0 until end of turn, where X is the discarded card's mana value"; + staticText = "draw a card, then discard a card. {this} gets +X/+0 until end of turn, where X is the discarded card's mana value"; } private SpellboundDragonEffect(final SpellboundDragonEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/SpellweaverDuo.java b/Mage.Sets/src/mage/cards/s/SpellweaverDuo.java index 56d4e05bd79..8bb8dc88462 100644 --- a/Mage.Sets/src/mage/cards/s/SpellweaverDuo.java +++ b/Mage.Sets/src/mage/cards/s/SpellweaverDuo.java @@ -13,6 +13,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class SpellweaverDuo extends CardImpl { // When Spellweaver Duo enters the battlefield, you may return target tapped creature to its owner's hand. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SphinxBoneWand.java b/Mage.Sets/src/mage/cards/s/SphinxBoneWand.java index 7fd45681f59..5e51d11c7de 100644 --- a/Mage.Sets/src/mage/cards/s/SphinxBoneWand.java +++ b/Mage.Sets/src/mage/cards/s/SphinxBoneWand.java @@ -53,7 +53,7 @@ class SphinxBoneWandEffect extends OneShotEffect { SphinxBoneWandEffect() { super(Outcome.Damage); - this.staticText = "put a charge counter on Sphinx-Bone Wand. If you do, Sphinx-Bone Wand deals damage equal to the number of charge counters on it to any target"; + this.staticText = "put a charge counter on {this}. If you do, {this} deals damage equal to the number of charge counters on it to any target"; } private SphinxBoneWandEffect(final SphinxBoneWandEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/SpikeRogue.java b/Mage.Sets/src/mage/cards/s/SpikeRogue.java index 60054497861..0873b0b5323 100644 --- a/Mage.Sets/src/mage/cards/s/SpikeRogue.java +++ b/Mage.Sets/src/mage/cards/s/SpikeRogue.java @@ -1,6 +1,5 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; @@ -14,14 +13,13 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.counters.CounterType; -import mage.filter.StaticFilters; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class SpikeRogue extends CardImpl { @@ -43,7 +41,7 @@ public final class SpikeRogue extends CardImpl { // {2}, Remove a +1/+1 counter from a creature you control: Put a +1/+1 counter on Spike Rogue. Ability ability2 = new SimpleActivatedAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), new GenericManaCost(2)); - ability2.addCost(new RemoveCounterCost(new TargetControlledCreaturePermanent(1, 1, StaticFilters.FILTER_CONTROLLED_CREATURE, true), CounterType.P1P1)); + ability2.addCost(new RemoveCounterCost(new TargetControlledCreaturePermanent(), CounterType.P1P1)); this.addAbility(ability2); } diff --git a/Mage.Sets/src/mage/cards/s/SpinalVillain.java b/Mage.Sets/src/mage/cards/s/SpinalVillain.java index 024d66d413c..939bbe18f1e 100644 --- a/Mage.Sets/src/mage/cards/s/SpinalVillain.java +++ b/Mage.Sets/src/mage/cards/s/SpinalVillain.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class SpinalVillain extends CardImpl { // {tap}: Destroy target blue creature. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SpinningDarkness.java b/Mage.Sets/src/mage/cards/s/SpinningDarkness.java index 5d69e872bc7..11fccebbb95 100644 --- a/Mage.Sets/src/mage/cards/s/SpinningDarkness.java +++ b/Mage.Sets/src/mage/cards/s/SpinningDarkness.java @@ -22,8 +22,11 @@ import mage.filter.StaticFilters; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author emerald000 @@ -39,7 +42,7 @@ public final class SpinningDarkness extends CardImpl { // Spinning Darkness deals 3 damage to target nonblack creature. You gain 3 life. this.getSpellAbility().addEffect(new DamageTargetEffect(3)); this.getSpellAbility().addEffect(new GainLifeEffect(3)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); } private SpinningDarkness(final SpinningDarkness card) { diff --git a/Mage.Sets/src/mage/cards/s/SpinyStarfish.java b/Mage.Sets/src/mage/cards/s/SpinyStarfish.java index a4b9a5b1f5e..74f9d145ae3 100644 --- a/Mage.Sets/src/mage/cards/s/SpinyStarfish.java +++ b/Mage.Sets/src/mage/cards/s/SpinyStarfish.java @@ -1,22 +1,26 @@ package mage.cards.s; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.WatcherScope; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.token.StarfishToken; +import mage.util.CardUtil; import mage.watchers.Watcher; import java.util.HashMap; @@ -38,16 +42,9 @@ public final class SpinyStarfish extends CardImpl { this.addAbility(new SimpleActivatedAbility(new RegenerateSourceEffect(), new ManaCostsImpl<>("{U}"))); // At the beginning of each end step, if Spiny Starfish regenerated this turn, create a 0/1 blue Starfish creature token for each time it regenerated this turn. - this.addAbility( - new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - TargetController.ANY, new CreateTokenEffect( - new StarfishToken(), - new SpinyStarfishDynamicValue()), - false), - SpinyStarfishCondition.instance, - "At the beginning of each end step, if {this} regenerated this turn, create a 0/1 blue Starfish creature token for each time it regenerated this turn."), - new SpinyStarfishWatcher()); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.ANY, new CreateTokenEffect(new StarfishToken(), SpinyStarfishValue.instance), false + ).withInterveningIf(SpinyStarfishCondition.instance), new SpinyStarfishWatcher()); } private SpinyStarfish(final SpinyStarfish card) { @@ -66,66 +63,26 @@ enum SpinyStarfishCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - SpinyStarfishWatcher watcher = game.getState().getWatcher(SpinyStarfishWatcher.class); - return watcher != null && watcher.regeneratedCount(source.getSourceId()) != 0; + return SpinyStarfishWatcher.regeneratedCount(game, source) > 0; } @Override public String toString() { - return "if Spiny Starfish regenerated this turn"; + return "{this} regenerated this turn"; } - } -class SpinyStarfishWatcher extends Watcher { - - // Probably dumb to record all regeneration events, could just record this, - // but not sure how to know what source this watcher is attached to. - private final Map regeneratedCount = new HashMap<>(); - - public SpinyStarfishWatcher() { - super(WatcherScope.GAME); - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.REGENERATED) { - UUID regeneratedId = event.getTargetId(); - Integer count = regeneratedCount.get(regeneratedId); - if (count == null) { - count = 0; - } - regeneratedCount.put(regeneratedId, ++count); - } - } - - @Override - public void reset() { - super.reset(); - regeneratedCount.clear(); - } - - public int regeneratedCount(UUID sourceId) { - return regeneratedCount.getOrDefault(sourceId, 0); - } - -} - -class SpinyStarfishDynamicValue implements DynamicValue { +enum SpinyStarfishValue implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - SpinyStarfishWatcher watcher = game.getState().getWatcher( - SpinyStarfishWatcher.class); - if (watcher != null) { - return watcher.regeneratedCount(sourceAbility.getSourceId()); - } - return 0; + return SpinyStarfishWatcher.regeneratedCount(game, sourceAbility); } @Override - public SpinyStarfishDynamicValue copy() { - return new SpinyStarfishDynamicValue(); + public SpinyStarfishValue copy() { + return this; } @Override @@ -135,6 +92,35 @@ class SpinyStarfishDynamicValue implements DynamicValue { @Override public String getMessage() { - return "time {this} regenerated this turn"; + return "time it regenerated this turn"; + } +} + +class SpinyStarfishWatcher extends Watcher { + + private final Map regeneratedCount = new HashMap<>(); + + public SpinyStarfishWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.REGENERATED) { + regeneratedCount.compute(new MageObjectReference(event.getTargetId(), game), CardUtil::setOrIncrementValue); + } + } + + @Override + public void reset() { + super.reset(); + regeneratedCount.clear(); + } + + static int regeneratedCount(Game game, Ability source) { + return game.getState() + .getWatcher(SpinyStarfishWatcher.class) + .regeneratedCount + .getOrDefault(new MageObjectReference(source.getSourcePermanentOrLKI(game), game), 0); } } diff --git a/Mage.Sets/src/mage/cards/s/SpiresOfOrazca.java b/Mage.Sets/src/mage/cards/s/SpiresOfOrazca.java index 09c1026c17e..2e8945aa7e9 100644 --- a/Mage.Sets/src/mage/cards/s/SpiresOfOrazca.java +++ b/Mage.Sets/src/mage/cards/s/SpiresOfOrazca.java @@ -16,6 +16,7 @@ import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -45,7 +46,7 @@ public final class SpiresOfOrazca extends CardImpl { effect = new RemoveFromCombatTargetEffect(); effect.setText(" "); ability.addEffect(effect); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SpiritBonds.java b/Mage.Sets/src/mage/cards/s/SpiritBonds.java index d421a43a230..5bdf691fdc3 100644 --- a/Mage.Sets/src/mage/cards/s/SpiritBonds.java +++ b/Mage.Sets/src/mage/cards/s/SpiritBonds.java @@ -20,6 +20,7 @@ import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.game.permanent.token.SpiritWhiteToken; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; @@ -49,7 +50,7 @@ public final class SpiritBonds extends CardImpl { Ability ability = new SimpleActivatedAbility( new GainAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{1}{W}")); ability.addCost(new SacrificeTargetCost(filterSpirit)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SpiritMirror.java b/Mage.Sets/src/mage/cards/s/SpiritMirror.java index 27046c43c6f..1e304c1d5e3 100644 --- a/Mage.Sets/src/mage/cards/s/SpiritMirror.java +++ b/Mage.Sets/src/mage/cards/s/SpiritMirror.java @@ -1,45 +1,45 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.permanent.token.ReflectionToken; import mage.target.TargetPermanent; +import java.util.UUID; + /** * @author LevelX2 */ public final class SpiritMirror extends CardImpl { - private static final FilterPermanent filterToken = new FilterPermanent(SubType.REFLECTION, "Reflection token"); + private static final FilterPermanent filterToken = new FilterPermanent(SubType.REFLECTION, "there are no Reflection tokens on the battlefield"); private static final FilterPermanent filter = new FilterPermanent("Reflection"); static { - filterToken.add(SubType.REFLECTION.getPredicate()); filterToken.add(TokenPredicate.TRUE); filter.add(SubType.REFLECTION.getPredicate()); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filterToken, ComparisonType.EQUAL_TO, 0, false); + public SpiritMirror(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); // At the beginning of your upkeep, if there are no Reflection tokens on the battlefield, create a 2/2 white Reflection creature token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new ReflectionToken())), - new PermanentsOnTheBattlefieldCondition(filterToken, ComparisonType.EQUAL_TO, 0, false), - "At the beginning of your upkeep, if there are no Reflection tokens on the battlefield, create a 2/2 white Reflection creature token.")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new ReflectionToken())).withInterveningIf(condition)); // {0}: Destroy target Reflection. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new GenericManaCost(0)); diff --git a/Mage.Sets/src/mage/cards/s/SpiritWeaver.java b/Mage.Sets/src/mage/cards/s/SpiritWeaver.java index 15767aca4b7..97f81729947 100644 --- a/Mage.Sets/src/mage/cards/s/SpiritWeaver.java +++ b/Mage.Sets/src/mage/cards/s/SpiritWeaver.java @@ -17,6 +17,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -41,7 +42,7 @@ public final class SpiritWeaver extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(1); Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(0, 1, Duration.EndOfTurn), new GenericManaCost(2)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SpiritualSanctuary.java b/Mage.Sets/src/mage/cards/s/SpiritualSanctuary.java index 81619d25157..a29b5f56efe 100644 --- a/Mage.Sets/src/mage/cards/s/SpiritualSanctuary.java +++ b/Mage.Sets/src/mage/cards/s/SpiritualSanctuary.java @@ -1,11 +1,9 @@ - package mage.cards.s; -import java.util.UUID; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.GainLifeTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -13,32 +11,28 @@ import mage.constants.SubType; import mage.constants.TargetController; import mage.filter.FilterPermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class SpiritualSanctuary extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent(); + private static final FilterPermanent filter = new FilterPermanent(SubType.PLAINS, "that player controls a Plains"); static { - filter.add(SubType.PLAINS.getPredicate()); filter.add(TargetController.ACTIVE.getControllerPredicate()); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, false); + public SpiritualSanctuary(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); // At the beginning of each player's upkeep, if that player controls a Plains, they gain 1 life. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - TargetController.ANY, new GainLifeTargetEffect(1).setText("they gain 1 life"), - false - ), - new PermanentsOnTheBattlefieldCondition(filter), - "at the beginning of each player's upkeep, " - + "if that player controls a Plains, they gain 1 life" - )); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.EACH_PLAYER, new GainLifeTargetEffect(1).setText("they gain 1 life"), false + ).withInterveningIf(condition)); } private SpiritualSanctuary(final SpiritualSanctuary card) { diff --git a/Mage.Sets/src/mage/cards/s/SpiteMalice.java b/Mage.Sets/src/mage/cards/s/SpiteMalice.java index 27a4b2fc5fd..dd4cf56a26c 100644 --- a/Mage.Sets/src/mage/cards/s/SpiteMalice.java +++ b/Mage.Sets/src/mage/cards/s/SpiteMalice.java @@ -8,9 +8,12 @@ import mage.cards.SplitCard; import mage.constants.CardType; import mage.constants.SpellAbilityType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.TargetSpell; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author FenrisulfrX @@ -28,7 +31,7 @@ public final class SpiteMalice extends SplitCard { // Malice // Destroy target nonblack creature. It can't be regenerated. this.getRightHalfCard().getSpellAbility().addEffect(new DestroyTargetEffect(true)); - this.getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getRightHalfCard().getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); } private SpiteMalice(final SpiteMalice card) { diff --git a/Mage.Sets/src/mage/cards/s/SplashySpellcaster.java b/Mage.Sets/src/mage/cards/s/SplashySpellcaster.java index 0bcdfb6ba40..c7ae29d71ab 100644 --- a/Mage.Sets/src/mage/cards/s/SplashySpellcaster.java +++ b/Mage.Sets/src/mage/cards/s/SplashySpellcaster.java @@ -12,12 +12,11 @@ import mage.constants.SubType; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; /** - * * @author Susucr */ public final class SplashySpellcaster extends CardImpl { @@ -31,7 +30,7 @@ public final class SplashySpellcaster extends CardImpl { public SplashySpellcaster(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); - + this.subtype.add(SubType.ELEMENTAL); this.subtype.add(SubType.WIZARD); this.power = new MageInt(2); @@ -42,8 +41,7 @@ public final class SplashySpellcaster extends CardImpl { new CreateRoleAttachedTargetEffect(RoleType.SORCERER), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false ); - ability.addTarget(new TargetControlledCreaturePermanent(0, 1, filter, false)); - + ability.addTarget(new TargetPermanent(0, 1, filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/Splinterfright.java b/Mage.Sets/src/mage/cards/s/Splinterfright.java index 318a8d17bee..716e03e6c8a 100644 --- a/Mage.Sets/src/mage/cards/s/Splinterfright.java +++ b/Mage.Sets/src/mage/cards/s/Splinterfright.java @@ -1,41 +1,43 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; -import mage.game.events.GameEvent.EventType; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author North */ public final class Splinterfright extends CardImpl { + private static final DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURES); + public Splinterfright(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(0); this.toughness = new MageInt(0); this.addAbility(TrampleAbility.getInstance()); + // Splinterfright's power and toughness are each equal to the number of creature cards in your graveyard. - CardsInControllerGraveyardCount count = new CardsInControllerGraveyardCount(new FilterCreatureCard("creature cards")); - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(count))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(xValue))); + // At the beginning of your upkeep, put the top two cards of your library into your graveyard. - this.addAbility(new OnEventTriggeredAbility(EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", new MillCardsControllerEffect(2), false)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new MillCardsControllerEffect(2))); } private Splinterfright(final Splinterfright card) { diff --git a/Mage.Sets/src/mage/cards/s/SplitTheParty.java b/Mage.Sets/src/mage/cards/s/SplitTheParty.java index 21ab34362f1..3815306dc2c 100644 --- a/Mage.Sets/src/mage/cards/s/SplitTheParty.java +++ b/Mage.Sets/src/mage/cards/s/SplitTheParty.java @@ -1,9 +1,5 @@ package mage.cards.s; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -17,11 +13,14 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.TargetPlayer; -import mage.target.common.TargetCreaturePermanent; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; /** - * * @author weirddan455 */ public final class SplitTheParty extends CardImpl { @@ -72,7 +71,7 @@ class SplitThePartyEffect extends OneShotEffect { int halfCreatures = (numCreatures / 2) + (numCreatures % 2); FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures controlled by " + targetPlayer.getName()); filter.add(new ControllerIdPredicate(targetPlayer.getId())); - TargetCreaturePermanent target = new TargetCreaturePermanent(halfCreatures, halfCreatures, filter, true); + TargetPermanent target = new TargetPermanent(halfCreatures, halfCreatures, filter, true); if (controller.chooseTarget(outcome, target, source, game)) { Set cardsToHand = new HashSet<>(); for (UUID creatureId : target.getTargets()) { diff --git a/Mage.Sets/src/mage/cards/s/SporebackTroll.java b/Mage.Sets/src/mage/cards/s/SporebackTroll.java index d5ef05423f6..361679077be 100644 --- a/Mage.Sets/src/mage/cards/s/SporebackTroll.java +++ b/Mage.Sets/src/mage/cards/s/SporebackTroll.java @@ -14,8 +14,11 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_CREATURE_P1P1; + /** * * @author fireshoes @@ -34,7 +37,7 @@ public final class SporebackTroll extends CardImpl { // {1}{G}: Regenerate target creature with a +1/+1 counter on it. Ability ability = new SimpleActivatedAbility(new RegenerateTargetEffect(), new ManaCostsImpl<>("{1}{G}")); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_P1P1)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_P1P1)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/Sporogenesis.java b/Mage.Sets/src/mage/cards/s/Sporogenesis.java index 61960d3cf7c..29d093f1613 100644 --- a/Mage.Sets/src/mage/cards/s/Sporogenesis.java +++ b/Mage.Sets/src/mage/cards/s/Sporogenesis.java @@ -23,6 +23,7 @@ import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.game.permanent.token.SaprolingToken; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -44,7 +45,7 @@ public final class Sporogenesis extends CardImpl { // At the beginning of your upkeep, you may put a fungus counter on target nontoken creature. Ability ability = new BeginningOfUpkeepTriggeredAbility(new AddCountersTargetEffect(CounterType.FUNGUS.createInstance()), true); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Whenever a creature with a fungus counter on it dies, create a 1/1 green Saproling creature token for each fungus counter on that creature. diff --git a/Mage.Sets/src/mage/cards/s/SpringleafDrum.java b/Mage.Sets/src/mage/cards/s/SpringleafDrum.java index 9a19176ec54..478c2a72f9a 100644 --- a/Mage.Sets/src/mage/cards/s/SpringleafDrum.java +++ b/Mage.Sets/src/mage/cards/s/SpringleafDrum.java @@ -1,33 +1,26 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.common.TapTargetCost; import mage.abilities.mana.AnyColorManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.filter.StaticFilters; + +import java.util.UUID; /** * @author Loki */ public final class SpringleafDrum extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); - - static { - filter.add(TappedPredicate.UNTAPPED); - } - public SpringleafDrum(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{1}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); + // {T}, Tap an untapped creature you control: Add one mana of any color. Ability ability = new AnyColorManaAbility(); - ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, false))); + ability.addCost(new TapTargetCost(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SpyNetwork.java b/Mage.Sets/src/mage/cards/s/SpyNetwork.java index 036591054f7..98f916d29df 100644 --- a/Mage.Sets/src/mage/cards/s/SpyNetwork.java +++ b/Mage.Sets/src/mage/cards/s/SpyNetwork.java @@ -16,8 +16,8 @@ import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.TargetPlayer; -import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -103,7 +103,7 @@ class SpyNetworkFaceDownEffect extends OneShotEffect { FilterCreaturePermanent filter = new FilterCreaturePermanent("face down creature controlled by " + player.getLogName()); filter.add(FaceDownPredicate.instance); filter.add(new ControllerIdPredicate(player.getId())); - TargetCreaturePermanent target = new TargetCreaturePermanent(1, 1, filter, true); + TargetPermanent target = new TargetPermanent(1, 1, filter, true); if (target.canChoose(controller.getId(), source, game)) { while (controller.chooseUse(outcome, "Look at a face down creature controlled by " + player.getLogName() + "?", source, game)) { target.clearChosen(); diff --git a/Mage.Sets/src/mage/cards/s/SquadCommander.java b/Mage.Sets/src/mage/cards/s/SquadCommander.java index a4974b9e741..821fec403b8 100644 --- a/Mage.Sets/src/mage/cards/s/SquadCommander.java +++ b/Mage.Sets/src/mage/cards/s/SquadCommander.java @@ -2,16 +2,15 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.FullPartyCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.PartyCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.hint.common.PartyCountHint; import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -36,23 +35,19 @@ public final class SquadCommander extends CardImpl { this.toughness = new MageInt(3); // When Squad Commander enters the battlefield, create a 1/1 white Kor Warrior creature token for each creature in your party. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect( - new KorWarriorToken(), PartyCount.instance) + this.addAbility(new EntersBattlefieldTriggeredAbility( + new CreateTokenEffect(new KorWarriorToken(), PartyCount.instance) ).addHint(PartyCountHint.instance)); // At the beginning of combat on your turn, if you have a full party, creatures you control get +1/+0 and gain indestructible until end of turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - new BoostControlledEffect( - 1, 0, Duration.EndOfTurn - ) - ), FullPartyCondition.instance, "At the beginning of combat on your turn, " + - "if you have a full party, creatures you control get +1/+0 and gain indestructible until end of turn." - ); + Ability ability = new BeginningOfCombatTriggeredAbility( + new BoostControlledEffect(1, 0, Duration.EndOfTurn) + .setText("creatures you control get +1/+0") + ).withInterveningIf(FullPartyCondition.instance); ability.addEffect(new GainAbilityAllEffect( IndestructibleAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURE - )); + ).setText("and gain indestructible until end of turn")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/StalkingAssassin.java b/Mage.Sets/src/mage/cards/s/StalkingAssassin.java index f0dfc6a5b67..506107506ec 100644 --- a/Mage.Sets/src/mage/cards/s/StalkingAssassin.java +++ b/Mage.Sets/src/mage/cards/s/StalkingAssassin.java @@ -16,6 +16,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -46,7 +47,7 @@ public final class StalkingAssassin extends CardImpl { // {3}{B}, {T}: Destroy target tapped creature. ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{3}{B}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/StalkingYeti.java b/Mage.Sets/src/mage/cards/s/StalkingYeti.java index 3a9d6cc6a87..e8a2d84cc3b 100644 --- a/Mage.Sets/src/mage/cards/s/StalkingYeti.java +++ b/Mage.Sets/src/mage/cards/s/StalkingYeti.java @@ -1,29 +1,23 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.SourceOnBattlefieldCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnToHandSourceEffect; -import mage.constants.SubType; -import mage.constants.SuperType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetOpponentsCreaturePermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class StalkingYeti extends CardImpl { @@ -37,18 +31,15 @@ public final class StalkingYeti extends CardImpl { this.toughness = new MageInt(3); // When Stalking Yeti enters the battlefield, if it's on the battlefield, it deals damage equal to its power to target creature an opponent controls and that creature deals damage equal to its power to Stalking Yeti. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new StalkingYetiEffect()), - SourceOnBattlefieldCondition.instance, - "When {this} enters, if it's on the battlefield, " - + "it deals damage equal to its power to target creature an opponent controls " - + "and that creature deals damage equal to its power to {this}." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new StalkingYetiEffect()) + .withInterveningIf(SourceOnBattlefieldCondition.instance); ability.addTarget(new TargetOpponentsCreaturePermanent()); this.addAbility(ability); // {2}{snow}: Return Stalking Yeti to its owner's hand. Activate this ability only any time you could cast a sorcery. - this.addAbility(new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandSourceEffect(true), new ManaCostsImpl<>("{2}{S}"))); + this.addAbility(new ActivateAsSorceryActivatedAbility( + Zone.BATTLEFIELD, new ReturnToHandSourceEffect(true), new ManaCostsImpl<>("{2}{S}") + )); } private StalkingYeti(final StalkingYeti card) { @@ -86,6 +77,7 @@ class StalkingYetiEffect extends OneShotEffect { return false; } thatCreature.damage(thisCreature.getPower().getValue(), thisCreature.getId(), source, game, false, true); + game.processAction(); thisCreature.damage(thatCreature.getPower().getValue(), thatCreature.getId(), source, game, false, true); return true; } diff --git a/Mage.Sets/src/mage/cards/s/StallionOfAshmouth.java b/Mage.Sets/src/mage/cards/s/StallionOfAshmouth.java index 4caf6afde6e..3a3c3075ba2 100644 --- a/Mage.Sets/src/mage/cards/s/StallionOfAshmouth.java +++ b/Mage.Sets/src/mage/cards/s/StallionOfAshmouth.java @@ -3,12 +3,15 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import java.util.UUID; @@ -26,8 +29,7 @@ public final class StallionOfAshmouth extends CardImpl { // Delirium — {1}{B}: Stallion of Ashmouth gets +1/+1 until end of turn. Activate this ability only if there are // four or more card types among cards in your graveyard. - this.addAbility(new ConditionalActivatedAbility( - Zone.BATTLEFIELD, + this.addAbility(new ActivateIfConditionActivatedAbility( new BoostSourceEffect(1, 1, Duration.EndOfTurn), new ManaCostsImpl<>("{1}{B}"), DeliriumCondition.instance ).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); diff --git a/Mage.Sets/src/mage/cards/s/StalwartPathlighter.java b/Mage.Sets/src/mage/cards/s/StalwartPathlighter.java index 5bc9270cbb8..16291ad8b2c 100644 --- a/Mage.Sets/src/mage/cards/s/StalwartPathlighter.java +++ b/Mage.Sets/src/mage/cards/s/StalwartPathlighter.java @@ -1,16 +1,18 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.common.CovenCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.hint.common.CovenHint; import mage.abilities.keyword.IndestructibleAbility; import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; import java.util.UUID; @@ -32,14 +34,10 @@ public final class StalwartPathlighter extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // Coven — At the beginning of combat on your turn, if you control three or more creatures with different powers, creatures you control gain indestructible until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility(new GainAbilityControlledEffect( - IndestructibleAbility.getInstance(), Duration.EndOfTurn, - StaticFilters.FILTER_CONTROLLED_CREATURE - )), CovenCondition.instance, "At the beginning " + - "of combat on your turn, if you control three or more creatures with different powers, " + - "creatures you control gain indestructible until end of turn." - ).addHint(CovenHint.instance).setAbilityWord(AbilityWord.COVEN)); + this.addAbility(new BeginningOfCombatTriggeredAbility(new GainAbilityControlledEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURES + )).withInterveningIf(CovenCondition.instance).addHint(CovenHint.instance).setAbilityWord(AbilityWord.COVEN)); } private StalwartPathlighter(final StalwartPathlighter card) { diff --git a/Mage.Sets/src/mage/cards/s/StampedeRider.java b/Mage.Sets/src/mage/cards/s/StampedeRider.java index b37887a022e..0ab8f2d272e 100644 --- a/Mage.Sets/src/mage/cards/s/StampedeRider.java +++ b/Mage.Sets/src/mage/cards/s/StampedeRider.java @@ -1,11 +1,11 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.common.FerociousCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.common.FerociousHint; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -31,13 +31,9 @@ public final class StampedeRider extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // At the beginning of each combat, if you control a creature with power 4 or greater, Stampede Rider gets +1/+1 until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - TargetController.ANY, new BoostSourceEffect(1, 1, Duration.EndOfTurn), - false - ), FerociousCondition.instance, "At the beginning of each combat, " + - "if you control a creature with power 4 or greater, {this} gets +1/+1 until end of turn." - )); + this.addAbility(new BeginningOfCombatTriggeredAbility( + TargetController.ANY, new BoostSourceEffect(1, 1, Duration.EndOfTurn), false + ).withInterveningIf(FerociousCondition.instance).addHint(FerociousHint.instance)); } private StampedeRider(final StampedeRider card) { diff --git a/Mage.Sets/src/mage/cards/s/StampedingElkHerd.java b/Mage.Sets/src/mage/cards/s/StampedingElkHerd.java index f5b5a7bc4b7..6c54515a694 100644 --- a/Mage.Sets/src/mage/cards/s/StampedingElkHerd.java +++ b/Mage.Sets/src/mage/cards/s/StampedingElkHerd.java @@ -1,38 +1,35 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.FormidableCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class StampedingElkHerd extends CardImpl { public StampedingElkHerd(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); this.subtype.add(SubType.ELK); this.power = new MageInt(5); this.toughness = new MageInt(5); // Formidable — Whenever Stampeding Elk Herd attacks, if creatures you control have total power 8 or greater, creatures you control gain trample until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.EndOfTurn, new FilterControlledCreaturePermanent()), false), - FormidableCondition.instance, - "Formidable — Whenever {this} attacks, if creatures you control have total power 8 or greater, creatures you control gain trample until end of turn." - )); + this.addAbility(new AttacksTriggeredAbility(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES + )).withInterveningIf(FormidableCondition.instance).setAbilityWord(AbilityWord.FORMIDABLE)); } private StampedingElkHerd(final StampedingElkHerd card) { diff --git a/Mage.Sets/src/mage/cards/s/StandOrFall.java b/Mage.Sets/src/mage/cards/s/StandOrFall.java index d9aa5f889b3..d17588f3ae2 100644 --- a/Mage.Sets/src/mage/cards/s/StandOrFall.java +++ b/Mage.Sets/src/mage/cards/s/StandOrFall.java @@ -1,9 +1,9 @@ package mage.cards.s; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.combat.CantBlockAllEffect; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -17,7 +17,7 @@ import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.ArrayList; import java.util.List; @@ -77,7 +77,7 @@ class StandOrFallEffect extends OneShotEffect { } FilterCreaturePermanent opponentFilter = new FilterCreaturePermanent(); opponentFilter.add(new ControllerIdPredicate(oppId)); - TargetCreaturePermanent creatures = new TargetCreaturePermanent(0, Integer.MAX_VALUE, opponentFilter, true); + TargetPermanent creatures = new TargetPermanent(0, Integer.MAX_VALUE, opponentFilter, true); List pile1 = new ArrayList<>(); if (player.choose(Outcome.Neutral, creatures, source, game)) { List targets = creatures.getTargets(); diff --git a/Mage.Sets/src/mage/cards/s/StarCrownedStag.java b/Mage.Sets/src/mage/cards/s/StarCrownedStag.java index ca39f3e5089..f83d6e64c96 100644 --- a/Mage.Sets/src/mage/cards/s/StarCrownedStag.java +++ b/Mage.Sets/src/mage/cards/s/StarCrownedStag.java @@ -12,6 +12,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -34,7 +35,7 @@ public final class StarCrownedStag extends CardImpl { // Whenever attacks, tap target creature defending player controls. Ability ability = new AttacksTriggeredAbility(new TapTargetEffect(), false); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/StarDestroyer.java b/Mage.Sets/src/mage/cards/s/StarDestroyer.java index 02bfcf1b8a1..f3a3ffc6a85 100644 --- a/Mage.Sets/src/mage/cards/s/StarDestroyer.java +++ b/Mage.Sets/src/mage/cards/s/StarDestroyer.java @@ -16,8 +16,9 @@ import mage.filter.common.FilterCreatureOrPlayer; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.game.permanent.token.TIEFighterToken; -import mage.target.common.TargetCreatureOrPlayer; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetPermanentOrPlayer; import java.util.UUID; @@ -45,7 +46,7 @@ public final class StarDestroyer extends CardImpl { // {2}{U}: Tap target artifact creature. Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new ManaCostsImpl<>("{2}{U}")); - ability.addTarget(new TargetCreaturePermanent(filter1)); + ability.addTarget(new TargetPermanent(filter1)); this.addAbility(ability); // {2}{B}: Create a 1/1 black Starship artifact creature token with spaceflight named TIE Fighter. @@ -53,7 +54,7 @@ public final class StarDestroyer extends CardImpl { // {2}{R}: Star Destroyer deals 2 damge to target non-Starship creature or player. ability = new SimpleActivatedAbility(new DamageTargetEffect(2), new ManaCostsImpl<>("{2}{R}")); - ability.addTarget(new TargetCreatureOrPlayer(filter3)); + ability.addTarget(new TargetPermanentOrPlayer(filter3)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/StarbreachWhale.java b/Mage.Sets/src/mage/cards/s/StarbreachWhale.java new file mode 100644 index 00000000000..ccc70cc47e2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StarbreachWhale.java @@ -0,0 +1,45 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.WarpAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StarbreachWhale extends CardImpl { + + public StarbreachWhale(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.subtype.add(SubType.WHALE); + this.power = new MageInt(3); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When this creature enters, surveil 2. + this.addAbility(new EntersBattlefieldTriggeredAbility(new SurveilEffect(2))); + + // Warp {1}{U} + this.addAbility(new WarpAbility(this, "{1}{U}")); + } + + private StarbreachWhale(final StarbreachWhale card) { + super(card); + } + + @Override + public StarbreachWhale copy() { + return new StarbreachWhale(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StarfighterPilot.java b/Mage.Sets/src/mage/cards/s/StarfighterPilot.java new file mode 100644 index 00000000000..60133be6b99 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StarfighterPilot.java @@ -0,0 +1,38 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.BecomesTappedSourceTriggeredAbility; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StarfighterPilot extends CardImpl { + + public StarfighterPilot(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PILOT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever this creature becomes tapped, surveil 1. + this.addAbility(new BecomesTappedSourceTriggeredAbility(new SurveilEffect(1))); + } + + private StarfighterPilot(final StarfighterPilot card) { + super(card); + } + + @Override + public StarfighterPilot copy() { + return new StarfighterPilot(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StarforgedSword.java b/Mage.Sets/src/mage/cards/s/StarforgedSword.java index 9f9d50aa5ca..52e1c6bd132 100644 --- a/Mage.Sets/src/mage/cards/s/StarforgedSword.java +++ b/Mage.Sets/src/mage/cards/s/StarforgedSword.java @@ -4,7 +4,6 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAttachToTarget; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.GiftWasPromisedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.effects.common.continuous.LoseAbilityAttachedEffect; import mage.abilities.keyword.EquipAbility; @@ -33,10 +32,7 @@ public final class StarforgedSword extends CardImpl { this.addAbility(new GiftAbility(this, GiftType.TAPPED_FISH)); // When Starforged Sword enters, if the gift was promised, attach Starforged Sword to target creature you control. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldAttachToTarget(), GiftWasPromisedCondition.TRUE, - "When {this} enters, if the gift was promised, attach {this} to target creature you control." - )); + this.addAbility(new EntersBattlefieldAttachToTarget().withInterveningIf(GiftWasPromisedCondition.TRUE)); // Equipped creature gets +3/+3 and loses flying. Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(3, 3)); diff --git a/Mage.Sets/src/mage/cards/s/StarscreamPowerHungry.java b/Mage.Sets/src/mage/cards/s/StarscreamPowerHungry.java index 0e847a27e42..9000a352fdb 100644 --- a/Mage.Sets/src/mage/cards/s/StarscreamPowerHungry.java +++ b/Mage.Sets/src/mage/cards/s/StarscreamPowerHungry.java @@ -1,11 +1,10 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.CombatDamageDealtToYouTriggeredAbility; import mage.abilities.common.DrawCardControllerTriggeredAbility; import mage.abilities.condition.common.MonarchIsSourceControllerCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.hint.common.MonarchHint; @@ -41,18 +40,14 @@ public final class StarscreamPowerHungry extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever you draw a card, if you're the monarch, target opponent loses 2 life. - TriggeredAbility trigger = new ConditionalInterveningIfTriggeredAbility( - new DrawCardControllerTriggeredAbility(new LoseLifeTargetEffect(2), false), - MonarchIsSourceControllerCondition.instance, - "Whenever you draw a card, if you're the monarch, target opponent loses 2 life." - ); - trigger.addTarget(new TargetOpponent()); - trigger.addHint(MonarchHint.instance); - this.addAbility(trigger); + Ability ability = new DrawCardControllerTriggeredAbility(new LoseLifeTargetEffect(2), false) + .withInterveningIf(MonarchIsSourceControllerCondition.instance); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability.addHint(MonarchHint.instance)); // Whenever one or more creatures deal combat damage to you, convert Starscream. this.addAbility(new CombatDamageDealtToYouTriggeredAbility( - new TransformSourceEffect().setText("convert {this}") + new TransformSourceEffect().setText("convert {this}") )); } @@ -64,4 +59,4 @@ public final class StarscreamPowerHungry extends CardImpl { public StarscreamPowerHungry copy() { return new StarscreamPowerHungry(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/StarscreamSeekerLeader.java b/Mage.Sets/src/mage/cards/s/StarscreamSeekerLeader.java index 094c85c01c4..e8f24856628 100644 --- a/Mage.Sets/src/mage/cards/s/StarscreamSeekerLeader.java +++ b/Mage.Sets/src/mage/cards/s/StarscreamSeekerLeader.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.BecomesMonarchSourceControllerTriggeredAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.condition.common.MonarchIsNotSetCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.BecomesMonarchTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.hint.common.MonarchHint; @@ -48,15 +47,13 @@ public final class StarscreamSeekerLeader extends CardImpl { this.addAbility(HasteAbility.getInstance()); // Whenever Starscream deals combat damage to a player, if there is no monarch, that player becomes the monarch. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new DealsCombatDamageToAPlayerTriggeredAbility(new BecomesMonarchTargetEffect(), false, true), - MonarchIsNotSetCondition.instance, - "Whenever {this} deals combat damage to a player, if there is no monarch, that player becomes the monarch." - ).addHint(MonarchHint.instance)); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new BecomesMonarchTargetEffect().setText("that player becomes the monarch"), false, true + ).withInterveningIf(MonarchIsNotSetCondition.instance).addHint(MonarchHint.instance)); // Whenever you become the monarch, convert Starscream. this.addAbility(new BecomesMonarchSourceControllerTriggeredAbility( - new TransformSourceEffect().setText("convert {this}") + new TransformSourceEffect().setText("convert {this}") )); } diff --git a/Mage.Sets/src/mage/cards/s/StarseerMentor.java b/Mage.Sets/src/mage/cards/s/StarseerMentor.java index 5e4c4bb4674..a176893417c 100644 --- a/Mage.Sets/src/mage/cards/s/StarseerMentor.java +++ b/Mage.Sets/src/mage/cards/s/StarseerMentor.java @@ -2,16 +2,15 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.common.YouGainedOrLostLifeCondition; import mage.abilities.costs.OrCost; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DoUnlessTargetPlayerOrTargetsControllerPaysEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -42,24 +41,19 @@ public final class StarseerMentor extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // At the beginning of your end step, if you gained or lost life this turn, target opponent loses 3 life unless they sacrifice a nonland permanent or discard a card. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - new DoUnlessTargetPlayerOrTargetsControllerPaysEffect( - new LoseLifeTargetEffect(3), - new OrCost( - "sacrifice a nonland permanent or discard a card", - new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_NON_LAND), - new DiscardCardCost() - ), - "Sacrifice a nonland permanent or discard a card to prevent losing 3 life?" - ) - ), YouGainedOrLostLifeCondition.instance, "At the beginning of your end step, if you gained or lost life this turn, " - + "target opponent loses 3 life unless they sacrifice a nonland permanent of their choice or discard a card." - ); + Ability ability = new BeginningOfEndStepTriggeredAbility( + new DoUnlessTargetPlayerOrTargetsControllerPaysEffect( + new LoseLifeTargetEffect(3), + new OrCost( + "sacrifice a nonland permanent or discard a card", + new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_NON_LAND), + new DiscardCardCost() + ), + "Sacrifice a nonland permanent or discard a card to prevent losing 3 life?" + ).setText("target opponent loses 3 life unless they sacrifice a nonland permanent of their choice or discard a card") + ).withInterveningIf(YouGainedOrLostLifeCondition.instance); ability.addTarget(new TargetOpponent()); - ability.addWatcher(new PlayerGainedLifeWatcher()); - ability.addHint(YouGainedOrLostLifeCondition.getHint()); - this.addAbility(ability); + this.addAbility(ability.addHint(YouGainedOrLostLifeCondition.getHint()), new PlayerGainedLifeWatcher()); } private StarseerMentor(final StarseerMentor card) { diff --git a/Mage.Sets/src/mage/cards/s/StartFinish.java b/Mage.Sets/src/mage/cards/s/StartFinish.java index 1a80fefa46e..85ea7fd1390 100644 --- a/Mage.Sets/src/mage/cards/s/StartFinish.java +++ b/Mage.Sets/src/mage/cards/s/StartFinish.java @@ -14,6 +14,7 @@ import mage.constants.SpellAbilityType; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.game.permanent.token.WarriorVigilantToken; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; @@ -37,7 +38,7 @@ public final class StartFinish extends SplitCard { // As an additional cost to cast Finish, sacrifice a creature. Destroy target creature. getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); getRightHalfCard().getSpellAbility().addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE)); - getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature (to destoy)"))); + getRightHalfCard().getSpellAbility().addTarget(new TargetPermanent(new FilterCreaturePermanent("creature (to destoy)"))); getRightHalfCard().getSpellAbility().addEffect(new DestroyTargetEffect("Destroy target creature")); } diff --git a/Mage.Sets/src/mage/cards/s/StarvingRevenant.java b/Mage.Sets/src/mage/cards/s/StarvingRevenant.java index 8d0a80c749d..1479337add8 100644 --- a/Mage.Sets/src/mage/cards/s/StarvingRevenant.java +++ b/Mage.Sets/src/mage/cards/s/StarvingRevenant.java @@ -5,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.common.DrawCardControllerTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DescendCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; @@ -38,13 +37,8 @@ public final class StarvingRevenant extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new StarvingRevenantEffect())); // Descend 8 -- Whenever you draw a card, if there are eight or more permanent cards in your graveyard, target opponent loses 1 life and you gain 1 life. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new DrawCardControllerTriggeredAbility(new LoseLifeTargetEffect(1), false), - DescendCondition.EIGHT, "Whenever you draw a card, " - + "if there are eight or more permanent cards in your graveyard, " - + "target opponent loses 1 life and you gain 1 life." - ); - ability.addEffect(new GainLifeEffect(1)); + Ability ability = new DrawCardControllerTriggeredAbility(new LoseLifeTargetEffect(1), false).withInterveningIf(DescendCondition.EIGHT); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); ability.addTarget(new TargetOpponent()); this.addAbility(ability.addHint(DescendCondition.getHint()).setAbilityWord(AbilityWord.DESCEND_8)); } @@ -90,4 +84,4 @@ class StarvingRevenantEffect extends OneShotEffect { return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/StaticOrb.java b/Mage.Sets/src/mage/cards/s/StaticOrb.java index f5027681dd5..c9072dd1181 100644 --- a/Mage.Sets/src/mage/cards/s/StaticOrb.java +++ b/Mage.Sets/src/mage/cards/s/StaticOrb.java @@ -1,7 +1,6 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.RestrictionUntapNotMoreThanEffect; @@ -9,12 +8,13 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** * * @author LevelX2 @@ -45,7 +45,7 @@ class StaticOrbEffect extends RestrictionUntapNotMoreThanEffect { public StaticOrbEffect() { super(Duration.WhileOnBattlefield, 2, filter); - staticText = "As long as Static Orb is untapped, players can't untap more than two permanents during their untap steps"; + staticText = "As long as {this} is untapped, players can't untap more than two permanents during their untap steps"; } private StaticOrbEffect(final StaticOrbEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/SteadfastUnicorn.java b/Mage.Sets/src/mage/cards/s/SteadfastUnicorn.java index bd89a9d7841..fbc5c6931ec 100644 --- a/Mage.Sets/src/mage/cards/s/SteadfastUnicorn.java +++ b/Mage.Sets/src/mage/cards/s/SteadfastUnicorn.java @@ -14,7 +14,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; import java.util.UUID; @@ -33,8 +32,9 @@ public final class SteadfastUnicorn extends CardImpl { // {3}{W}: Creatures you control get +1/+1 and gain vigilance until end of turn. Activate only during your turn. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.EndOfTurn) - .setText("creatures you control get +1/+1"), new ManaCostsImpl<>("{3}{W}"), MyTurnCondition.instance + new BoostControlledEffect(1, 1, Duration.EndOfTurn) + .setText("creatures you control get +1/+1"), + new ManaCostsImpl<>("{3}{W}"), MyTurnCondition.instance ); ability.addEffect(new GainAbilityControlledEffect( VigilanceAbility.getInstance(), Duration.EndOfTurn, diff --git a/Mage.Sets/src/mage/cards/s/StealStrength.java b/Mage.Sets/src/mage/cards/s/StealStrength.java index 9597f4fbbf6..0797db89e1d 100644 --- a/Mage.Sets/src/mage/cards/s/StealStrength.java +++ b/Mage.Sets/src/mage/cards/s/StealStrength.java @@ -1,44 +1,29 @@ - package mage.cards.s; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.other.AnotherTargetPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; /** - * * @author fireshoes */ public final class StealStrength extends CardImpl { public StealStrength(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); // Target creature gets +1/+1 until end of turn. Another target creature gets -1/-1 until end of turn. - this.getSpellAbility().addEffect(new StealStrengthEffect()); - - FilterCreaturePermanent filter1 = new FilterCreaturePermanent("creature (gets +1/+1 until end of turn)"); - TargetCreaturePermanent target1 = new TargetCreaturePermanent(filter1); - target1.setTargetTag(1); - this.getSpellAbility().addTarget(target1); - - FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another creature (gets -1/-1 until end of turn)"); - filter2.add(new AnotherTargetPredicate(2)); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter2); - target2.setTargetTag(2); - this.getSpellAbility().addTarget(target2); + this.getSpellAbility().addEffect(new BoostTargetEffect(1, 1)); + this.getSpellAbility().addEffect(new BoostTargetEffect(-1, -1).setTargetPointer(new SecondTargetPointer()).setText("Another target creature gets -1/-1 until end of turn")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("+1/+1").setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2).withChooseHint("-1/-1").setTargetTag(2)); } private StealStrength(final StealStrength card) { @@ -50,35 +35,3 @@ public final class StealStrength extends CardImpl { return new StealStrength(this); } } - -class StealStrengthEffect extends ContinuousEffectImpl { - - StealStrengthEffect() { - super(Duration.EndOfTurn, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.BoostCreature); - this.staticText = "Target creature gets +1/+1 until end of turn. Another target creature gets -1/-1 until end of turn"; - } - - private StealStrengthEffect(final StealStrengthEffect effect) { - super(effect); - } - - @Override - public StealStrengthEffect copy() { - return new StealStrengthEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent != null) { - permanent.addPower(1); - permanent.addToughness(1); - } - permanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - if (permanent != null) { - permanent.addPower(-1); - permanent.addToughness(-1); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SteamCatapult.java b/Mage.Sets/src/mage/cards/s/SteamCatapult.java index f9a2a9244fa..e06801fbc1e 100644 --- a/Mage.Sets/src/mage/cards/s/SteamCatapult.java +++ b/Mage.Sets/src/mage/cards/s/SteamCatapult.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -12,17 +10,18 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class SteamCatapult extends CardImpl { - + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { @@ -30,16 +29,17 @@ public final class SteamCatapult extends CardImpl { } public SteamCatapult(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); this.power = new MageInt(2); this.toughness = new MageInt(3); // {tap}: Destroy target tapped creature. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new DestroyTargetEffect(), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); - ability.addTarget(new TargetCreaturePermanent(filter)); + Ability ability = new ActivateIfConditionActivatedAbility( + new DestroyTargetEffect(), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance + ); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SteamcoreWeird.java b/Mage.Sets/src/mage/cards/s/SteamcoreWeird.java index 852c4980643..b11ced49a24 100644 --- a/Mage.Sets/src/mage/cards/s/SteamcoreWeird.java +++ b/Mage.Sets/src/mage/cards/s/SteamcoreWeird.java @@ -1,37 +1,34 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.ManaWasSpentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.ColoredManaSymbol; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author FenrisulfrX */ public final class SteamcoreWeird extends CardImpl { public SteamcoreWeird(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); this.subtype.add(SubType.WEIRD); this.power = new MageInt(1); this.toughness = new MageInt(3); // When Steamcore Weird enters the battlefield, if {R} was spent to cast Steamcore Weird, it deals 2 damage to any target. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2, "it")); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2, "it")) + .withInterveningIf(ManaWasSpentCondition.RED); ability.addTarget(new TargetAnyTarget()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, ManaWasSpentCondition.RED, - "When {this} enters, if {R} was spent to cast it, it deals 2 damage to any target.")); + this.addAbility(ability); } private SteamcoreWeird(final SteamcoreWeird card) { diff --git a/Mage.Sets/src/mage/cards/s/SteelclawLance.java b/Mage.Sets/src/mage/cards/s/SteelclawLance.java index 733f9a55e64..b80874c09d7 100644 --- a/Mage.Sets/src/mage/cards/s/SteelclawLance.java +++ b/Mage.Sets/src/mage/cards/s/SteelclawLance.java @@ -9,17 +9,18 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; -import mage.target.common.TargetControlledCreaturePermanent; /** * @author TheElk801 */ public final class SteelclawLance extends CardImpl { - private static final FilterControlledCreaturePermanent filter + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(SubType.KNIGHT, "Knight"); public SteelclawLance(UUID ownerId, CardSetInfo setInfo) { @@ -31,10 +32,10 @@ public final class SteelclawLance extends CardImpl { this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(2, 2))); // Equip Knight {1} - this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(1), new TargetControlledCreaturePermanent(filter), false)); + this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(1), new TargetPermanent(filter), false)); // Equip {3} - this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(3), new TargetControlledCreaturePermanent(), false)); + this.addAbility(new EquipAbility(3, false)); } diff --git a/Mage.Sets/src/mage/cards/s/StellaLeeWildCard.java b/Mage.Sets/src/mage/cards/s/StellaLeeWildCard.java index d64bc90e05f..a3fd08dd33b 100644 --- a/Mage.Sets/src/mage/cards/s/StellaLeeWildCard.java +++ b/Mage.Sets/src/mage/cards/s/StellaLeeWildCard.java @@ -47,8 +47,7 @@ public final class StellaLeeWildCard extends CardImpl { // {T}: Copy target instant or sorcery spell you control. You may choose new targets for the copy. Activate only if you've cast three or more spells this turn. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new CopyTargetStackObjectEffect(), - new TapSourceCost(), StellaLeeWildCardCondition.instance + new CopyTargetStackObjectEffect(), new TapSourceCost(), StellaLeeWildCardCondition.instance ); ability.addTarget(new TargetSpell(filter)); this.addAbility(ability.addHint(StormAbility.getHint())); diff --git a/Mage.Sets/src/mage/cards/s/SteppeGlider.java b/Mage.Sets/src/mage/cards/s/SteppeGlider.java index 5b01012e024..7b1bd660799 100644 --- a/Mage.Sets/src/mage/cards/s/SteppeGlider.java +++ b/Mage.Sets/src/mage/cards/s/SteppeGlider.java @@ -17,8 +17,11 @@ import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_A_CREATURE_P1P1; + /** * * @author fireshoes @@ -44,7 +47,7 @@ public final class SteppeGlider extends CardImpl { effect = new GainAbilityTargetEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn); effect.setText("and vigilance until end of turn"); ability.addEffect(effect); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_A_CREATURE_P1P1)); + ability.addTarget(new TargetPermanent(FILTER_A_CREATURE_P1P1)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SternMarshal.java b/Mage.Sets/src/mage/cards/s/SternMarshal.java index 56900530e2f..a924dfc0874 100644 --- a/Mage.Sets/src/mage/cards/s/SternMarshal.java +++ b/Mage.Sets/src/mage/cards/s/SternMarshal.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -11,27 +9,29 @@ import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class SternMarshal extends CardImpl { public SternMarshal(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); this.power = new MageInt(2); this.toughness = new MageInt(2); // {tap}: Target creature gets +2/+2 until end of turn. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new BoostTargetEffect(2, 2, Duration.EndOfTurn), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new BoostTargetEffect(2, 2, Duration.EndOfTurn), + new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance + ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/StingerflingSpider.java b/Mage.Sets/src/mage/cards/s/StingerflingSpider.java index b0b3c981717..2e38bd05cba 100644 --- a/Mage.Sets/src/mage/cards/s/StingerflingSpider.java +++ b/Mage.Sets/src/mage/cards/s/StingerflingSpider.java @@ -15,6 +15,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -36,7 +37,7 @@ public final class StingerflingSpider extends CardImpl { this.toughness = new MageInt(5); this.addAbility(ReachAbility.getInstance()); Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), true); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/StingingCaveCrawler.java b/Mage.Sets/src/mage/cards/s/StingingCaveCrawler.java index b24f63945ed..03aa6835d48 100644 --- a/Mage.Sets/src/mage/cards/s/StingingCaveCrawler.java +++ b/Mage.Sets/src/mage/cards/s/StingingCaveCrawler.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.DescendCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.keyword.DeathtouchAbility; @@ -33,12 +32,8 @@ public final class StingingCaveCrawler extends CardImpl { this.addAbility(DeathtouchAbility.getInstance()); // Descend 4 -- Whenever Stinging Cave Crawler attacks, if there are four or more permanent cards in your graveyard, you draw a card and you lose 1 life. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new DrawCardSourceControllerEffect(1)), - DescendCondition.FOUR, "Whenever {this} attacks, if there are four " + - "or more permanent cards in your graveyard, you draw a card and you lose 1 life." - ); - ability.addEffect(new LoseLifeSourceControllerEffect(1)); + Ability ability = new AttacksTriggeredAbility(new DrawCardSourceControllerEffect(1, true)).withInterveningIf(DescendCondition.FOUR); + ability.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and")); this.addAbility(ability.setAbilityWord(AbilityWord.DESCEND_4).addHint(DescendCondition.getHint())); } diff --git a/Mage.Sets/src/mage/cards/s/StingingShot.java b/Mage.Sets/src/mage/cards/s/StingingShot.java index 138a2d01de1..b3fb6f6d770 100644 --- a/Mage.Sets/src/mage/cards/s/StingingShot.java +++ b/Mage.Sets/src/mage/cards/s/StingingShot.java @@ -12,6 +12,7 @@ import mage.constants.CardType; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -30,7 +31,7 @@ public final class StingingShot extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}"); // Put three -1/-1 counters on target creature with flying. - getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + getSpellAbility().addTarget(new TargetPermanent(filter)); getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.M1M1.createInstance(3))); // Cycling {2} diff --git a/Mage.Sets/src/mage/cards/s/Stingscourger.java b/Mage.Sets/src/mage/cards/s/Stingscourger.java index ed9b214ad50..f9cefbe112d 100644 --- a/Mage.Sets/src/mage/cards/s/Stingscourger.java +++ b/Mage.Sets/src/mage/cards/s/Stingscourger.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -11,17 +9,17 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.StaticFilters; -import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; /** - * * @author jonubuu */ public final class Stingscourger extends CardImpl { public Stingscourger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); this.subtype.add(SubType.GOBLIN); this.subtype.add(SubType.WARRIOR); @@ -30,10 +28,10 @@ public final class Stingscourger extends CardImpl { // Echo {3}{R} this.addAbility(new EchoAbility("{3}{R}")); + // When Stingscourger enters the battlefield, return target creature an opponent controls to its owner's hand. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()); - TargetCreaturePermanent target = new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE); - ability.addTarget(target); + ability.addTarget(new TargetOpponentsCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/StitchedMangler.java b/Mage.Sets/src/mage/cards/s/StitchedMangler.java index 0487d1754ee..4d6a9a94b1d 100644 --- a/Mage.Sets/src/mage/cards/s/StitchedMangler.java +++ b/Mage.Sets/src/mage/cards/s/StitchedMangler.java @@ -13,8 +13,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -36,7 +39,7 @@ public final class StitchedMangler extends CardImpl { Effect effect = new DontUntapInControllersNextUntapStepTargetEffect(); effect.setText("That creature doesn't untap during its controller's next untap step"); ability.addEffect(effect); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/StoneCatapult.java b/Mage.Sets/src/mage/cards/s/StoneCatapult.java index b0ba155ccf9..5bcca38c131 100644 --- a/Mage.Sets/src/mage/cards/s/StoneCatapult.java +++ b/Mage.Sets/src/mage/cards/s/StoneCatapult.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -13,20 +11,21 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author fireshoes */ public final class StoneCatapult extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped nonblack creature"); + + private static final FilterPermanent filter = new FilterCreaturePermanent("tapped nonblack creature"); static { filter.add(TappedPredicate.TAPPED); @@ -34,16 +33,17 @@ public final class StoneCatapult extends CardImpl { } public StoneCatapult(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); this.power = new MageInt(1); this.toughness = new MageInt(2); // {tap}: Destroy target tapped nonblack creature. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new DestroyTargetEffect(), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); - ability.addTarget(new TargetCreaturePermanent(filter)); + Ability ability = new ActivateIfConditionActivatedAbility( + new DestroyTargetEffect(), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance + ); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/StoneHavenPilgrim.java b/Mage.Sets/src/mage/cards/s/StoneHavenPilgrim.java index f1f2685ffb9..aa066ecc210 100644 --- a/Mage.Sets/src/mage/cards/s/StoneHavenPilgrim.java +++ b/Mage.Sets/src/mage/cards/s/StoneHavenPilgrim.java @@ -5,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.LifelinkAbility; @@ -14,7 +13,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.filter.StaticFilters; +import mage.filter.common.FilterArtifactOrEnchantmentPermanent; import java.util.UUID; @@ -23,8 +22,9 @@ import java.util.UUID; */ public final class StoneHavenPilgrim extends CardImpl { - private static final Condition condition - = new PermanentsOnTheBattlefieldCondition(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterArtifactOrEnchantmentPermanent("you control an artifact or enchantment") + ); public StoneHavenPilgrim(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); @@ -35,13 +35,12 @@ public final class StoneHavenPilgrim extends CardImpl { this.toughness = new MageInt(2); // Whenever Stone Haven Pilgrim attacks, if you control an artifact or enchantment, Stone Haven Pilgrim gets +1/+1 and gains lifelink until end of turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility( - new BoostSourceEffect(1, 1, Duration.EndOfTurn), false - ), condition, "Whenever {this} attacks, if you control an artifact or enchantment, " + - "{this} gets +1/+1 and gains lifelink until end of turn." - ); - ability.addEffect(new GainAbilitySourceEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn)); + Ability ability = new AttacksTriggeredAbility(new BoostSourceEffect( + 1, 1, Duration.EndOfTurn + ).setText("{this} gets +1/+1")).withInterveningIf(condition); + ability.addEffect(new GainAbilitySourceEffect( + LifelinkAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains lifelink until end of turn")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/StormElemental.java b/Mage.Sets/src/mage/cards/s/StormElemental.java index 41673d298e1..3f793bcb1d8 100644 --- a/Mage.Sets/src/mage/cards/s/StormElemental.java +++ b/Mage.Sets/src/mage/cards/s/StormElemental.java @@ -19,6 +19,7 @@ import mage.filter.common.FilterLandCard; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.game.Game; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -46,7 +47,7 @@ public final class StormElemental extends CardImpl { // {U}, Exile the top card of your library: Tap target creature with flying. Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new ManaCostsImpl<>("{U}")); ability.addCost(new ExileTopCardLibraryCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // {U}, Exile the top card of your library: If the exiled card is a snow land, Storm Elemental gets +1/+1 until end of turn. diff --git a/Mage.Sets/src/mage/cards/s/StormFleetArsonist.java b/Mage.Sets/src/mage/cards/s/StormFleetArsonist.java index 48ee6857076..0f9895ad186 100644 --- a/Mage.Sets/src/mage/cards/s/StormFleetArsonist.java +++ b/Mage.Sets/src/mage/cards/s/StormFleetArsonist.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.SacrificeEffect; import mage.abilities.hint.common.RaidHint; import mage.cards.CardImpl; @@ -12,7 +11,7 @@ import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.target.common.TargetOpponent; import mage.watchers.common.PlayerAttackedWatcher; @@ -32,14 +31,11 @@ public final class StormFleetArsonist extends CardImpl { this.toughness = new MageInt(4); // Raid - When Storm Fleet Arsonist enters the battlefield, if you attacked this turn, target opponent sacrifices a permanent. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new SacrificeEffect(new FilterPermanent(), 1, "Target opponent")), - RaidCondition.instance, - "When {this} enters, if you attacked this turn, target opponent sacrifices a permanent."); + Ability ability = new EntersBattlefieldTriggeredAbility( + new SacrificeEffect(StaticFilters.FILTER_PERMANENT_A, 1, "target opponent") + ).withInterveningIf(RaidCondition.instance); ability.addTarget(new TargetOpponent()); - ability.setAbilityWord(AbilityWord.RAID); - ability.addHint(RaidHint.instance); - this.addAbility(ability, new PlayerAttackedWatcher()); + this.addAbility(ability.setAbilityWord(AbilityWord.RAID).addHint(RaidHint.instance), new PlayerAttackedWatcher()); } private StormFleetArsonist(final StormFleetArsonist card) { diff --git a/Mage.Sets/src/mage/cards/s/StormFleetPyromancer.java b/Mage.Sets/src/mage/cards/s/StormFleetPyromancer.java index cc9967b7acf..8ac6ef90b68 100644 --- a/Mage.Sets/src/mage/cards/s/StormFleetPyromancer.java +++ b/Mage.Sets/src/mage/cards/s/StormFleetPyromancer.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.hint.common.RaidHint; import mage.cards.CardImpl; @@ -32,14 +31,9 @@ public final class StormFleetPyromancer extends CardImpl { this.toughness = new MageInt(2); // Raid - When Storm Fleet Pyromancer enters the battlefield, if you attacked this turn, Storm Fleet Pyromancer deals 2 damage to any target. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2)), - RaidCondition.instance, - "When {this} enters, if you attacked this turn, {this} deals 2 damage to any target."); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2)).withInterveningIf(RaidCondition.instance); ability.addTarget(new TargetAnyTarget()); - ability.setAbilityWord(AbilityWord.RAID); - ability.addHint(RaidHint.instance); - this.addAbility(ability, new PlayerAttackedWatcher()); + this.addAbility(ability.setAbilityWord(AbilityWord.RAID).addHint(RaidHint.instance), new PlayerAttackedWatcher()); } private StormFleetPyromancer(final StormFleetPyromancer card) { diff --git a/Mage.Sets/src/mage/cards/s/StormFleetSpy.java b/Mage.Sets/src/mage/cards/s/StormFleetSpy.java index cf37d6515c4..ddda8a2da29 100644 --- a/Mage.Sets/src/mage/cards/s/StormFleetSpy.java +++ b/Mage.Sets/src/mage/cards/s/StormFleetSpy.java @@ -1,10 +1,8 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.hint.common.RaidHint; import mage.cards.CardImpl; @@ -30,13 +28,8 @@ public final class StormFleetSpy extends CardImpl { this.toughness = new MageInt(2); // Raid — When this creature enters, if you attacked this turn, draw a card. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)), - RaidCondition.instance, - "When this creature enters, if you attacked this turn, draw a card."); - ability.setAbilityWord(AbilityWord.RAID); - ability.addHint(RaidHint.instance); - this.addAbility(ability, new PlayerAttackedWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .withInterveningIf(RaidCondition.instance).setAbilityWord(AbilityWord.RAID).addHint(RaidHint.instance), new PlayerAttackedWatcher()); } private StormFleetSpy(final StormFleetSpy card) { diff --git a/Mage.Sets/src/mage/cards/s/StormFront.java b/Mage.Sets/src/mage/cards/s/StormFront.java index c5eebd53499..6ab00a62498 100644 --- a/Mage.Sets/src/mage/cards/s/StormFront.java +++ b/Mage.Sets/src/mage/cards/s/StormFront.java @@ -13,6 +13,7 @@ import mage.constants.CardType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -32,7 +33,7 @@ public final class StormFront extends CardImpl { // {G}{G}: Tap target creature with flying. Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new ManaCostsImpl<>("{G}{G}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/StormTheVault.java b/Mage.Sets/src/mage/cards/s/StormTheVault.java index 11d924c3997..a76502a82c5 100644 --- a/Mage.Sets/src/mage/cards/s/StormTheVault.java +++ b/Mage.Sets/src/mage/cards/s/StormTheVault.java @@ -1,30 +1,32 @@ - package mage.cards.s; -import java.util.UUID; - -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.OneOrMoreCombatDamagePlayerTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.hint.ValueHint; +import mage.abilities.hint.common.ArtifactYouControlHint; import mage.abilities.keyword.TransformAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SuperType; -import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledArtifactPermanent; import mage.game.permanent.token.TreasureToken; +import java.util.UUID; + /** * @author LevelX2 */ public final class StormTheVault extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledArtifactPermanent("you control five or more artifacts"), ComparisonType.MORE_THAN, 4 + ); + public StormTheVault(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{R}"); @@ -37,11 +39,8 @@ public final class StormTheVault extends CardImpl { // At the beginning of your end step, if you control five or more artifacts, transform Storm the Vault. this.addAbility(new TransformAbility()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility(new TransformSourceEffect()), - new PermanentsOnTheBattlefieldCondition(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT, ComparisonType.MORE_THAN, 4), - "At the beginning of your end step, if you control five or more artifacts, transform {this}" - ).addHint(new ValueHint("Artifacts you control", new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT)))); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new TransformSourceEffect()) + .withInterveningIf(condition).addHint(ArtifactYouControlHint.instance)); } private StormTheVault(final StormTheVault card) { diff --git a/Mage.Sets/src/mage/cards/s/StormchaserChimera.java b/Mage.Sets/src/mage/cards/s/StormchaserChimera.java index a8f25dec02d..fcd3024d338 100644 --- a/Mage.Sets/src/mage/cards/s/StormchaserChimera.java +++ b/Mage.Sets/src/mage/cards/s/StormchaserChimera.java @@ -1,7 +1,6 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -10,20 +9,17 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.keyword.ScryEffect; import mage.abilities.keyword.FlyingAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.cards.*; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** * * @author LevelX2 @@ -59,7 +55,7 @@ class StormchaserChimeraEffect extends OneShotEffect { StormchaserChimeraEffect() { super(Outcome.Benefit); - this.staticText = ", then reveal the top card of your library. Stormchaser Chimera gets +X/+0 until end of turn, where X is that card's mana value"; + this.staticText = ", then reveal the top card of your library. {this} gets +X/+0 until end of turn, where X is that card's mana value"; } private StormchaserChimeraEffect(final StormchaserChimeraEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/StormscapeBattlemage.java b/Mage.Sets/src/mage/cards/s/StormscapeBattlemage.java index 676e6c643ca..414424d8f18 100644 --- a/Mage.Sets/src/mage/cards/s/StormscapeBattlemage.java +++ b/Mage.Sets/src/mage/cards/s/StormscapeBattlemage.java @@ -1,11 +1,10 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.KickedCostCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.keyword.KickerAbility; @@ -14,16 +13,20 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class StormscapeBattlemage extends CardImpl { + private static final Condition condition = new KickedCostCondition("{W}"); + private static final Condition condition2 = new KickedCostCondition("{2}{B}"); + public StormscapeBattlemage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); this.subtype.add(SubType.METATHRAN); this.subtype.add(SubType.WIZARD); @@ -36,17 +39,14 @@ public final class StormscapeBattlemage extends CardImpl { this.addAbility(kickerAbility); // When Stormscape Battlemage enters the battlefield, if it was kicked with its {W} kicker, you gain 3 life. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3),false), - new KickedCostCondition("{W}"), - "When Stormscape Battlemage enters the battlefield, if it was kicked with its {W} kicker, you gain 3 life.")); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3)).withInterveningIf(condition)); // When Stormscape Battlemage enters the battlefield, if it was kicked with its {2}{B} kicker, destroy target nonblack creature. That creature can't be regenerated. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(true),false); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - ability, new KickedCostCondition("{2}{B}"), - "When Stormscape Battlemage enters the battlefield, if it was kicked with its {2}{B} kicker, destroy target nonblack creature. That creature can't be regenerated.")); + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect( + "destroy target nonblack creature. That creature can't be regenerated", true + )).withInterveningIf(condition2); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.addAbility(ability); } private StormscapeBattlemage(final StormscapeBattlemage card) { diff --git a/Mage.Sets/src/mage/cards/s/Storyweave.java b/Mage.Sets/src/mage/cards/s/Storyweave.java index a49c99a5b33..e69ae663f01 100644 --- a/Mage.Sets/src/mage/cards/s/Storyweave.java +++ b/Mage.Sets/src/mage/cards/s/Storyweave.java @@ -71,8 +71,8 @@ class StoryweaveReplacementEffect extends ReplacementEffectImpl { StoryweaveReplacementEffect() { super(Duration.EndOfTurn, Outcome.BoostCreature); - staticText = "The next time one or more enchantment creatures enter the battlefield " + - "under your control this turn, each enters with two additional +1/+1 counters on it"; + staticText = "The next time one or more enchantment creatures you control enter this turn, " + + "each enters with two additional +1/+1 counters on it"; } private StoryweaveReplacementEffect(final StoryweaveReplacementEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/Strafe.java b/Mage.Sets/src/mage/cards/s/Strafe.java index bb69167d509..4fdf5bd5df1 100644 --- a/Mage.Sets/src/mage/cards/s/Strafe.java +++ b/Mage.Sets/src/mage/cards/s/Strafe.java @@ -10,6 +10,7 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -30,7 +31,7 @@ public final class Strafe extends CardImpl { // Strafe deals 3 damage to target nonred creature. this.getSpellAbility().addEffect(new DamageTargetEffect(3)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private Strafe(final Strafe card) { diff --git a/Mage.Sets/src/mage/cards/s/StragoAndRelm.java b/Mage.Sets/src/mage/cards/s/StragoAndRelm.java index ef49bd3a27c..d7f26bdefe0 100644 --- a/Mage.Sets/src/mage/cards/s/StragoAndRelm.java +++ b/Mage.Sets/src/mage/cards/s/StragoAndRelm.java @@ -115,7 +115,7 @@ class StragoAndRelmEffect extends OneShotEffect { .map(Controllable::getControllerId) .map(game::getPlayer) .ifPresent(player -> CardUtil.castSpellWithAttributesForFree( - opponent, source, game, new CardsImpl(card), + player, source, game, new CardsImpl(card), StaticFilters.FILTER_CARD, StragoAndRelmTracker.instance )); return true; diff --git a/Mage.Sets/src/mage/cards/s/StranglingSoot.java b/Mage.Sets/src/mage/cards/s/StranglingSoot.java index e720e91b118..fe1f37ca4b5 100644 --- a/Mage.Sets/src/mage/cards/s/StranglingSoot.java +++ b/Mage.Sets/src/mage/cards/s/StranglingSoot.java @@ -12,6 +12,7 @@ import mage.constants.ComparisonType; import mage.constants.TimingRule; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ToughnessPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class StranglingSoot extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); // Destroy target creature with toughness 3 or less. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); // Flashback {5}{R} this.addAbility(new FlashbackAbility(this, new ManaCostsImpl<>("{5}{R}"))); diff --git a/Mage.Sets/src/mage/cards/s/StreambedAquitects.java b/Mage.Sets/src/mage/cards/s/StreambedAquitects.java index 32ba35910ea..e1f85fcb534 100644 --- a/Mage.Sets/src/mage/cards/s/StreambedAquitects.java +++ b/Mage.Sets/src/mage/cards/s/StreambedAquitects.java @@ -14,6 +14,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetLandPermanent; @@ -41,7 +42,7 @@ public final class StreambedAquitects extends CardImpl { ability.addEffect(new GainAbilityTargetEffect( new IslandwalkAbility(false), Duration.EndOfTurn ).setText("and gains islandwalk until end of turn")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // {tap}: Target land becomes an Island until end of turn. diff --git a/Mage.Sets/src/mage/cards/s/StreetSpasm.java b/Mage.Sets/src/mage/cards/s/StreetSpasm.java index 4492e3de0d0..d43add838ba 100644 --- a/Mage.Sets/src/mage/cards/s/StreetSpasm.java +++ b/Mage.Sets/src/mage/cards/s/StreetSpasm.java @@ -15,6 +15,7 @@ import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -35,7 +36,7 @@ public final class StreetSpasm extends CardImpl { // Street Spasm deals X damage to target creature without flying you don't control. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DamageTargetEffect(GetXValue.instance)); // Overload {X}{X}{R}{R} (You may cast this spell for its overload cost. If you do, change its text by replacing all instances of "target" with "each.") @@ -50,4 +51,4 @@ public final class StreetSpasm extends CardImpl { public StreetSpasm copy() { return new StreetSpasm(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/StrongTheBrutishThespian.java b/Mage.Sets/src/mage/cards/s/StrongTheBrutishThespian.java index d7c9f8849ad..0defbb6289f 100644 --- a/Mage.Sets/src/mage/cards/s/StrongTheBrutishThespian.java +++ b/Mage.Sets/src/mage/cards/s/StrongTheBrutishThespian.java @@ -19,6 +19,7 @@ import mage.game.events.GameEvent; import java.util.UUID; public class StrongTheBrutishThespian extends CardImpl { + public StrongTheBrutishThespian(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); this.addSuperType(SuperType.LEGENDARY); @@ -31,14 +32,13 @@ public class StrongTheBrutishThespian extends CardImpl { // Ward {2} this.addAbility(new WardAbility(new ManaCostsImpl<>("{2}"))); - // Enrage - Whenever strong is dealt damage, you get three rad counters and put three +1/+1 counters on Strong. + // Enrage - Whenever Strong is dealt damage, you get three rad counters and put three +1/+1 counters on Strong. Ability enrageAbility = new DealtDamageToSourceTriggeredAbility(new AddCountersPlayersEffect(CounterType.RAD.createInstance(3), TargetController.YOU), false, true); - enrageAbility.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(3)).setText("put three +1/+1 counters on Strong")); + enrageAbility.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(3)).concatBy("and")); this.addAbility(enrageAbility); // You gain life rather than lose life from radiation. - Ability healAbility = new SimpleStaticAbility(new StrongTheBrutishThespianHealEffect().setText("You gain life rather than lose life from radiation.")); - this.addAbility(healAbility); + this.addAbility(new SimpleStaticAbility(new StrongTheBrutishThespianHealEffect())); } public StrongTheBrutishThespian(StrongTheBrutishThespian card) { @@ -50,29 +50,32 @@ public class StrongTheBrutishThespian extends CardImpl { return new StrongTheBrutishThespian(this); } - class StrongTheBrutishThespianHealEffect extends ContinuousRuleModifyingEffectImpl { +} - protected StrongTheBrutishThespianHealEffect() { - super(Duration.Custom, Outcome.Benefit); - } +// TODO: It doesn't interfere with anything else yet, but this should be restructured as a replacement, not continuous rule modifying +class StrongTheBrutishThespianHealEffect extends ContinuousRuleModifyingEffectImpl { - public StrongTheBrutishThespianHealEffect(StrongTheBrutishThespianHealEffect effect) { - super(effect); - } + StrongTheBrutishThespianHealEffect() { + super(Duration.Custom, Outcome.Benefit); + staticText = "You gain life rather than lose life from radiation"; + } - @Override - public StrongTheBrutishThespianHealEffect copy() { - return new StrongTheBrutishThespianHealEffect(this); - } + private StrongTheBrutishThespianHealEffect(StrongTheBrutishThespianHealEffect effect) { + super(effect); + } - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.RADIATION_GAIN_LIFE; - } + @Override + public StrongTheBrutishThespianHealEffect copy() { + return new StrongTheBrutishThespianHealEffect(this); + } - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - return event.getPlayerId().equals(source.getControllerId()); - } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.RADIATION_GAIN_LIFE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return event.getPlayerId().equals(source.getControllerId()); } } diff --git a/Mage.Sets/src/mage/cards/s/StrongholdAssassin.java b/Mage.Sets/src/mage/cards/s/StrongholdAssassin.java index cfa0017f30c..64db08a91e8 100644 --- a/Mage.Sets/src/mage/cards/s/StrongholdAssassin.java +++ b/Mage.Sets/src/mage/cards/s/StrongholdAssassin.java @@ -14,9 +14,12 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.StaticFilters; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author LevelX2 @@ -35,7 +38,7 @@ public final class StrongholdAssassin extends CardImpl { // {tap}, Sacrifice a creature: Destroy target nonblack creature. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new TapSourceCost()); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE)); - Target target = new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK); + Target target = new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK); ability.addTarget(target); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/StruggleForSkemfar.java b/Mage.Sets/src/mage/cards/s/StruggleForSkemfar.java index 13f0055c916..37ed7ade191 100644 --- a/Mage.Sets/src/mage/cards/s/StruggleForSkemfar.java +++ b/Mage.Sets/src/mage/cards/s/StruggleForSkemfar.java @@ -8,8 +8,8 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.counters.CounterType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -28,8 +28,8 @@ public final class StruggleForSkemfar extends CardImpl { "(Each deals damage equal to its power to the other.)" )); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent( - 0, 1, StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL, false + this.getSpellAbility().addTarget(new TargetPermanent( + 0, 1, StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL )); // Foretell {G} diff --git a/Mage.Sets/src/mage/cards/s/StruggleSurvive.java b/Mage.Sets/src/mage/cards/s/StruggleSurvive.java index 8359745a101..0ae2fefafb6 100644 --- a/Mage.Sets/src/mage/cards/s/StruggleSurvive.java +++ b/Mage.Sets/src/mage/cards/s/StruggleSurvive.java @@ -1,6 +1,5 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.Effect; @@ -17,6 +16,8 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * * @author LevelX2 @@ -29,7 +30,7 @@ public final class StruggleSurvive extends SplitCard { // Struggle // Struggle deals damage to target creature equal to the number of lands you control. Effect effect = new DamageTargetEffect(new PermanentsOnBattlefieldCount(new FilterControlledLandPermanent("the number of lands you control"))); - effect.setText("Struggle deals damage to target creature equal to the number of lands you control"); + effect.setText("{this} deals damage to target creature equal to the number of lands you control"); getLeftHalfCard().getSpellAbility().addEffect(effect); getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/s/SubterraneanScout.java b/Mage.Sets/src/mage/cards/s/SubterraneanScout.java index 6e9650ec68c..f714f5c1bec 100644 --- a/Mage.Sets/src/mage/cards/s/SubterraneanScout.java +++ b/Mage.Sets/src/mage/cards/s/SubterraneanScout.java @@ -13,6 +13,7 @@ import mage.constants.SubType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -36,7 +37,7 @@ public final class SubterraneanScout extends CardImpl { // When Subterranean Scout enters the battlefield, target creature with power 2 or less can't be blocked this turn. Ability ability = new EntersBattlefieldTriggeredAbility(new CantBeBlockedTargetEffect(), false); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SulfurousBlast.java b/Mage.Sets/src/mage/cards/s/SulfurousBlast.java index c45e6aa7ae5..188707472d1 100644 --- a/Mage.Sets/src/mage/cards/s/SulfurousBlast.java +++ b/Mage.Sets/src/mage/cards/s/SulfurousBlast.java @@ -1,7 +1,6 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.condition.common.AddendumCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DamageEverythingEffect; @@ -9,6 +8,8 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import java.util.UUID; + /** * * @author fireshoes @@ -23,7 +24,7 @@ public final class SulfurousBlast extends CardImpl { new DamageEverythingEffect(3), new DamageEverythingEffect(2), AddendumCondition.instance, - "Sulfurous Blast deals 2 damage to each creature and each player. If you cast this spell during your main phase, Sulfurous Blast deals 3 damage to each creature and each player instead")); + "{this} deals 2 damage to each creature and each player. If you cast this spell during your main phase, {this} deals 3 damage to each creature and each player instead")); } private SulfurousBlast(final SulfurousBlast card) { diff --git a/Mage.Sets/src/mage/cards/s/SultaiCharm.java b/Mage.Sets/src/mage/cards/s/SultaiCharm.java index e3857574757..380c7c8377e 100644 --- a/Mage.Sets/src/mage/cards/s/SultaiCharm.java +++ b/Mage.Sets/src/mage/cards/s/SultaiCharm.java @@ -33,7 +33,7 @@ public final class SultaiCharm extends CardImpl { // Choose one - // * Destroy target monocolored creature. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); // * Destroy target artifact or enchantment. diff --git a/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java b/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java index 6c27701de1c..b31c57e3a04 100644 --- a/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java +++ b/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java @@ -2,23 +2,17 @@ package mage.cards.s; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.cards.CardsImpl; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.players.Player; -import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; import java.util.UUID; @@ -35,7 +29,10 @@ public final class SunbirdsInvocation extends CardImpl { // where X is that spell's converted mana cost. You may cast a card revealed this // way with converted mana cost X or less without paying its mana cost. Put the // rest on the bottom of your library in a random order. - this.addAbility(new SunbirdsInvocationTriggeredAbility()); + this.addAbility(new SpellCastControllerTriggeredAbility( + Zone.BATTLEFIELD, new SunbirdsInvocationEffect(), null, + false, SetTargetPointer.SPELL, Zone.HAND + )); } private SunbirdsInvocation(final SunbirdsInvocation card) { @@ -48,52 +45,14 @@ public final class SunbirdsInvocation extends CardImpl { } } -class SunbirdsInvocationTriggeredAbility extends SpellCastControllerTriggeredAbility { - - SunbirdsInvocationTriggeredAbility() { - super(new SunbirdsInvocationEffect(), false); - } - - private SunbirdsInvocationTriggeredAbility(SunbirdsInvocationTriggeredAbility ability) { - super(ability); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getPlayerId().equals(getControllerId())) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null - && spell.getFromZone() == Zone.HAND - && spell.isOwnedBy(getControllerId())) { // must be from the controller's hand - if (spell.getCard() != null) { - for (Effect effect : getEffects()) { - effect.setTargetPointer(new FixedTarget(spell.getId())); - } - return true; - } - } - } - return false; - } - - @Override - public SunbirdsInvocationTriggeredAbility copy() { - return new SunbirdsInvocationTriggeredAbility(this); - } - - @Override - public String getRule() { - return "Whenever you cast a spell from your hand, reveal the top X cards of your library, " + - "where X is that spell's mana value. You may cast a spell with mana value X or less " + - "from among cards revealed this way without paying its mana cost. " + - "Put the rest on the bottom of your library in a random order."; - } -} - class SunbirdsInvocationEffect extends OneShotEffect { SunbirdsInvocationEffect() { super(Outcome.PutCardInPlay); + setText("reveal the top X cards of your library, where X is that spell's mana value. " + + "You may cast a spell with mana value X or less " + + "from among cards revealed this way without paying its mana cost. " + + "Put the rest on the bottom of your library in a random order."); } private SunbirdsInvocationEffect(final SunbirdsInvocationEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/SundialOfTheInfinite.java b/Mage.Sets/src/mage/cards/s/SundialOfTheInfinite.java index 5fca98c8f07..7a240dcba93 100644 --- a/Mage.Sets/src/mage/cards/s/SundialOfTheInfinite.java +++ b/Mage.Sets/src/mage/cards/s/SundialOfTheInfinite.java @@ -6,11 +6,9 @@ import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.EndTurnEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import java.util.UUID; @@ -23,9 +21,10 @@ public final class SundialOfTheInfinite extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // {1}, {T}: End the turn. Activate this ability only during your turn. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new EndTurnEffect(), new GenericManaCost(1), MyTurnCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new EndTurnEffect(), new GenericManaCost(1), MyTurnCondition.instance + ); ability.addCost(new TapSourceCost()); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); } @@ -37,4 +36,4 @@ public final class SundialOfTheInfinite extends CardImpl { public SundialOfTheInfinite copy() { return new SundialOfTheInfinite(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/Sunforger.java b/Mage.Sets/src/mage/cards/s/Sunforger.java index 44d9e4d2c21..17f7c9b95a6 100644 --- a/Mage.Sets/src/mage/cards/s/Sunforger.java +++ b/Mage.Sets/src/mage/cards/s/Sunforger.java @@ -1,6 +1,5 @@ package mage.cards.s; -import java.util.UUID; import mage.ApprovingObject; import mage.ObjectColor; import mage.abilities.Ability; @@ -17,12 +16,7 @@ import mage.abilities.keyword.EquipAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicates; @@ -33,6 +27,8 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** * * @author jeffwadsworth @@ -52,7 +48,7 @@ public final class Sunforger extends CardImpl { // without paying its mana cost. Then shuffle your library. Ability ability = new SimpleActivatedAbility( new SunforgerEffect(), new ManaCostsImpl<>("{R}{W}")); - ability.addCost(new SunforgerUnattachCost(this.getName())); + ability.addCost(new SunforgerUnattachCost()); this.addAbility(ability); // Equip {3} @@ -127,8 +123,8 @@ class SunforgerEffect extends OneShotEffect { class SunforgerUnattachCost extends CostImpl { - public SunforgerUnattachCost(String name) { - this.text = "Unattach " + name; + public SunforgerUnattachCost() { + this.text = "Unattach {this}"; } private SunforgerUnattachCost(final SunforgerUnattachCost cost) { diff --git a/Mage.Sets/src/mage/cards/s/SungoldSentinel.java b/Mage.Sets/src/mage/cards/s/SungoldSentinel.java index 1951791b24f..b6d6782888b 100644 --- a/Mage.Sets/src/mage/cards/s/SungoldSentinel.java +++ b/Mage.Sets/src/mage/cards/s/SungoldSentinel.java @@ -5,7 +5,7 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; import mage.abilities.condition.common.CovenCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.combat.CantBeBlockedByAllSourceEffect; @@ -43,9 +43,8 @@ public final class SungoldSentinel extends CardImpl { this.addAbility(ability); // Coven — {1}{W}: Choose a color. Sungold Sentinel gains hexproof from that color until end of turn and can't be blocked by creatures of that color this turn. Activate only if you control three or more creatures with different powers. - this.addAbility(new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new SungoldSentinelEffect(), - new ManaCostsImpl<>("{1}{W}"), CovenCondition.instance + this.addAbility(new ActivateIfConditionActivatedAbility( + new SungoldSentinelEffect(), new ManaCostsImpl<>("{1}{W}"), CovenCondition.instance ).addHint(CovenHint.instance).setAbilityWord(AbilityWord.COVEN)); } diff --git a/Mage.Sets/src/mage/cards/s/Sunlance.java b/Mage.Sets/src/mage/cards/s/Sunlance.java index 59f69241c1f..29a371bb8a8 100644 --- a/Mage.Sets/src/mage/cards/s/Sunlance.java +++ b/Mage.Sets/src/mage/cards/s/Sunlance.java @@ -10,6 +10,7 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -30,7 +31,7 @@ public final class Sunlance extends CardImpl { // Sunlance deals 3 damage to target nonwhite creature. this.getSpellAbility().addEffect(new DamageTargetEffect(3)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private Sunlance(final Sunlance card) { diff --git a/Mage.Sets/src/mage/cards/s/SunscapeBattlemage.java b/Mage.Sets/src/mage/cards/s/SunscapeBattlemage.java index 84fde706032..17180abd35d 100644 --- a/Mage.Sets/src/mage/cards/s/SunscapeBattlemage.java +++ b/Mage.Sets/src/mage/cards/s/SunscapeBattlemage.java @@ -1,12 +1,10 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.KickedCostCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.FlyingAbility; @@ -17,21 +15,26 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author FenrisulfrX */ public final class SunscapeBattlemage extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying"); + static { filter.add(new AbilityPredicate(FlyingAbility.class)); } + private static final Condition condition = new KickedCostCondition("{1}{G}"); + private static final Condition condition2 = new KickedCostCondition("{2}{U}"); + public SunscapeBattlemage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(2); @@ -43,15 +46,12 @@ public final class SunscapeBattlemage extends CardImpl { this.addAbility(kickerAbility); // When {this} enters, if it was kicked with its {1}{G} kicker, destroy target creature with flying. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), false); - ability.addTarget(new TargetCreaturePermanent(filter)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new KickedCostCondition("{1}{G}"), - "When {this} enters, if it was kicked with its {1}{G} kicker, destroy target creature with flying.")); + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()).withInterveningIf(condition); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); // When {this} enters, if it was kicked with its {2}{U} kicker, draw two cards. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( - new DrawCardSourceControllerEffect(2)), new KickedCostCondition("{2}{U}"), - "When {this} enters, if it was kicked with its {2}{U} kicker, draw two cards.")); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(2)).withInterveningIf(condition2)); } private SunscapeBattlemage(final SunscapeBattlemage card) { diff --git a/Mage.Sets/src/mage/cards/s/SunsetSaboteur.java b/Mage.Sets/src/mage/cards/s/SunsetSaboteur.java new file mode 100644 index 00000000000..1aa86dc5258 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SunsetSaboteur.java @@ -0,0 +1,52 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.abilities.keyword.WardAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SunsetSaboteur extends CardImpl { + + public SunsetSaboteur(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(4); + this.toughness = new MageInt(1); + + // Menace + this.addAbility(new MenaceAbility()); + + // Ward--Discard a card. + this.addAbility(new WardAbility(new DiscardCardCost())); + + // Whenever this creature attacks, put a +1/+1 counter on target creature an opponent controls. + Ability ability = new AttacksTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + } + + private SunsetSaboteur(final SunsetSaboteur card) { + super(card); + } + + @Override + public SunsetSaboteur copy() { + return new SunsetSaboteur(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SunspireGatekeepers.java b/Mage.Sets/src/mage/cards/s/SunspireGatekeepers.java index 991b66ad310..6b31290ab33 100644 --- a/Mage.Sets/src/mage/cards/s/SunspireGatekeepers.java +++ b/Mage.Sets/src/mage/cards/s/SunspireGatekeepers.java @@ -2,17 +2,13 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.YouControlTwoOrMoreGatesCondition; import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.common.GatesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.filter.common.FilterControlledPermanent; import mage.game.permanent.token.KnightToken; import java.util.UUID; @@ -20,18 +16,8 @@ import java.util.UUID; /** * @author LevelX2 */ - - public final class SunspireGatekeepers extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent(); - - static { - filter.add(SubType.GATE.getPredicate()); - } - - private static final Condition gatesCondition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); - public SunspireGatekeepers(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.subtype.add(SubType.HUMAN); @@ -41,11 +27,8 @@ public final class SunspireGatekeepers extends CardImpl { this.toughness = new MageInt(4); // When Sunspire Gatekeepers enter the battlefield, if you control two or more Gates, create a 2/2 white Knight creature token with vigilance. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new KnightToken())), - gatesCondition, - "When {this} enters, if you control two or more Gates, create a 2/2 white Knight creature token with vigilance.") - .addHint(new ConditionHint(gatesCondition, "you control two or more Gates"))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new KnightToken())) + .withInterveningIf(YouControlTwoOrMoreGatesCondition.instance).addHint(GatesYouControlHint.instance)); } private SunspireGatekeepers(final SunspireGatekeepers card) { diff --git a/Mage.Sets/src/mage/cards/s/SunstrikeLegionnaire.java b/Mage.Sets/src/mage/cards/s/SunstrikeLegionnaire.java index 007dad01b53..b076bf3dc5a 100644 --- a/Mage.Sets/src/mage/cards/s/SunstrikeLegionnaire.java +++ b/Mage.Sets/src/mage/cards/s/SunstrikeLegionnaire.java @@ -20,6 +20,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -49,7 +50,7 @@ public final class SunstrikeLegionnaire extends CardImpl { this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new UntapSourceEffect(), untapFilter, false)); // {tap}: Tap target creature with converted mana cost 3 or less. Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(tapFilter)); + ability.addTarget(new TargetPermanent(tapFilter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SuperState.java b/Mage.Sets/src/mage/cards/s/SuperState.java new file mode 100644 index 00000000000..54c74486952 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SuperState.java @@ -0,0 +1,100 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessAttachedEffect; +import mage.abilities.keyword.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SuperState extends CardImpl { + + public SuperState(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{7}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.AURA); + + // Enchant creature you control + TargetPermanent auraTarget = new TargetControlledCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget)); + + // Enchanted creature has base power and toughness 9/9 and has flying, first strike, trample, and haste. + Ability ability = new SimpleStaticAbility(new SetBasePowerToughnessAttachedEffect(9, 9, AttachmentType.AURA)); + ability.addEffect(new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA).setText("and has flying")); + ability.addEffect(new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.AURA).setText(", first strike")); + ability.addEffect(new GainAbilityAttachedEffect(TrampleAbility.getInstance(), AttachmentType.AURA).setText(", trample")); + ability.addEffect(new GainAbilityAttachedEffect(HasteAbility.getInstance(), AttachmentType.AURA).setText(", and haste")); + this.addAbility(ability); + + // Whenever enchanted creature deals combat damage to an opponent, it deals that much damage to each other opponent. + this.addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility( + new SuperStateEffect(), "enchanted creature", false, + true, true, TargetController.OPPONENT + )); + } + + private SuperState(final SuperState card) { + super(card); + } + + @Override + public SuperState copy() { + return new SuperState(this); + } +} + +class SuperStateEffect extends OneShotEffect { + + SuperStateEffect() { + super(Outcome.Benefit); + staticText = "it deals that much damage to each other opponent"; + } + + private SuperStateEffect(final SuperStateEffect effect) { + super(effect); + } + + @Override + public SuperStateEffect copy() { + return new SuperStateEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + UUID permanentId = Optional + .ofNullable(source.getSourcePermanentOrLKI(game)) + .map(Permanent::getAttachedTo) + .orElse(null); + int damage = SavedDamageValue.MUCH.calculate(game, source, this); + if (permanentId == null || damage < 1) { + return false; + } + UUID playerId = getTargetPointer().getFirst(game, source); + for (UUID opponentId : game.getOpponents(source.getControllerId())) { + Optional.ofNullable(opponentId) + .filter(uuid -> !uuid.equals(playerId)) + .map(game::getPlayer) + .ifPresent(player -> player.damage(damage, permanentId, source, game)); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SupplyCaravan.java b/Mage.Sets/src/mage/cards/s/SupplyCaravan.java index 432f671342a..d6f488d3d18 100644 --- a/Mage.Sets/src/mage/cards/s/SupplyCaravan.java +++ b/Mage.Sets/src/mage/cards/s/SupplyCaravan.java @@ -1,15 +1,15 @@ - package mage.cards.s; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.permanent.token.WarriorVigilantToken; @@ -17,17 +17,18 @@ import mage.game.permanent.token.WarriorVigilantToken; import java.util.UUID; /** - * * @author fireshoes */ public final class SupplyCaravan extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a tapped creature"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("you control a tapped creature"); static { filter.add(TappedPredicate.TAPPED); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + public SupplyCaravan(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); @@ -36,9 +37,7 @@ public final class SupplyCaravan extends CardImpl { this.toughness = new MageInt(5); // When Supply Caravan enters the battlefield, if you control a tapped creature, create a 1/1 white Warrior creature token with vigilance. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new WarriorVigilantToken())), - new PermanentsOnTheBattlefieldCondition(filter), - "When {this} enters, if you control a tapped creature, create a 1/1 white Warrior creature token with vigilance.")); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new WarriorVigilantToken())).withInterveningIf(condition)); } private SupplyCaravan(final SupplyCaravan card) { diff --git a/Mage.Sets/src/mage/cards/s/SupremeLeaderSnoke.java b/Mage.Sets/src/mage/cards/s/SupremeLeaderSnoke.java index a827ad49a06..c58a477800a 100644 --- a/Mage.Sets/src/mage/cards/s/SupremeLeaderSnoke.java +++ b/Mage.Sets/src/mage/cards/s/SupremeLeaderSnoke.java @@ -23,6 +23,7 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.XManaValueTargetAdjuster; import mage.watchers.Watcher; @@ -31,6 +32,8 @@ import java.util.HashMap; import java.util.Map; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE; + /** * @author NinthWorld */ @@ -59,7 +62,7 @@ public final class SupremeLeaderSnoke extends CardImpl { ability3.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield).setText("It gains haste")); ability3.addEffect(new GainAbilityTargetEffect(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new SacrificeSourceEffect()), Duration.WhileOnBattlefield) .setText("Sacrifice that creature at the beginning of the next end step")); - ability3.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE)); + ability3.addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE)); ability3.setTargetAdjuster(new XManaValueTargetAdjuster()); this.addAbility(ability3); } diff --git a/Mage.Sets/src/mage/cards/s/SurgeEngine.java b/Mage.Sets/src/mage/cards/s/SurgeEngine.java index 0e525fa1cf4..37713904f21 100644 --- a/Mage.Sets/src/mage/cards/s/SurgeEngine.java +++ b/Mage.Sets/src/mage/cards/s/SurgeEngine.java @@ -17,10 +17,12 @@ import mage.abilities.keyword.CantBeBlockedSourceAbility; import mage.abilities.keyword.DefenderAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; import mage.game.Game; -import java.util.Objects; import java.util.Optional; import java.util.UUID; @@ -50,7 +52,7 @@ public final class SurgeEngine extends CardImpl { // {2}{U}: Surge Engine becomes blue and has base power and toughness 5/4. Activate only if Surge Engine doesn't have defender. ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new BecomesColorSourceEffect(ObjectColor.BLUE, Duration.Custom), + new BecomesColorSourceEffect(ObjectColor.BLUE, Duration.Custom), new ManaCostsImpl<>("{2}{U}"), SurgeEngineCondition.instance ); ability.addEffect(new SetBasePowerToughnessSourceEffect( @@ -85,7 +87,7 @@ enum SurgeEngineCondition implements Condition { @Override public String toString() { - return "if {this} doesn't have defender"; + return "{this} doesn't have defender"; } } diff --git a/Mage.Sets/src/mage/cards/s/SurgeOfRighteousness.java b/Mage.Sets/src/mage/cards/s/SurgeOfRighteousness.java index b5e8abf1f44..d6d9f80a58b 100644 --- a/Mage.Sets/src/mage/cards/s/SurgeOfRighteousness.java +++ b/Mage.Sets/src/mage/cards/s/SurgeOfRighteousness.java @@ -12,6 +12,7 @@ import mage.filter.common.FilterAttackingOrBlockingCreature; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -32,7 +33,7 @@ public final class SurgeOfRighteousness extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}"); // Destroy target black or red creature that's attacking or blocking. You gain 2 life. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addEffect(new GainLifeEffect(2)); } diff --git a/Mage.Sets/src/mage/cards/s/SurrakElusiveHunter.java b/Mage.Sets/src/mage/cards/s/SurrakElusiveHunter.java index 074aa4a8807..4b94ef71e87 100644 --- a/Mage.Sets/src/mage/cards/s/SurrakElusiveHunter.java +++ b/Mage.Sets/src/mage/cards/s/SurrakElusiveHunter.java @@ -16,7 +16,6 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.game.stack.StackObject; -import mage.util.CardUtil; import java.util.UUID; @@ -90,7 +89,7 @@ class SurrakElusiveHunterTriggeredAbility extends TriggeredAbilityImpl { if (!checkTargeted(event.getTargetId(), game)) { return false; } - StackObject targetingObject = CardUtil.findTargetingStackObject(this.getId().toString(), event, game); + StackObject targetingObject = game.findTargetingStackObject(this.getId().toString(), event); return targetingObject != null && game.getOpponents(getControllerId()).contains(targetingObject.getControllerId()); } } diff --git a/Mage.Sets/src/mage/cards/s/SurrakTheHuntCaller.java b/Mage.Sets/src/mage/cards/s/SurrakTheHuntCaller.java index 1a604ab6d66..2b849e7690f 100644 --- a/Mage.Sets/src/mage/cards/s/SurrakTheHuntCaller.java +++ b/Mage.Sets/src/mage/cards/s/SurrakTheHuntCaller.java @@ -1,30 +1,25 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.common.FormidableCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.HasteAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.SuperType; +import mage.constants.*; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class SurrakTheHuntCaller extends CardImpl { public SurrakTheHuntCaller(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WARRIOR); @@ -32,12 +27,11 @@ public final class SurrakTheHuntCaller extends CardImpl { this.toughness = new MageInt(4); // Formidable — At the beginning of combat on your turn, if creatures you control have total power 8 or greater, target creature you control gains haste until end of turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn)), - FormidableCondition.instance, - "Formidable — At the beginning of combat on your turn, if creatures you control have total power 8 or greater, target creature you control gains haste until end of turn."); + Ability ability = new BeginningOfCombatTriggeredAbility(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + )).withInterveningIf(FormidableCondition.instance); ability.addTarget(new TargetControlledCreaturePermanent()); - this.addAbility(ability); + this.addAbility(ability.setAbilityWord(AbilityWord.FORMIDABLE)); } private SurrakTheHuntCaller(final SurrakTheHuntCaller card) { diff --git a/Mage.Sets/src/mage/cards/s/SurrakarBanisher.java b/Mage.Sets/src/mage/cards/s/SurrakarBanisher.java index 0b049c9f53e..b4d473462b8 100644 --- a/Mage.Sets/src/mage/cards/s/SurrakarBanisher.java +++ b/Mage.Sets/src/mage/cards/s/SurrakarBanisher.java @@ -12,6 +12,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -34,7 +35,7 @@ public final class SurrakarBanisher extends CardImpl { this.toughness = new MageInt(3); Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SvyelunitePriest.java b/Mage.Sets/src/mage/cards/s/SvyelunitePriest.java index 8aa108fdba3..0084ae13ebd 100644 --- a/Mage.Sets/src/mage/cards/s/SvyelunitePriest.java +++ b/Mage.Sets/src/mage/cards/s/SvyelunitePriest.java @@ -1,40 +1,40 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.ShroudAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.PhaseStep; -import mage.constants.Zone; +import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class SvyelunitePriest extends CardImpl { public SvyelunitePriest(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.subtype.add(SubType.MERFOLK); this.subtype.add(SubType.CLERIC); this.power = new MageInt(1); this.toughness = new MageInt(1); // {U}{U}, {tap}: Target creature gains shroud until end of turn. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new GainAbilityTargetEffect(ShroudAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{U}{U}"), - new IsStepCondition(PhaseStep.UPKEEP), null); + Ability ability = new ActivateIfConditionActivatedAbility( + new GainAbilityTargetEffect( + ShroudAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl<>("{U}{U}"), IsStepCondition.getMyUpkeep() + ); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/Swarmyard.java b/Mage.Sets/src/mage/cards/s/Swarmyard.java index b1833ba27e9..575fba873aa 100644 --- a/Mage.Sets/src/mage/cards/s/Swarmyard.java +++ b/Mage.Sets/src/mage/cards/s/Swarmyard.java @@ -14,6 +14,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -41,7 +42,7 @@ public final class Swarmyard extends CardImpl { // {tap}: Regenerate target Insect, Rat, Spider, or Squirrel. Ability ability = new SimpleActivatedAbility(new RegenerateTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/Swat.java b/Mage.Sets/src/mage/cards/s/Swat.java index 336201fd61b..f7d35aed9d9 100644 --- a/Mage.Sets/src/mage/cards/s/Swat.java +++ b/Mage.Sets/src/mage/cards/s/Swat.java @@ -11,6 +11,7 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -31,7 +32,7 @@ public final class Swat extends CardImpl { // Destroy target creature with power 2 or less. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Cycling {2} this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{2}"))); } diff --git a/Mage.Sets/src/mage/cards/s/SwayOfIllusion.java b/Mage.Sets/src/mage/cards/s/SwayOfIllusion.java index e312df45a2f..d5240b2134b 100644 --- a/Mage.Sets/src/mage/cards/s/SwayOfIllusion.java +++ b/Mage.Sets/src/mage/cards/s/SwayOfIllusion.java @@ -1,19 +1,16 @@ - package mage.cards.s; -import java.util.UUID; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.BecomesColorTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class SwayOfIllusion extends CardImpl { @@ -22,10 +19,9 @@ public final class SwayOfIllusion extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Any number of target creatures become the color of your choice until end of turn. - Effect effect = new BecomesColorTargetEffect(Duration.EndOfTurn); - effect.setText("Any number of target creatures become the color of your choice until end of turn"); - this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE, StaticFilters.FILTER_PERMANENT_CREATURE, false)); + this.getSpellAbility().addEffect(new BecomesColorTargetEffect(Duration.EndOfTurn) + .setText("Any number of target creatures become the color of your choice until end of turn")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE)); // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); diff --git a/Mage.Sets/src/mage/cards/s/SwiftKick.java b/Mage.Sets/src/mage/cards/s/SwiftKick.java index d1f50d8462d..9f49a28e41f 100644 --- a/Mage.Sets/src/mage/cards/s/SwiftKick.java +++ b/Mage.Sets/src/mage/cards/s/SwiftKick.java @@ -8,11 +8,14 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author LevelX2 */ @@ -29,7 +32,7 @@ public final class SwiftKick extends CardImpl { effect = new FightTargetsEffect(); effect.setText("It fights target creature you don't control"); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); } private SwiftKick(final SwiftKick card) { diff --git a/Mage.Sets/src/mage/cards/s/SwiftReckoning.java b/Mage.Sets/src/mage/cards/s/SwiftReckoning.java index 58980f6a871..649fd935d54 100644 --- a/Mage.Sets/src/mage/cards/s/SwiftReckoning.java +++ b/Mage.Sets/src/mage/cards/s/SwiftReckoning.java @@ -13,6 +13,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -42,7 +43,7 @@ public final class SwiftReckoning extends CardImpl { // Destroy target tapped creature. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private SwiftReckoning(final SwiftReckoning card) { diff --git a/Mage.Sets/src/mage/cards/s/Switcheroo.java b/Mage.Sets/src/mage/cards/s/Switcheroo.java index 40bb2a065db..32dda7fe957 100644 --- a/Mage.Sets/src/mage/cards/s/Switcheroo.java +++ b/Mage.Sets/src/mage/cards/s/Switcheroo.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.effects.common.continuous.ExchangeControlTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -9,19 +7,20 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * @author noxx */ public final class Switcheroo extends CardImpl { - private static final String rule = "Exchange control of two target creatures"; - public Switcheroo(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{U}"); // Exchange control of two target creatures. - this.getSpellAbility().addEffect(new ExchangeControlTargetEffect(Duration.EndOfGame, rule)); + this.getSpellAbility().addEffect(new ExchangeControlTargetEffect( + Duration.EndOfGame, "exchange control of two target creatures" + )); this.getSpellAbility().addTarget(new TargetCreaturePermanent(2)); } diff --git a/Mage.Sets/src/mage/cards/s/SwoopingPteranodon.java b/Mage.Sets/src/mage/cards/s/SwoopingPteranodon.java index 488c2e5c6bd..0c6b47e941d 100644 --- a/Mage.Sets/src/mage/cards/s/SwoopingPteranodon.java +++ b/Mage.Sets/src/mage/cards/s/SwoopingPteranodon.java @@ -26,6 +26,8 @@ import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author jimga150 @@ -62,7 +64,7 @@ public final class SwoopingPteranodon extends CardImpl { ability.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn).setText("and haste until end of turn.")); ability.addEffect(new SwoopingPteranodonCreateDelayedTriggerEffect()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/SwordOfTheChosen.java b/Mage.Sets/src/mage/cards/s/SwordOfTheChosen.java index cdb30c613c3..6ae5cf22d2d 100644 --- a/Mage.Sets/src/mage/cards/s/SwordOfTheChosen.java +++ b/Mage.Sets/src/mage/cards/s/SwordOfTheChosen.java @@ -13,6 +13,7 @@ import mage.constants.Duration; import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -33,7 +34,7 @@ public final class SwordOfTheChosen extends CardImpl { // {tap}: Target legendary creature gets +2/+2 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(2, 2, Duration.EndOfTurn), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SwordOfTheMeek.java b/Mage.Sets/src/mage/cards/s/SwordOfTheMeek.java index 92f8ad6f43c..c7ef125f9ee 100644 --- a/Mage.Sets/src/mage/cards/s/SwordOfTheMeek.java +++ b/Mage.Sets/src/mage/cards/s/SwordOfTheMeek.java @@ -1,8 +1,7 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; @@ -12,20 +11,22 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.filter.predicate.mageobject.ToughnessPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SwordOfTheMeek extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a 1/1 creature"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("a 1/1 creature you control"); static { filter.add(new PowerPredicate(ComparisonType.EQUAL_TO, 1)); @@ -33,16 +34,19 @@ public final class SwordOfTheMeek extends CardImpl { } public SwordOfTheMeek(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); this.subtype.add(SubType.EQUIPMENT); // Equipped creature gets +1/+2. - this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 2, Duration.WhileOnBattlefield))); + this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 2))); + // Equip {2} this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(2), false)); + // Whenever a 1/1 creature you control enters, you may return Sword of the Meek from your graveyard to the battlefield, then attach it to that creature. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(Zone.GRAVEYARD, new SwordOfTheMeekEffect(), filter, true, SetTargetPointer.PERMANENT) - .setTriggerPhrase("Whenever a 1/1 creature enters under your control, ")); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + Zone.GRAVEYARD, new SwordOfTheMeekEffect(), filter, true, SetTargetPointer.PERMANENT + )); } private SwordOfTheMeek(final SwordOfTheMeek card) { @@ -59,7 +63,7 @@ class SwordOfTheMeekEffect extends OneShotEffect { SwordOfTheMeekEffect() { super(Outcome.Benefit); - this.staticText = "you may return {this} from your graveyard to the battlefield, then attach it to that creature"; + this.staticText = "you may return this card from your graveyard to the battlefield, then attach it to that creature"; } private SwordOfTheMeekEffect(final SwordOfTheMeekEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/Symbiosis.java b/Mage.Sets/src/mage/cards/s/Symbiosis.java index 00bbedc8898..0cd976e38b7 100644 --- a/Mage.Sets/src/mage/cards/s/Symbiosis.java +++ b/Mage.Sets/src/mage/cards/s/Symbiosis.java @@ -1,27 +1,24 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; -/** - * - * @author LoneFox +import java.util.UUID; +/** + * @author LoneFox */ public final class Symbiosis extends CardImpl { public Symbiosis(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); // Two target creatures each get +2/+2 until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2)); this.getSpellAbility().addTarget(new TargetCreaturePermanent(2)); - this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn)); } private Symbiosis(final Symbiosis card) { diff --git a/Mage.Sets/src/mage/cards/s/SymbioticDeployment.java b/Mage.Sets/src/mage/cards/s/SymbioticDeployment.java index bae31e2a3b7..81c761cebf7 100644 --- a/Mage.Sets/src/mage/cards/s/SymbioticDeployment.java +++ b/Mage.Sets/src/mage/cards/s/SymbioticDeployment.java @@ -1,43 +1,33 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.TapTargetCost; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.SkipDrawStepEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author fireshoes */ public final class SymbioticDeployment extends CardImpl { - - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); - - static { - filter.add(TappedPredicate.UNTAPPED); - } public SymbioticDeployment(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); // Skip your draw step. this.addAbility(new SimpleStaticAbility(new SkipDrawStepEffect())); - + // {1}, Tap two untapped creatures you control: Draw a card. - Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{1}")); - ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(2, 2, filter, false))); + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(1)); + ability.addCost(new TapTargetCost(2, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SymmetryMatrix.java b/Mage.Sets/src/mage/cards/s/SymmetryMatrix.java index 4d57437fbec..059d54e3a5f 100644 --- a/Mage.Sets/src/mage/cards/s/SymmetryMatrix.java +++ b/Mage.Sets/src/mage/cards/s/SymmetryMatrix.java @@ -1,6 +1,6 @@ package mage.cards.s; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -8,7 +8,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicate; import mage.game.Game; import mage.game.permanent.Permanent; @@ -20,7 +20,7 @@ import java.util.UUID; */ public final class SymmetryMatrix extends CardImpl { - private static final FilterPermanent filter = new FilterCreaturePermanent("a creature with power equal to its toughness"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("a creature you control with power equal to its toughness"); static { filter.add(SymmetryMatrixPredicate.instance); @@ -30,9 +30,9 @@ public final class SymmetryMatrix extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // Whenever a creature with power equal to its toughness you control enters, you may pay {1}. If you do, draw a card. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new DoIfCostPaid( - new DrawCardSourceControllerEffect(1), new GenericManaCost(1) - ), filter)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new GenericManaCost(1)), filter + )); } private SymmetryMatrix(final SymmetryMatrix card) { diff --git a/Mage.Sets/src/mage/cards/s/SynthInfiltrator.java b/Mage.Sets/src/mage/cards/s/SynthInfiltrator.java index 7af3c8dfa0f..a1475f4fb49 100644 --- a/Mage.Sets/src/mage/cards/s/SynthInfiltrator.java +++ b/Mage.Sets/src/mage/cards/s/SynthInfiltrator.java @@ -45,7 +45,7 @@ public final class SynthInfiltrator extends CardImpl { } }; Effect effect = new CopyPermanentEffect(StaticFilters.FILTER_PERMANENT_CREATURE, synthInfiltratorCopyApplier); - effect.setText("You may have {this} enter the battlefield as a copy of any creature on the battlefield, except it's a Synth artifact creature in addition to its other types"); + effect.setText("You may have {this} enter as a copy of any creature on the battlefield, except it's a Synth artifact creature in addition to its other types"); Ability ability = new SimpleStaticAbility(Zone.ALL, new EntersBattlefieldEffect(effect, "", true)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SyrGwynHeroOfAshvale.java b/Mage.Sets/src/mage/cards/s/SyrGwynHeroOfAshvale.java index 3af5f5c8d07..6680746e72c 100644 --- a/Mage.Sets/src/mage/cards/s/SyrGwynHeroOfAshvale.java +++ b/Mage.Sets/src/mage/cards/s/SyrGwynHeroOfAshvale.java @@ -15,10 +15,10 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.permanent.EquippedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -27,11 +27,9 @@ import java.util.UUID; */ public final class SyrGwynHeroOfAshvale extends CardImpl { - private static final FilterControlledCreaturePermanent filter + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("equipped creature you control"); private static final FilterPermanent filter2 - = new FilterControlledPermanent(SubType.EQUIPMENT); - private static final FilterControlledCreaturePermanent filter3 = new FilterControlledCreaturePermanent(SubType.KNIGHT, "Knight"); static { @@ -63,9 +61,8 @@ public final class SyrGwynHeroOfAshvale extends CardImpl { // Equipment you control have equip Knight {0}. this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( new EquipAbility( - Outcome.AddAbility, new GenericManaCost(0), - new TargetControlledCreaturePermanent(filter3) - ), Duration.WhileOnBattlefield, filter2 + Outcome.AddAbility, new GenericManaCost(0), new TargetPermanent(filter2) + ), Duration.WhileOnBattlefield, StaticFilters.FILTER_CONTROLLED_PERMANENT_EQUIPMENT ).setText("Equipment you control have equip Knight {0}."))); } diff --git a/Mage.Sets/src/mage/cards/s/SzarelGenesisShepherd.java b/Mage.Sets/src/mage/cards/s/SzarelGenesisShepherd.java new file mode 100644 index 00000000000..4783143f058 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SzarelGenesisShepherd.java @@ -0,0 +1,70 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SacrificePermanentTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerValue; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SzarelGenesisShepherd extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("another nontoken permanent"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(TokenPredicate.FALSE); + } + + public SzarelGenesisShepherd(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{R}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.INSECT); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(2); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // You may play lands from your graveyard. + this.addAbility(new SimpleStaticAbility(PlayFromGraveyardControllerEffect.playLands())); + + // Whenever you sacrifice another nontoken permanent during your turn, put a number of +1/+1 counters equal to Szarel's power on up to one other target creature. + Ability ability = new SacrificePermanentTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance(), SourcePermanentPowerValue.NOT_NEGATIVE) + .setText("put a number of +1/+1 counters equal to {this}'s power on up to one other target creature"), filter + ).withTriggerCondition(MyTurnCondition.instance); + ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + this.addAbility(ability); + } + + private SzarelGenesisShepherd(final SzarelGenesisShepherd card) { + super(card); + } + + @Override + public SzarelGenesisShepherd copy() { + return new SzarelGenesisShepherd(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TARDIS.java b/Mage.Sets/src/mage/cards/t/TARDIS.java index b4556aee1c0..62858d0ab90 100644 --- a/Mage.Sets/src/mage/cards/t/TARDIS.java +++ b/Mage.Sets/src/mage/cards/t/TARDIS.java @@ -5,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.PlaneswalkEffect; import mage.abilities.effects.common.continuous.NextSpellCastHasAbilityEffect; import mage.abilities.hint.ConditionHint; @@ -25,11 +24,12 @@ import java.util.UUID; * @author Skiwkr */ public final class TARDIS extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.TIME_LORD); - private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.TIME_LORD, "you control a Time Lord") + ); - private static final Hint hint = new ConditionHint(condition, "You control a Time Lord"); + private static final Hint hint = new ConditionHint(condition); public TARDIS(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); @@ -40,19 +40,14 @@ public final class TARDIS extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever TARDIS attacks, if you control a Time Lord, the next spell you cast this turn has cascade and you may planeswalk. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new NextSpellCastHasAbilityEffect(new CascadeAbility()), false), - new PermanentsOnTheBattlefieldCondition(filter), - "Whenever {this} attacks, if you control a Time Lord, the next spell you cast this turn has cascade and you may planeswalk."); + Ability ability = new AttacksTriggeredAbility( + new NextSpellCastHasAbilityEffect(new CascadeAbility()) + ).withInterveningIf(condition); + ability.addEffect(new PlaneswalkEffect(true).concatBy("and")); + this.addAbility(ability.addHint(hint)); - ability.addEffect(new PlaneswalkEffect(true)); - - ability.addHint(hint); - - this.addAbility(ability); // Crew 2 this.addAbility(new CrewAbility(2)); - } private TARDIS(final TARDIS card) { diff --git a/Mage.Sets/src/mage/cards/t/TIEBomber.java b/Mage.Sets/src/mage/cards/t/TIEBomber.java index 72ef2bae096..05adb874de5 100644 --- a/Mage.Sets/src/mage/cards/t/TIEBomber.java +++ b/Mage.Sets/src/mage/cards/t/TIEBomber.java @@ -1,27 +1,29 @@ package mage.cards.t; -import java.util.UUID; import mage.MageInt; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.IsPhaseCondition; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.continuous.LoseAbilitySourceEffect; import mage.abilities.keyword.SpaceflightAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.TurnPhase; -import mage.constants.Zone; + +import java.util.UUID; /** - * * @author Styxo */ public final class TIEBomber extends CardImpl { + private static final Condition condition = new IsPhaseCondition(TurnPhase.COMBAT); + public TIEBomber(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.STARSHIP); @@ -32,12 +34,10 @@ public final class TIEBomber extends CardImpl { this.addAbility(SpaceflightAbility.getInstance()); // {1}: TIE Bomber loses Spaceflight until end od turn. Activate this ability only during combat. - this.addAbility(new ConditionalActivatedAbility( - Zone.BATTLEFIELD, + this.addAbility(new ActivateIfConditionActivatedAbility( new LoseAbilitySourceEffect(SpaceflightAbility.getInstance(), Duration.EndOfTurn), - new GenericManaCost(1), - new IsPhaseCondition(TurnPhase.COMBAT), - "{1}: {this} loses Spaceflight until end od turn. Activate only during combat.")); + new GenericManaCost(1), condition + )); } private TIEBomber(final TIEBomber card) { diff --git a/Mage.Sets/src/mage/cards/t/TabletOfCompleation.java b/Mage.Sets/src/mage/cards/t/TabletOfCompleation.java index 4a009269a93..43a6817091b 100644 --- a/Mage.Sets/src/mage/cards/t/TabletOfCompleation.java +++ b/Mage.Sets/src/mage/cards/t/TabletOfCompleation.java @@ -1,7 +1,5 @@ package mage.cards.t; -import java.util.UUID; - import mage.Mana; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -21,6 +19,8 @@ import mage.constants.ManaType; import mage.constants.Zone; import mage.counters.CounterType; +import java.util.UUID; + /** * @author TheElk801 */ @@ -44,8 +44,7 @@ public final class TabletOfCompleation extends CardImpl { // {1}, {T}: Draw a card. Activate only if Tablet of Compleation has five or more oil counters on it. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), - new GenericManaCost(1), condition2 + new DrawCardSourceControllerEffect(1), new GenericManaCost(1), condition2 ); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/t/TacticalAdvantage.java b/Mage.Sets/src/mage/cards/t/TacticalAdvantage.java index e63e6f0ea8e..412a4381318 100644 --- a/Mage.Sets/src/mage/cards/t/TacticalAdvantage.java +++ b/Mage.Sets/src/mage/cards/t/TacticalAdvantage.java @@ -10,6 +10,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.BlockedPredicate; import mage.filter.predicate.permanent.BlockingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -36,7 +37,7 @@ public final class TacticalAdvantage extends CardImpl { // Target blocking or blocked creature you control gets +2/+2 until end of turn. this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private TacticalAdvantage(final TacticalAdvantage card) { diff --git a/Mage.Sets/src/mage/cards/t/TaigamOjutaiMaster.java b/Mage.Sets/src/mage/cards/t/TaigamOjutaiMaster.java index 68cf65183b4..77e7c42cfab 100644 --- a/Mage.Sets/src/mage/cards/t/TaigamOjutaiMaster.java +++ b/Mage.Sets/src/mage/cards/t/TaigamOjutaiMaster.java @@ -2,26 +2,22 @@ package mage.cards.t; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.common.AttackedThisTurnSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.CantBeCounteredControlledEffect; import mage.abilities.keyword.ReboundAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterSpell; +import mage.filter.StaticFilters; import mage.filter.predicate.Predicates; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.stack.Spell; -import mage.players.Player; -import mage.target.targetpointer.FixedTarget; +import java.util.Optional; import java.util.UUID; /** @@ -29,16 +25,14 @@ import java.util.UUID; */ public final class TaigamOjutaiMaster extends CardImpl { - private static final String effectText = "Whenever you cast an instant or sorcery spell from your hand, if {this} attacked this turn, that spell gains rebound."; - private static final FilterSpell filter = new FilterSpell("Instant, sorcery, and Dragon spells you control"); + private static final FilterSpell filter = new FilterSpell("instant, sorcery, and Dragon spells you control"); static { - filter.add( - (Predicates.or( - CardType.INSTANT.getPredicate(), - CardType.SORCERY.getPredicate(), - SubType.DRAGON.getPredicate())) - ); + filter.add(Predicates.or( + CardType.INSTANT.getPredicate(), + CardType.SORCERY.getPredicate(), + SubType.DRAGON.getPredicate() + )); } public TaigamOjutaiMaster(UUID ownerId, CardSetInfo setInfo) { @@ -54,10 +48,11 @@ public final class TaigamOjutaiMaster extends CardImpl { this.addAbility(new SimpleStaticAbility(new CantBeCounteredControlledEffect(filter, Duration.WhileOnBattlefield))); // Whenever you cast an instant or sorcery spell from your hand, if Taigam, Ojutai Master attacked this turn, that spell gains rebound. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new TaigamOjutaiMasterTriggeredAbility(), - AttackedThisTurnSourceCondition.instance, - effectText); - this.addAbility(ability); + this.addAbility(new SpellCastControllerTriggeredAbility( + Zone.BATTLEFIELD, new TaigamOjutaiMasterEffect(), + StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, + false, SetTargetPointer.SPELL, Zone.HAND + ).withInterveningIf(AttackedThisTurnSourceCondition.instance)); } private TaigamOjutaiMaster(final TaigamOjutaiMaster card) { @@ -70,84 +65,33 @@ public final class TaigamOjutaiMaster extends CardImpl { } } -class TaigamOjutaiMasterTriggeredAbility extends DelayedTriggeredAbility { +class TaigamOjutaiMasterEffect extends ContinuousEffectImpl { - public TaigamOjutaiMasterTriggeredAbility() { - super(new TaigamOjutaiMasterGainReboundEffect(), Duration.EndOfTurn, true); - setTriggerPhrase("Whenever you cast an instant or sorcery spell from your hand, if {this} attacked this turn, "); - } - - private TaigamOjutaiMasterTriggeredAbility(final TaigamOjutaiMasterTriggeredAbility ability) { - super(ability); - } - - @Override - public TaigamOjutaiMasterTriggeredAbility copy() { - return new TaigamOjutaiMasterTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.SPELL_CAST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getPlayerId().equals(this.getControllerId())) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null && spell.getFromZone() == Zone.HAND) { - if (spell.getCard() != null - && spell.getCard().isInstantOrSorcery(game)) { - for (Effect effect : getEffects()) { - effect.setTargetPointer(new FixedTarget(spell.getId())); - } - return true; - } - } - } - return false; - } -} - -class TaigamOjutaiMasterGainReboundEffect extends ContinuousEffectImpl { - - TaigamOjutaiMasterGainReboundEffect() { + TaigamOjutaiMasterEffect() { super(Duration.Custom, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); staticText = "that spell gains rebound"; } - private TaigamOjutaiMasterGainReboundEffect(final TaigamOjutaiMasterGainReboundEffect effect) { + private TaigamOjutaiMasterEffect(final TaigamOjutaiMasterEffect effect) { super(effect); } @Override - public TaigamOjutaiMasterGainReboundEffect copy() { - return new TaigamOjutaiMasterGainReboundEffect(this); + public TaigamOjutaiMasterEffect copy() { + return new TaigamOjutaiMasterEffect(this); } @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - Spell spell = game.getStack().getSpell(getTargetPointer().getFirst(game, source)); - if (spell != null) { - Card card = spell.getCard(); - if (card != null) { - addReboundAbility(card, source, game); - } - } else { - discard(); - } - return true; - } - return false; - } - - private void addReboundAbility(Card card, Ability source, Game game) { - boolean found = card.getAbilities(game).containsClass(ReboundAbility.class); - if (!found) { - Ability ability = new ReboundAbility(); - game.getState().addOtherAbility(card, ability); + Spell spell = game.getStack().getSpell(getTargetPointer().getFirst(game, source)); + if (spell == null) { + discard(); + return false; } + Optional.of(spell) + .map(Spell::getCard) + .filter(card -> !card.getAbilities(game).containsClass(ReboundAbility.class)) + .ifPresent(card -> game.getState().addOtherAbility(card, new ReboundAbility())); + return true; } } diff --git a/Mage.Sets/src/mage/cards/t/TailSlash.java b/Mage.Sets/src/mage/cards/t/TailSlash.java index bc5f9619427..ad50c57fbbd 100644 --- a/Mage.Sets/src/mage/cards/t/TailSlash.java +++ b/Mage.Sets/src/mage/cards/t/TailSlash.java @@ -5,11 +5,14 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author LevelX2 */ @@ -21,7 +24,7 @@ public final class TailSlash extends CardImpl { // Target creature you control deals damage equal to its power to target creature you don't control. this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); } private TailSlash(final TailSlash card) { diff --git a/Mage.Sets/src/mage/cards/t/TajuruArcher.java b/Mage.Sets/src/mage/cards/t/TajuruArcher.java index ac1d5cffa70..18fc688065e 100644 --- a/Mage.Sets/src/mage/cards/t/TajuruArcher.java +++ b/Mage.Sets/src/mage/cards/t/TajuruArcher.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -41,7 +42,7 @@ public final class TajuruArcher extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(2); Ability ability = new AllyEntersBattlefieldTriggeredAbility(new DamageTargetEffect(new PermanentsOnBattlefieldCount(filter)), true); - ability.addTarget(new TargetCreaturePermanent(filterTarget)); + ability.addTarget(new TargetPermanent(filterTarget)); this.addAbility(ability.setAbilityWord(null)); } diff --git a/Mage.Sets/src/mage/cards/t/TakeDown.java b/Mage.Sets/src/mage/cards/t/TakeDown.java index 7cf0576ccc9..14989740706 100644 --- a/Mage.Sets/src/mage/cards/t/TakeDown.java +++ b/Mage.Sets/src/mage/cards/t/TakeDown.java @@ -11,6 +11,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -31,7 +32,7 @@ public final class TakeDown extends CardImpl { // Choose one — // • Take Down deals 4 damage to target creature with flying. this.getSpellAbility().addEffect(new DamageTargetEffect(4)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // • Take Down deals 1 damage to each creature with flying Mode mode = new Mode(new DamageAllEffect(1, filter)); diff --git a/Mage.Sets/src/mage/cards/t/TakeIntoCustody.java b/Mage.Sets/src/mage/cards/t/TakeIntoCustody.java index f0fa97252a3..daf8fa68f64 100644 --- a/Mage.Sets/src/mage/cards/t/TakeIntoCustody.java +++ b/Mage.Sets/src/mage/cards/t/TakeIntoCustody.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; import mage.abilities.effects.common.TapTargetEffect; import mage.cards.CardImpl; @@ -9,8 +7,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class TakeIntoCustody extends CardImpl { @@ -20,8 +19,8 @@ public final class TakeIntoCustody extends CardImpl { // Tap target creature. It doesn't untap during its controller's next untap step. this.getSpellAbility().addEffect(new TapTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(1)); this.getSpellAbility().addEffect(new DontUntapInControllersNextUntapStepTargetEffect("It")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } private TakeIntoCustody(final TakeIntoCustody card) { diff --git a/Mage.Sets/src/mage/cards/t/TakeInventory.java b/Mage.Sets/src/mage/cards/t/TakeInventory.java index f3c89ded44a..11b40c82df5 100644 --- a/Mage.Sets/src/mage/cards/t/TakeInventory.java +++ b/Mage.Sets/src/mage/cards/t/TakeInventory.java @@ -1,7 +1,6 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -13,8 +12,9 @@ import mage.constants.CardType; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.NamePredicate; +import java.util.UUID; + /** - * * @author fireshoes * modified tiera3 - added Hint */ @@ -25,17 +25,18 @@ public final class TakeInventory extends CardImpl { static { filter.add(new NamePredicate("Take Inventory")); } + private static final Hint hint = new ValueHint( "Cards named Take Inventory in your graveyard", new CardsInControllerGraveyardCount(filter) ); public TakeInventory(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}"); // Draw a card, then draw cards equal to the number of cards named Take Inventory in your graveyard. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); Effect effect = new DrawCardSourceControllerEffect(new CardsInControllerGraveyardCount(filter)); - effect.setText(", then draw cards equal to the number of cards named {this} in your graveyard"); + effect.setText(", then draw cards equal to the number of cards named Take Inventory in your graveyard"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addHint(hint); } diff --git a/Mage.Sets/src/mage/cards/t/TakeVengeance.java b/Mage.Sets/src/mage/cards/t/TakeVengeance.java index 53eb232659f..253cd29bb61 100644 --- a/Mage.Sets/src/mage/cards/t/TakeVengeance.java +++ b/Mage.Sets/src/mage/cards/t/TakeVengeance.java @@ -7,6 +7,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -26,7 +27,7 @@ public final class TakeVengeance extends CardImpl { // Destroy target tapped creature. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private TakeVengeance(final TakeVengeance card) { diff --git a/Mage.Sets/src/mage/cards/t/Takklemaggot.java b/Mage.Sets/src/mage/cards/t/Takklemaggot.java index d67eb63a0bd..45ccdda4756 100644 --- a/Mage.Sets/src/mage/cards/t/Takklemaggot.java +++ b/Mage.Sets/src/mage/cards/t/Takklemaggot.java @@ -101,7 +101,7 @@ class TakklemaggotEffect extends OneShotEffect { } FilterCreaturePermanent filter = new FilterCreaturePermanent(); filter.add(new CanBeEnchantedByPredicate(auraCard)); - Target target = new TargetCreaturePermanent(filter).withNotTarget(true); + Target target = new TargetPermanent(filter).withNotTarget(true); if (!game.getBattlefield().getActivePermanents(filter, player.getId(), source, game).isEmpty() && player.choose(outcome, target, source, game)) { // return attached to that creature diff --git a/Mage.Sets/src/mage/cards/t/TalasResearcher.java b/Mage.Sets/src/mage/cards/t/TalasResearcher.java index 7bd3d41700e..8c1408d0f55 100644 --- a/Mage.Sets/src/mage/cards/t/TalasResearcher.java +++ b/Mage.Sets/src/mage/cards/t/TalasResearcher.java @@ -1,9 +1,6 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.MyTurnBeforeAttackersDeclaredCondition; import mage.abilities.costs.common.TapSourceCost; @@ -12,16 +9,16 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; + +import java.util.UUID; /** - * * @author fireshoes */ public final class TalasResearcher extends CardImpl { public TalasResearcher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.PIRATE); this.subtype.add(SubType.WIZARD); @@ -29,10 +26,10 @@ public final class TalasResearcher extends CardImpl { this.toughness = new MageInt(1); // {tap}: Draw a card. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new DrawCardSourceControllerEffect(1), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); - - this.addAbility(ability); + this.addAbility(new ActivateIfConditionActivatedAbility( + new DrawCardSourceControllerEffect(1), new TapSourceCost(), + MyTurnBeforeAttackersDeclaredCondition.instance + )); } private TalasResearcher(final TalasResearcher card) { diff --git a/Mage.Sets/src/mage/cards/t/TaleOfTinuviel.java b/Mage.Sets/src/mage/cards/t/TaleOfTinuviel.java index 436831ae34f..f5ccf51b009 100644 --- a/Mage.Sets/src/mage/cards/t/TaleOfTinuviel.java +++ b/Mage.Sets/src/mage/cards/t/TaleOfTinuviel.java @@ -48,7 +48,7 @@ public final class TaleOfTinuviel extends CardImpl { sagaAbility.addChapterEffect( this, SagaChapter.CHAPTER_III, SagaChapter.CHAPTER_III, new GainAbilityTargetEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn), - new TargetControlledCreaturePermanent(0, 2, StaticFilters.FILTER_CONTROLLED_CREATURES, false) + new TargetControlledCreaturePermanent(0, 2) ); this.addAbility(sagaAbility); } diff --git a/Mage.Sets/src/mage/cards/t/TalionTheKindlyLord.java b/Mage.Sets/src/mage/cards/t/TalionTheKindlyLord.java index c6d438b3499..19ccefbf0f6 100644 --- a/Mage.Sets/src/mage/cards/t/TalionTheKindlyLord.java +++ b/Mage.Sets/src/mage/cards/t/TalionTheKindlyLord.java @@ -75,7 +75,7 @@ enum TalionTheKindlyLordPredicate implements ObjectSourcePlayerPredicate input, Game game) { Object obj = game.getState().getValue( "chosenNumber_" + input.getSource().getSourceId() - + '_' + input.getSource().getSourceObjectZoneChangeCounter() + + '_' + input.getObject().getZoneChangeCounter(game) ); if (obj == null) { return false; diff --git a/Mage.Sets/src/mage/cards/t/TamiyoFieldResearcher.java b/Mage.Sets/src/mage/cards/t/TamiyoFieldResearcher.java index 3fd3f65fb23..85f9c3e17f8 100644 --- a/Mage.Sets/src/mage/cards/t/TamiyoFieldResearcher.java +++ b/Mage.Sets/src/mage/cards/t/TamiyoFieldResearcher.java @@ -42,7 +42,7 @@ public final class TamiyoFieldResearcher extends CardImpl { // +1: Choose up to two target creatures. Until your next turn, whenever either of those creatures deals combat damage, you draw a card. Ability ability = new LoyaltyAbility(new TamiyoFieldResearcherEffect1(), 1); - ability.addTarget(new TargetCreaturePermanent(0, 2, StaticFilters.FILTER_PERMANENT_CREATURES, false)); + ability.addTarget(new TargetCreaturePermanent(0, 2)); this.addAbility(ability); // -2: Tap up to two target nonland permanents. They don't untap during their controller's next untap step. diff --git a/Mage.Sets/src/mage/cards/t/TangleWire.java b/Mage.Sets/src/mage/cards/t/TangleWire.java index 39d89ac7b8c..0b77c52e5c4 100644 --- a/Mage.Sets/src/mage/cards/t/TangleWire.java +++ b/Mage.Sets/src/mage/cards/t/TangleWire.java @@ -1,11 +1,10 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FadingAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -21,6 +20,8 @@ import mage.players.Player; import mage.target.Target; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + /** * * @author Plopman @@ -58,7 +59,7 @@ class TangleWireEffect extends OneShotEffect { TangleWireEffect() { super(Outcome.Sacrifice); - staticText = "that player taps an untapped artifact, creature, or land they control for each fade counter on Tangle Wire"; + staticText = "that player taps an untapped artifact, creature, or land they control for each fade counter on {this}"; } private TangleWireEffect(final TangleWireEffect effect) { diff --git a/Mage.Sets/src/mage/cards/t/TannukMemorialEnsign.java b/Mage.Sets/src/mage/cards/t/TannukMemorialEnsign.java new file mode 100644 index 00000000000..e6cb55e89ba --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TannukMemorialEnsign.java @@ -0,0 +1,47 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.LandfallAbility; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.IfAbilityHasResolvedXTimesEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.TargetController; +import mage.watchers.common.AbilityResolvedWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TannukMemorialEnsign extends CardImpl { + + public TannukMemorialEnsign(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.KAVU); + this.subtype.add(SubType.PILOT); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Landfall - Whenever a land you control enters, Tannuk deals 1 damage to each opponent. If this is the second time this ability has resolved this turn, draw a card. + Ability ability = new LandfallAbility(new DamagePlayersEffect(1, TargetController.OPPONENT)); + ability.addEffect(new IfAbilityHasResolvedXTimesEffect(2, new DrawCardSourceControllerEffect(1))); + this.addAbility(ability, new AbilityResolvedWatcher()); + } + + private TannukMemorialEnsign(final TannukMemorialEnsign card) { + super(card); + } + + @Override + public TannukMemorialEnsign copy() { + return new TannukMemorialEnsign(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TapestryOfTheAges.java b/Mage.Sets/src/mage/cards/t/TapestryOfTheAges.java index f4743421a64..da974f65989 100644 --- a/Mage.Sets/src/mage/cards/t/TapestryOfTheAges.java +++ b/Mage.Sets/src/mage/cards/t/TapestryOfTheAges.java @@ -1,44 +1,39 @@ - package mage.cards.t; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.WatcherScope; -import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.watchers.Watcher; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; /** - * * @author LevelX2 */ public final class TapestryOfTheAges extends CardImpl { public TapestryOfTheAges(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // {2}, {T}: Draw a card. Activate this ability only if you've cast a noncreature spell this turn. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new DrawCardSourceControllerEffect(1), - new ManaCostsImpl<>("{2}"), - PlayerCastNonCreatureSpellCondition.instance); + new DrawCardSourceControllerEffect(1), + new GenericManaCost(2), PlayerCastNonCreatureSpellCondition.instance + ); ability.addCost(new TapSourceCost()); - this.addAbility(ability, new PlayerCastNonCreatureSpellWatcher()); - + this.addAbility(ability, new PlayerCastNonCreatureSpellWatcher()); } private TapestryOfTheAges(final TapestryOfTheAges card) { @@ -59,7 +54,7 @@ enum PlayerCastNonCreatureSpellCondition implements Condition { PlayerCastNonCreatureSpellWatcher watcher = game.getState().getWatcher(PlayerCastNonCreatureSpellWatcher.class); return watcher != null && watcher.playerDidCastNonCreatureSpellThisTurn(source.getControllerId()); } - + @Override public String toString() { return "you've cast a noncreature spell this turn"; diff --git a/Mage.Sets/src/mage/cards/t/TatsunariToadRider.java b/Mage.Sets/src/mage/cards/t/TatsunariToadRider.java index 214c00c68f3..d8938a0caff 100644 --- a/Mage.Sets/src/mage/cards/t/TatsunariToadRider.java +++ b/Mage.Sets/src/mage/cards/t/TatsunariToadRider.java @@ -7,7 +7,6 @@ import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.combat.CantBeBlockedByAllTargetEffect; import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; @@ -34,7 +33,7 @@ import java.util.UUID; */ public final class TatsunariToadRider extends CardImpl { - private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("you don't control a creature named Keimi"); private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent(); private static final FilterPermanent filter3 = new FilterControlledPermanent(SubType.FROG); @@ -56,14 +55,10 @@ public final class TatsunariToadRider extends CardImpl { this.toughness = new MageInt(3); // Whenever you cast an enchantment spell, if you don't control a creature named Keimi, create Keimi, a legendary 3/3 black and green Frog creature token with "Whenever you cast an enchantment spell, each opponent loses 1 life and you gain 1 life." - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new SpellCastControllerTriggeredAbility( - new CreateTokenEffect(new KeimiToken()), - StaticFilters.FILTER_SPELL_AN_ENCHANTMENT, false - ), condition, "Whenever you cast an enchantment spell, if you don't control " + - "a creature named Keimi, create Keimi, a legendary 3/3 black and green Frog creature token with " + - "\"Whenever you cast an enchantment spell, each opponent loses 1 life and you gain 1 life.\"" - )); + this.addAbility(new SpellCastControllerTriggeredAbility( + new CreateTokenEffect(new KeimiToken()), + StaticFilters.FILTER_SPELL_AN_ENCHANTMENT, false + ).withInterveningIf(condition)); // {1}{G/U}: Tatsunari, Toad Rider and target Frog you control can't be blocked this turn except by creatures with flying or reach. Ability ability = new SimpleActivatedAbility( diff --git a/Mage.Sets/src/mage/cards/t/TatyovaStewardOfTides.java b/Mage.Sets/src/mage/cards/t/TatyovaStewardOfTides.java index 3128a146b85..b48c6db4d7c 100644 --- a/Mage.Sets/src/mage/cards/t/TatyovaStewardOfTides.java +++ b/Mage.Sets/src/mage/cards/t/TatyovaStewardOfTides.java @@ -2,13 +2,13 @@ package mage.cards.t; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.LandfallAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.hint.common.LandsYouControlHint; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; @@ -16,6 +16,7 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledLandPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.game.permanent.token.custom.CreatureToken; import mage.target.TargetPermanent; @@ -34,7 +35,8 @@ public final class TatyovaStewardOfTides extends CardImpl { } private static final Condition condition = new PermanentsOnTheBattlefieldCondition( - StaticFilters.FILTER_LAND, ComparisonType.MORE_THAN, 6, true + new FilterControlledLandPermanent("you control seven or more lands"), + ComparisonType.MORE_THAN, 6, true ); public TatyovaStewardOfTides(UUID ownerId, CardSetInfo setInfo) { @@ -52,17 +54,13 @@ public final class TatyovaStewardOfTides extends CardImpl { ))); // Whenever a land you control enters, if you control seven or more lands, up to one target land you control becomes a 3/3 Elemental creature with haste. It's still a land. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldControlledTriggeredAbility(new BecomesCreatureTargetEffect( - new CreatureToken( - 3, 3, "3/3 Elemental creature with haste", SubType.ELEMENTAL - ).withAbility(HasteAbility.getInstance()), false, true, Duration.Custom - ), StaticFilters.FILTER_LAND_A), condition, "Whenever a land enters the battlefield " + - "under your control, if you control seven or more lands, up to one target land you control " + - "becomes a 3/3 Elemental creature with haste. It's still a land." - ); + Ability ability = new LandfallAbility( + new BecomesCreatureTargetEffect(new CreatureToken( + 3, 3, "3/3 Elemental creature with haste", SubType.ELEMENTAL + ).withAbility(HasteAbility.getInstance()), false, true, Duration.Custom) + ).withInterveningIf(condition); ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND)); - this.addAbility(ability); + this.addAbility(ability.setAbilityWord(null).addHint(LandsYouControlHint.instance)); } private TatyovaStewardOfTides(final TatyovaStewardOfTides card) { diff --git a/Mage.Sets/src/mage/cards/t/TauntingArbormage.java b/Mage.Sets/src/mage/cards/t/TauntingArbormage.java index ac01271ef3b..b38bc0bffd8 100644 --- a/Mage.Sets/src/mage/cards/t/TauntingArbormage.java +++ b/Mage.Sets/src/mage/cards/t/TauntingArbormage.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.combat.MustBeBlockedByAllTargetEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; @@ -33,11 +32,7 @@ public final class TauntingArbormage extends CardImpl { this.addAbility(new KickerAbility("{3}")); // When Taunting Arbormage enters the battlefield, if it was kicked, all creatures able to block target creature this turn do so. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new MustBeBlockedByAllTargetEffect(Duration.EndOfTurn)), - KickedCondition.ONCE, "When {this} enters, if it was kicked, " + - "all creatures able to block target creature this turn do so." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new MustBeBlockedByAllTargetEffect(Duration.EndOfTurn)).withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TawnossWand.java b/Mage.Sets/src/mage/cards/t/TawnossWand.java index 34c1271b4e8..b209debabcf 100644 --- a/Mage.Sets/src/mage/cards/t/TawnossWand.java +++ b/Mage.Sets/src/mage/cards/t/TawnossWand.java @@ -14,6 +14,7 @@ import mage.constants.ComparisonType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -34,7 +35,7 @@ public final class TawnossWand extends CardImpl { // {2}, {tap}: Target creature with power 2 or less is unblockable this turn. Ability ability = new SimpleActivatedAbility(new CantBeBlockedTargetEffect(), new TapSourceCost()); ability.addCost(new ManaCostsImpl<>("{2}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TazeemRoilmage.java b/Mage.Sets/src/mage/cards/t/TazeemRoilmage.java index 77c3289f3da..567ea897247 100644 --- a/Mage.Sets/src/mage/cards/t/TazeemRoilmage.java +++ b/Mage.Sets/src/mage/cards/t/TazeemRoilmage.java @@ -4,15 +4,13 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.FilterCard; -import mage.filter.common.FilterInstantOrSorceryCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; @@ -22,9 +20,6 @@ import java.util.UUID; */ public final class TazeemRoilmage extends CardImpl { - private static final FilterCard filter - = new FilterInstantOrSorceryCard("instant or sorcery card from your graveyard"); - public TazeemRoilmage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); @@ -37,12 +32,8 @@ public final class TazeemRoilmage extends CardImpl { this.addAbility(new KickerAbility("{4}")); // When Tazeem Roilmage enters the battlefield, if it was kicked, return target instant or sorcery card from your graveyard to your hand. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), false), - KickedCondition.ONCE, "When {this} enters, if it was kicked, " + - "return target instant or sorcery card from your graveyard to your hand." - ); - ability.addTarget(new TargetCardInYourGraveyard(filter)); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()).withInterveningIf(KickedCondition.ONCE); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TeamPennant.java b/Mage.Sets/src/mage/cards/t/TeamPennant.java index db08dfa9020..36d3e3fa5a3 100644 --- a/Mage.Sets/src/mage/cards/t/TeamPennant.java +++ b/Mage.Sets/src/mage/cards/t/TeamPennant.java @@ -14,18 +14,19 @@ import mage.constants.AttachmentType; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.TokenPredicate; +import mage.target.TargetPermanent; import java.util.UUID; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.target.common.TargetControlledCreaturePermanent; /** * @author TheElk801 */ public final class TeamPennant extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature token"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("creature token"); static { filter.add(TokenPredicate.TRUE); @@ -48,11 +49,12 @@ public final class TeamPennant extends CardImpl { // Equip creature token {1} this.addAbility(new EquipAbility( - Outcome.BoostCreature, new GenericManaCost(1), new TargetControlledCreaturePermanent(filter), false + Outcome.BoostCreature, new GenericManaCost(1), + new TargetPermanent(filter), false )); // Equip {3} - this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(3), new TargetControlledCreaturePermanent(), false)); + this.addAbility(new EquipAbility(3, false)); } private TeamPennant(final TeamPennant card) { diff --git a/Mage.Sets/src/mage/cards/t/TearsOfValakut.java b/Mage.Sets/src/mage/cards/t/TearsOfValakut.java index 7fb39717873..5eeb74dc09a 100644 --- a/Mage.Sets/src/mage/cards/t/TearsOfValakut.java +++ b/Mage.Sets/src/mage/cards/t/TearsOfValakut.java @@ -10,6 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -32,7 +33,7 @@ public final class TearsOfValakut extends CardImpl { // Tears of Valakut deals 5 damage to target creature with flying. this.getSpellAbility().addEffect(new DamageTargetEffect(5)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private TearsOfValakut(final TearsOfValakut card) { diff --git a/Mage.Sets/src/mage/cards/t/TectonicEdge.java b/Mage.Sets/src/mage/cards/t/TectonicEdge.java index 243bbc9cfb1..eb6f690d91e 100644 --- a/Mage.Sets/src/mage/cards/t/TectonicEdge.java +++ b/Mage.Sets/src/mage/cards/t/TectonicEdge.java @@ -1,6 +1,5 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.Condition; @@ -14,12 +13,12 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; -import mage.constants.Zone; import mage.filter.common.FilterLandPermanent; import mage.target.common.TargetNonBasicLandPermanent; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public final class TectonicEdge extends CardImpl { @@ -29,14 +28,14 @@ public final class TectonicEdge extends CardImpl { ); public TectonicEdge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},null); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, null); // Tap: Add 1. this.addAbility(new ColorlessManaAbility()); // {1}, {T}, Sacrifice Tectonic Edge: Destroy target nonbasic land. Activate only if an opponent controls four or more lands. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new DestroyTargetEffect(), new GenericManaCost(1), condition + new DestroyTargetEffect(), new GenericManaCost(1), condition ); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); diff --git a/Mage.Sets/src/mage/cards/t/TeganJovanka.java b/Mage.Sets/src/mage/cards/t/TeganJovanka.java index 0ea46909739..760b4a9ff55 100644 --- a/Mage.Sets/src/mage/cards/t/TeganJovanka.java +++ b/Mage.Sets/src/mage/cards/t/TeganJovanka.java @@ -15,6 +15,7 @@ import mage.constants.SuperType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.HistoricPredicate; import mage.filter.predicate.permanent.AttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -45,7 +46,7 @@ public final class TeganJovanka extends CardImpl { .setText("target attacking historic creature gets +1/+1"), 1 ); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); ability.addEffect(new GainAbilityTargetEffect(IndestructibleAbility.getInstance()) .setText("and gains indestructible until end of turn")); this.addAbility(ability.withFlavorWord("Brave Heart")); diff --git a/Mage.Sets/src/mage/cards/t/TegwyllsScouring.java b/Mage.Sets/src/mage/cards/t/TegwyllsScouring.java index b01786f5bbe..f5b263069dc 100644 --- a/Mage.Sets/src/mage/cards/t/TegwyllsScouring.java +++ b/Mage.Sets/src/mage/cards/t/TegwyllsScouring.java @@ -16,7 +16,6 @@ import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.permanent.token.FaerieRogueToken; -import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; @@ -24,6 +23,7 @@ import java.util.UUID; * @author karapuzz14 */ public final class TegwyllsScouring extends CardImpl { + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control with flying"); static { @@ -34,11 +34,9 @@ public final class TegwyllsScouring extends CardImpl { public TegwyllsScouring(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}{B}"); - // You may cast Tegwyll's Scouring as though it had flash by tapping three untapped creatures you control with flying in addition to paying its other costs. - Cost asThoughCost = new TapTargetCost(new TargetControlledCreaturePermanent(3, 3, filter, true)).setText(""); CostsImpl costs = new CostsImpl<>().setText("tapping three untapped creatures you control with flying"); - costs.add(asThoughCost); + costs.add(new TapTargetCost(3, filter).setText("")); Ability ability = new PayMoreToCastAsThoughtItHadFlashAbility(this, costs); ability.addEffect(new DestroyAllEffect(StaticFilters.FILTER_PERMANENT_CREATURES)); @@ -60,4 +58,4 @@ public final class TegwyllsScouring extends CardImpl { public TegwyllsScouring copy() { return new TegwyllsScouring(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/t/Teleport.java b/Mage.Sets/src/mage/cards/t/Teleport.java index c032191a5c3..9836ee79f45 100644 --- a/Mage.Sets/src/mage/cards/t/Teleport.java +++ b/Mage.Sets/src/mage/cards/t/Teleport.java @@ -1,7 +1,6 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; import mage.cards.CardImpl; @@ -10,6 +9,8 @@ import mage.constants.CardType; import mage.constants.PhaseStep; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * * @author L_J @@ -20,7 +21,7 @@ public final class Teleport extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}{U}{U}"); // Cast Teleport only during the declare attackers step. - this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, PhaseStep.DECLARE_ATTACKERS, null, "Cast Teleport only during the declare attackers step")); + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, PhaseStep.DECLARE_ATTACKERS, null, "Cast {this} only during the declare attackers step")); // Target creature can't be blocked this turn. this.getSpellAbility().addEffect(new CantBeBlockedTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/t/Telethopter.java b/Mage.Sets/src/mage/cards/t/Telethopter.java index 14ffaeed362..b61ade45608 100644 --- a/Mage.Sets/src/mage/cards/t/Telethopter.java +++ b/Mage.Sets/src/mage/cards/t/Telethopter.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapTargetCost; @@ -10,30 +8,27 @@ import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; /** * @author Loki */ public final class Telethopter extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); - - static { - filter.add(TappedPredicate.UNTAPPED); - } - public Telethopter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); this.subtype.add(SubType.THOPTER); this.power = new MageInt(3); this.toughness = new MageInt(1); - this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, false)))); + + this.addAbility(new SimpleActivatedAbility( + new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), + new TapTargetCost(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE) + )); } private Telethopter(final Telethopter card) { diff --git a/Mage.Sets/src/mage/cards/t/TemmetVizierOfNaktamun.java b/Mage.Sets/src/mage/cards/t/TemmetVizierOfNaktamun.java index 98f060d1a8e..91a561a03d9 100644 --- a/Mage.Sets/src/mage/cards/t/TemmetVizierOfNaktamun.java +++ b/Mage.Sets/src/mage/cards/t/TemmetVizierOfNaktamun.java @@ -1,32 +1,30 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.keyword.EmbalmAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Duration; import mage.constants.SuperType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.TokenPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author fireshoes */ public final class TemmetVizierOfNaktamun extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature token you control"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("creature token you control"); static { filter.add(TokenPredicate.TRUE); @@ -42,11 +40,9 @@ public final class TemmetVizierOfNaktamun extends CardImpl { this.toughness = new MageInt(2); // At the beginning of combat on your turn, target creature token you control gets +1/+1 until end of turn and can't be blocked this turn. - Ability ability = new BeginningOfCombatTriggeredAbility(new BoostTargetEffect(1, 1, Duration.EndOfTurn)); - Effect effect = new CantBeBlockedTargetEffect(); - effect.setText(" and can't be blocked this turn"); - ability.addEffect(effect); - ability.addTarget(new TargetControlledCreaturePermanent(filter)); + Ability ability = new BeginningOfCombatTriggeredAbility(new BoostTargetEffect(1, 1)); + ability.addEffect(new CantBeBlockedTargetEffect().setText("and can't be blocked this turn")); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Embalm {3}{W}{U} diff --git a/Mage.Sets/src/mage/cards/t/TempestOwl.java b/Mage.Sets/src/mage/cards/t/TempestOwl.java index 7355eeed445..54b6c534c7e 100644 --- a/Mage.Sets/src/mage/cards/t/TempestOwl.java +++ b/Mage.Sets/src/mage/cards/t/TempestOwl.java @@ -1,11 +1,9 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.KickerAbility; @@ -13,17 +11,18 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author Rafbill */ public final class TempestOwl extends CardImpl { public TempestOwl(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.subtype.add(SubType.BIRD); this.power = new MageInt(1); @@ -36,9 +35,9 @@ public final class TempestOwl extends CardImpl { this.addAbility(new KickerAbility("{4}{U}")); // When Tempest Owl enters the battlefield, if it was kicked, tap up to three target permanents. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect(), false); - ability.addTarget(new TargetPermanent(0, 3, new FilterPermanent(), false)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.ONCE, "When {this} enters, if it was kicked, tap up to three target permanents.")); + Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect(), false).withInterveningIf(KickedCondition.ONCE); + ability.addTarget(new TargetPermanent(0, 3, StaticFilters.FILTER_PERMANENTS)); + this.addAbility(ability); } private TempestOwl(final TempestOwl card) { diff --git a/Mage.Sets/src/mage/cards/t/TempleElder.java b/Mage.Sets/src/mage/cards/t/TempleElder.java index 38c9f2a4328..f243c79457c 100644 --- a/Mage.Sets/src/mage/cards/t/TempleElder.java +++ b/Mage.Sets/src/mage/cards/t/TempleElder.java @@ -1,9 +1,6 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.MyTurnBeforeAttackersDeclaredCondition; import mage.abilities.costs.common.TapSourceCost; @@ -12,25 +9,26 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; + +import java.util.UUID; /** - * * @author fireshoes */ public final class TempleElder extends CardImpl { public TempleElder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); this.power = new MageInt(1); this.toughness = new MageInt(2); // {tap}: You gain 1 life. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new GainLifeEffect(1), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); - this.addAbility(ability); + this.addAbility(new ActivateIfConditionActivatedAbility( + new GainLifeEffect(1), new TapSourceCost(), + MyTurnBeforeAttackersDeclaredCondition.instance + )); } private TempleElder(final TempleElder card) { diff --git a/Mage.Sets/src/mage/cards/t/TempleOfCivilization.java b/Mage.Sets/src/mage/cards/t/TempleOfCivilization.java index ee18a2fb64a..0e5544cfd20 100644 --- a/Mage.Sets/src/mage/cards/t/TempleOfCivilization.java +++ b/Mage.Sets/src/mage/cards/t/TempleOfCivilization.java @@ -11,7 +11,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TimingRule; -import mage.constants.Zone; import mage.game.Game; import mage.watchers.common.PlayerAttackedWatcher; @@ -33,12 +32,8 @@ public final class TempleOfCivilization extends CardImpl { // {2}{W}, {T}: Transform Temple of Civilization. Activate only if you attacked with three or more creatures this turn and only as a sorcery. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new TransformSourceEffect(), - new ManaCostsImpl<>("{2}{W}"), - TempleOfCivilizationCondition.instance, - TimingRule.SORCERY - ); + new TransformSourceEffect(), new ManaCostsImpl<>("{2}{W}"), TempleOfCivilizationCondition.instance + ).setTiming(TimingRule.SORCERY); ability.addCost(new TapSourceCost()); this.addAbility(ability, new PlayerAttackedWatcher()); } diff --git a/Mage.Sets/src/mage/cards/t/TempleOfCultivation.java b/Mage.Sets/src/mage/cards/t/TempleOfCultivation.java index 60d3c9327a3..bd991824891 100644 --- a/Mage.Sets/src/mage/cards/t/TempleOfCultivation.java +++ b/Mage.Sets/src/mage/cards/t/TempleOfCultivation.java @@ -2,20 +2,19 @@ package mage.cards.t; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.condition.IntCompareCondition; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.PermanentsYouControlCount; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.hint.ValueHint; +import mage.abilities.hint.common.PermanentsYouControlHint; import mage.abilities.mana.GreenManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.TimingRule; -import mage.constants.Zone; -import mage.game.Game; +import mage.filter.common.FilterControlledPermanent; import java.util.UUID; @@ -24,6 +23,10 @@ import java.util.UUID; */ public final class TempleOfCultivation extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent("you control ten or more permanents"), ComparisonType.MORE_THAN, 9 + ); + public TempleOfCultivation(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); this.nightCard = true; @@ -35,15 +38,10 @@ public final class TempleOfCultivation extends CardImpl { // {2}{G}, {T}: Transform Temple of Cultivation. Activate only if you control ten or more permanents and only as a sorcery. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new TransformSourceEffect(), - new ManaCostsImpl<>("{2}{G}"), - new TempleOfCultivationCondition(), - TimingRule.SORCERY - ); + new TransformSourceEffect(), new ManaCostsImpl<>("{2}{G}"), condition + ).setTiming(TimingRule.SORCERY); ability.addCost(new TapSourceCost()); - ability.addHint(new ValueHint("controlled permanents", PermanentsYouControlCount.instance)); - this.addAbility(ability); + this.addAbility(ability.addHint(PermanentsYouControlHint.instance)); } private TempleOfCultivation(final TempleOfCultivation card) { @@ -55,20 +53,3 @@ public final class TempleOfCultivation extends CardImpl { return new TempleOfCultivation(this); } } - -class TempleOfCultivationCondition extends IntCompareCondition { - - TempleOfCultivationCondition() { - super(ComparisonType.OR_GREATER, 10); - } - - @Override - protected int getInputValue(Game game, Ability source) { - return PermanentsYouControlCount.instance.calculate(game, source, null); - } - - @Override - public String toString() { - return "if you control ten or more permanents"; - } -} diff --git a/Mage.Sets/src/mage/cards/t/TempleOfCyclicalTime.java b/Mage.Sets/src/mage/cards/t/TempleOfCyclicalTime.java index b5639028634..88fa042529e 100644 --- a/Mage.Sets/src/mage/cards/t/TempleOfCyclicalTime.java +++ b/Mage.Sets/src/mage/cards/t/TempleOfCyclicalTime.java @@ -14,7 +14,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.TimingRule; -import mage.constants.Zone; import mage.counters.CounterType; import java.util.UUID; @@ -39,9 +38,8 @@ public final class TempleOfCyclicalTime extends CardImpl { // {2}{U}, {T}: Transform Temple of Cyclical Time. Activate only if it has no time counters on it and only as a sorcery. ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new TransformSourceEffect(), - new ManaCostsImpl<>("{2}{U}"), condition, TimingRule.SORCERY - ); + new TransformSourceEffect(), new ManaCostsImpl<>("{2}{U}"), condition + ).setTiming(TimingRule.SORCERY); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TempleOfPower.java b/Mage.Sets/src/mage/cards/t/TempleOfPower.java index 9056b7038f5..c6bb1dc614d 100644 --- a/Mage.Sets/src/mage/cards/t/TempleOfPower.java +++ b/Mage.Sets/src/mage/cards/t/TempleOfPower.java @@ -14,7 +14,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TimingRule; import mage.constants.WatcherScope; -import mage.constants.Zone; import mage.game.Game; import mage.game.command.CommandObject; import mage.game.events.DamagedEvent; @@ -43,16 +42,10 @@ public final class TempleOfPower extends CardImpl { // {2}{R}, {T}: Transform Temple of Power. Activate only if red sources you controlled dealt 4 or more noncombat damage this turn and only as a sorcery. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new TransformSourceEffect(), - new ManaCostsImpl<>("{2}{R}"), - TempleOfPowerCondition.instance, - TimingRule.SORCERY - ); - ability.addWatcher(new TempleOfPowerWatcher()); + new TransformSourceEffect(), new ManaCostsImpl<>("{2}{R}"), TempleOfPowerCondition.instance + ).setTiming(TimingRule.SORCERY); ability.addCost(new TapSourceCost()); - ability.addHint(TempleOfPowerHint.instance); - this.addAbility(ability); + this.addAbility(ability.addHint(TempleOfPowerHint.instance), new TempleOfPowerWatcher()); } private TempleOfPower(final TempleOfPower card) { @@ -77,7 +70,7 @@ enum TempleOfPowerCondition implements Condition { @Override public String toString() { - return "if red sources you controlled dealt 4 or more noncombat damage this turn"; + return "red sources you controlled dealt 4 or more noncombat damage this turn"; } } diff --git a/Mage.Sets/src/mage/cards/t/TempleOfTheDead.java b/Mage.Sets/src/mage/cards/t/TempleOfTheDead.java index 8a4e7056961..0c63338958b 100644 --- a/Mage.Sets/src/mage/cards/t/TempleOfTheDead.java +++ b/Mage.Sets/src/mage/cards/t/TempleOfTheDead.java @@ -12,7 +12,10 @@ import mage.abilities.hint.Hint; import mage.abilities.mana.BlackManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.TargetController; +import mage.constants.TimingRule; import java.util.UUID; @@ -22,7 +25,7 @@ import java.util.UUID; public final class TempleOfTheDead extends CardImpl { private static final Condition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 2, TargetController.ANY); - private static final Hint hint = new ConditionHint(condition, "a player has one or fewer cards in hand"); + private static final Hint hint = new ConditionHint(condition); public TempleOfTheDead(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); @@ -35,15 +38,10 @@ public final class TempleOfTheDead extends CardImpl { // {2}{B}, {T}: Transform Temple of the Dead. Activate only if a player has one or fewer cards in hand and only as a sorcery. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new TransformSourceEffect(), - new ManaCostsImpl<>("{2}{B}"), - condition, - TimingRule.SORCERY - ); + new TransformSourceEffect(), new ManaCostsImpl<>("{2}{B}"), condition + ).setTiming(TimingRule.SORCERY); ability.addCost(new TapSourceCost()); - ability.addHint(hint); - this.addAbility(ability); + this.addAbility(ability.addHint(hint)); } private TempleOfTheDead(final TempleOfTheDead card) { diff --git a/Mage.Sets/src/mage/cards/t/TemporalIntervention.java b/Mage.Sets/src/mage/cards/t/TemporalIntervention.java new file mode 100644 index 00000000000..9dd39b7c3fb --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TemporalIntervention.java @@ -0,0 +1,46 @@ +package mage.cards.t; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.VoidCondition; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.abilities.effects.common.discard.DiscardCardYouChooseTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.target.common.TargetOpponent; +import mage.watchers.common.VoidWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TemporalIntervention extends CardImpl { + + public TemporalIntervention(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); + + // Void -- This spell costs {2} less to cast if a nonland permanent left the battlefield this turn or a spell was warped this turn. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SpellCostReductionSourceEffect(2, VoidCondition.instance) + .setText("this spell costs {2} less to cast if a nonland permanent " + + "left the battlefield this turn or a spell was warped this turn") + ).setRuleAtTheTop(true).setAbilityWord(AbilityWord.VOID).addHint(VoidCondition.getHint()), new VoidWatcher()); + + // Target opponent reveals their hand. You choose a nonland card from it. That player discards that card. + this.getSpellAbility().addEffect(new DiscardCardYouChooseTargetEffect(StaticFilters.FILTER_CARD_NON_LAND)); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + private TemporalIntervention(final TemporalIntervention card) { + super(card); + } + + @Override + public TemporalIntervention copy() { + return new TemporalIntervention(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TemporaryInsanity.java b/Mage.Sets/src/mage/cards/t/TemporaryInsanity.java index 514db387a07..f6044020648 100644 --- a/Mage.Sets/src/mage/cards/t/TemporaryInsanity.java +++ b/Mage.Sets/src/mage/cards/t/TemporaryInsanity.java @@ -1,9 +1,5 @@ - package mage.cards.t; -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; @@ -12,10 +8,17 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetCreaturePermanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import java.util.HashSet; +import java.util.Optional; import java.util.UUID; /** @@ -23,22 +26,20 @@ import java.util.UUID; */ public final class TemporaryInsanity extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("creature with power less than the number of cards in your graveyard"); + public TemporaryInsanity(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}"); // Untap target creature with power less than the number of cards in your graveyard - this.getSpellAbility().addTarget(new TargetCreatureWithPowerLessThanNumberOfCardsInYourGraveyard()); this.getSpellAbility().addEffect(new UntapTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); // and gain control of it until end of turn. - Effect effect = new GainControlTargetEffect(Duration.EndOfTurn); - effect.setText("and gain control of it until end of turn"); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfTurn).setText("and gain control of it until end of turn")); // That creature gains haste until end of turn. - effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); - effect.setText("That creature gains haste until end of turn."); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn).setText("That creature gains haste until end of turn.")); } private TemporaryInsanity(final TemporaryInsanity card) { @@ -51,46 +52,17 @@ public final class TemporaryInsanity extends CardImpl { } } -class TargetCreatureWithPowerLessThanNumberOfCardsInYourGraveyard extends TargetCreaturePermanent { - - public TargetCreatureWithPowerLessThanNumberOfCardsInYourGraveyard() { - super(); - targetName = "creature with power less than the number of cards in your graveyard"; - } - - private TargetCreatureWithPowerLessThanNumberOfCardsInYourGraveyard(final TargetCreatureWithPowerLessThanNumberOfCardsInYourGraveyard target) { - super(target); - } +enum TemporaryInsanityPredicate implements ObjectSourcePlayerPredicate { + instance; @Override - public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (super.canTarget(controllerId, id, source, game)) { - Permanent target = game.getPermanent(id); - if (target != null) { - return target.getPower().getValue() < game.getPlayer(source.getControllerId()).getGraveyard().size(); - } - return false; - } - return false; - } - - @Override - public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { - MageObject targetSource = game.getObject(source); - if (targetSource != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) { - if (permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) { - if (permanent.getPower().getValue() < game.getPlayer(sourceControllerId).getGraveyard().size()) { - return true; - } - } - } - } - return false; - } - - @Override - public TargetCreatureWithPowerLessThanNumberOfCardsInYourGraveyard copy() { - return new TargetCreatureWithPowerLessThanNumberOfCardsInYourGraveyard(this); + public boolean apply(ObjectSourcePlayer input, Game game) { + return Optional + .ofNullable(input.getPlayerId()) + .map(game::getPlayer) + .map(Player::getGraveyard) + .map(HashSet::size) + .filter(x -> input.getObject().getPower().getValue() < x) + .isPresent(); } } diff --git a/Mage.Sets/src/mage/cards/t/TemurAscendancy.java b/Mage.Sets/src/mage/cards/t/TemurAscendancy.java index 266e0613e78..4fa88b5809f 100644 --- a/Mage.Sets/src/mage/cards/t/TemurAscendancy.java +++ b/Mage.Sets/src/mage/cards/t/TemurAscendancy.java @@ -1,8 +1,6 @@ - package mage.cards.t; -import java.util.UUID; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -12,31 +10,37 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class TemurAscendancy extends CardImpl { - final private static FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature with power 4 or greater"); + final private static FilterPermanent filter = new FilterControlledCreaturePermanent("a creature you control with power 4 or greater"); + static { filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); } public TemurAscendancy(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{G}{U}{R}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}{U}{R}"); // Creatures you control have haste. - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield, new FilterControlledCreaturePermanent("Creatures")))); - + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + HasteAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_CREATURES + ))); + // Whenever a creature with power 4 or greater you control enters, you may draw a card. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), filter, true)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new DrawCardSourceControllerEffect(1), filter, true + )); } private TemurAscendancy(final TemurAscendancy card) { diff --git a/Mage.Sets/src/mage/cards/t/TemurCharm.java b/Mage.Sets/src/mage/cards/t/TemurCharm.java index bc5ccdaf423..37dd4b3203f 100644 --- a/Mage.Sets/src/mage/cards/t/TemurCharm.java +++ b/Mage.Sets/src/mage/cards/t/TemurCharm.java @@ -16,12 +16,15 @@ import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.TargetSpell; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author LevelX2 */ @@ -44,7 +47,7 @@ public final class TemurCharm extends CardImpl { effect.setText("It fights target creature you don't control"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - Target target = new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL); + Target target = new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL); this.getSpellAbility().addTarget(target); // Counter target spell unless its controller pays {3}. diff --git a/Mage.Sets/src/mage/cards/t/TemurWarShaman.java b/Mage.Sets/src/mage/cards/t/TemurWarShaman.java index 15f0ea0907c..0b9ded054cb 100644 --- a/Mage.Sets/src/mage/cards/t/TemurWarShaman.java +++ b/Mage.Sets/src/mage/cards/t/TemurWarShaman.java @@ -16,10 +16,13 @@ import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author LevelX2 */ @@ -37,7 +40,7 @@ public final class TemurWarShaman extends CardImpl { // Whenever a permanent you control is turned face up, if it is a creature, you may have it fight target creature you don't control. Ability ability = new TemurWarShamanTriggeredAbility(); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TenaciousTomeseeker.java b/Mage.Sets/src/mage/cards/t/TenaciousTomeseeker.java index a257eff3a7a..835e8e2547d 100644 --- a/Mage.Sets/src/mage/cards/t/TenaciousTomeseeker.java +++ b/Mage.Sets/src/mage/cards/t/TenaciousTomeseeker.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.BargainedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.hint.common.BargainCostWasPaidHint; import mage.abilities.keyword.BargainAbility; @@ -34,11 +33,7 @@ public final class TenaciousTomeseeker extends CardImpl { this.addAbility(new BargainAbility()); // When Tenacious Tomeseeker enters the battlefield, if it was bargained, return target instant or sorcery card from your graveyard to your hand. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()), - BargainedCondition.instance, "When {this} enters, if it was bargained, " + - "return target instant or sorcery card from your graveyard to your hand." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()).withInterveningIf(BargainedCondition.instance); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); this.addAbility(ability.addHint(BargainCostWasPaidHint.instance)); } diff --git a/Mage.Sets/src/mage/cards/t/TerritorialAllosaurus.java b/Mage.Sets/src/mage/cards/t/TerritorialAllosaurus.java index 2a761be939e..2ab55d1ebef 100644 --- a/Mage.Sets/src/mage/cards/t/TerritorialAllosaurus.java +++ b/Mage.Sets/src/mage/cards/t/TerritorialAllosaurus.java @@ -1,24 +1,21 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.FightTargetSourceEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class TerritorialAllosaurus extends CardImpl { @@ -34,14 +31,11 @@ public final class TerritorialAllosaurus extends CardImpl { this.addAbility(new KickerAbility("{2}{G}")); // When Territorial Allosaurus enters the battlefield, if it was kicked, it fights another target creature. - EntersBattlefieldTriggeredAbility ability - = new EntersBattlefieldTriggeredAbility(new FightTargetSourceEffect()); - Ability conditionalAbility = new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.ONCE, - "When {this} enters, if it was kicked, it fights another target creature."); - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - filter.add(AnotherPredicate.instance); - conditionalAbility.addTarget(new TargetCreaturePermanent(filter)); - this.addAbility(conditionalAbility); + Ability ability = new EntersBattlefieldTriggeredAbility(new FightTargetSourceEffect()) + .withInterveningIf(KickedCondition.ONCE) + .withRuleTextReplacement(true); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + this.addAbility(ability); } private TerritorialAllosaurus(final TerritorialAllosaurus card) { diff --git a/Mage.Sets/src/mage/cards/t/TerritorialBoar.java b/Mage.Sets/src/mage/cards/t/TerritorialBoar.java index 69fc58b3bc5..7d423f35c28 100644 --- a/Mage.Sets/src/mage/cards/t/TerritorialBoar.java +++ b/Mage.Sets/src/mage/cards/t/TerritorialBoar.java @@ -2,7 +2,7 @@ package mage.cards.t; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.VigilanceAbility; @@ -13,7 +13,7 @@ import mage.constants.ComparisonType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import java.util.UUID; @@ -24,7 +24,7 @@ import java.util.UUID; public final class TerritorialBoar extends CardImpl { private static final FilterPermanent filter - = new FilterCreaturePermanent("a creature with power 4 or greater"); + = new FilterControlledCreaturePermanent("a creature you control with power 4 or greater"); static { filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); @@ -38,7 +38,7 @@ public final class TerritorialBoar extends CardImpl { this.toughness = new MageInt(2); // Whenever a creature with power 4 or greater you control enters, Territorial Boar gets +1/+1 and gains vigilance until end of turn. - Ability ability = new EntersBattlefieldControlledTriggeredAbility(new BoostSourceEffect( + Ability ability = new EntersBattlefieldAllTriggeredAbility(new BoostSourceEffect( 1, 1, Duration.EndOfTurn ).setText("{this} gets +1/+1"), filter); ability.addEffect(new GainAbilitySourceEffect( diff --git a/Mage.Sets/src/mage/cards/t/TerritorialHammerskull.java b/Mage.Sets/src/mage/cards/t/TerritorialHammerskull.java index f03aa39f640..faabc50cb81 100644 --- a/Mage.Sets/src/mage/cards/t/TerritorialHammerskull.java +++ b/Mage.Sets/src/mage/cards/t/TerritorialHammerskull.java @@ -11,8 +11,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author TheElk801 @@ -28,7 +31,7 @@ public final class TerritorialHammerskull extends CardImpl { // Whenever Territorial Hammerskull attacks, tap target creature an opponent controls. Ability ability = new AttacksTriggeredAbility(new TapTargetEffect(), false); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TerritorialWitchstalker.java b/Mage.Sets/src/mage/cards/t/TerritorialWitchstalker.java index 15e0ca3a6d8..f67723fe5c9 100644 --- a/Mage.Sets/src/mage/cards/t/TerritorialWitchstalker.java +++ b/Mage.Sets/src/mage/cards/t/TerritorialWitchstalker.java @@ -1,31 +1,29 @@ package mage.cards.t; -import java.util.UUID; - import mage.MageInt; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.abilities.Ability; import mage.abilities.condition.common.FerociousCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderSourceEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.hint.common.FerociousHint; import mage.abilities.keyword.DefenderAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; +import java.util.UUID; + /** - * * @author Xanderhall */ public final class TerritorialWitchstalker extends CardImpl { public TerritorialWitchstalker(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); - + this.subtype.add(SubType.WOLF); this.power = new MageInt(2); this.toughness = new MageInt(3); @@ -34,16 +32,11 @@ public final class TerritorialWitchstalker extends CardImpl { this.addAbility(DefenderAbility.getInstance()); // At the beginning of combat on your turn, if you control a creature with power 4 or greater, Territorial Witchstalker gets +1/+0 until end of turn and can attack this turn as though it didn't have defender. - TriggeredAbility ability = new BeginningOfCombatTriggeredAbility(new BoostSourceEffect(1, 0, Duration.EndOfTurn)); - ability.addEffect(new CanAttackAsThoughItDidntHaveDefenderSourceEffect(Duration.EndOfTurn)); - ability.addHint(FerociousHint.instance); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - ability, - FerociousCondition.instance, - "At the beginning of combat on your turn, if you control a creature with power 4 or greater, " - + "{this} gets +1/+0 until end of turn and can attack this turn as though it didn't have defender" - )); - + Ability ability = new BeginningOfCombatTriggeredAbility( + new BoostSourceEffect(1, 0, Duration.EndOfTurn) + ).withInterveningIf(FerociousCondition.instance); + ability.addEffect(new CanAttackAsThoughItDidntHaveDefenderSourceEffect(Duration.EndOfTurn, "and")); + this.addAbility(ability.addHint(FerociousHint.instance)); } private TerritorialWitchstalker(final TerritorialWitchstalker card) { diff --git a/Mage.Sets/src/mage/cards/t/TerritoryForge.java b/Mage.Sets/src/mage/cards/t/TerritoryForge.java index 50eea890d86..a17768652fd 100644 --- a/Mage.Sets/src/mage/cards/t/TerritoryForge.java +++ b/Mage.Sets/src/mage/cards/t/TerritoryForge.java @@ -5,7 +5,6 @@ import mage.abilities.ActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.ExileTargetEffect; import mage.cards.Card; @@ -37,11 +36,8 @@ public final class TerritoryForge extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}{R}"); // When Territory Forge enters the battlefield, if you cast it, exile target artifact or land. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ExileTargetEffect().setToSourceExileZone(true)), - CastFromEverywhereSourceCondition.instance, - "When {this} enters, if you cast it, exile target artifact or land." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetEffect().setToSourceExileZone(true)) + .withInterveningIf(CastFromEverywhereSourceCondition.instance); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); @@ -89,7 +85,7 @@ class TerritoryForgeStaticEffect extends ContinuousEffectImpl { } for (Card card : exileZone.getCards(game)) { for (Ability ability : card.getAbilities(game)) { - if (ability.isActivatedAbility()){ + if (ability.isActivatedAbility()) { ActivatedAbility copyAbility = (ActivatedAbility) ability.copy(); permanent.addAbility(copyAbility, source.getSourceId(), game, true); } diff --git a/Mage.Sets/src/mage/cards/t/Terror.java b/Mage.Sets/src/mage/cards/t/Terror.java index ff4dfbb1d25..50616805905 100644 --- a/Mage.Sets/src/mage/cards/t/Terror.java +++ b/Mage.Sets/src/mage/cards/t/Terror.java @@ -10,6 +10,7 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class Terror extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}"); // Destroy target nonartifact, nonblack creature. It can't be regenerated. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(FILTER)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER)); this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); } diff --git a/Mage.Sets/src/mage/cards/t/TestOfEndurance.java b/Mage.Sets/src/mage/cards/t/TestOfEndurance.java index de2584e22eb..4ba3ab56648 100644 --- a/Mage.Sets/src/mage/cards/t/TestOfEndurance.java +++ b/Mage.Sets/src/mage/cards/t/TestOfEndurance.java @@ -1,30 +1,29 @@ - package mage.cards.t; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.LifeCompareCondition; import mage.abilities.effects.common.WinGameSourceControllerEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.game.Game; +import mage.constants.ComparisonType; +import mage.constants.TargetController; + +import java.util.UUID; /** - * * @author fireshoes */ public final class TestOfEndurance extends CardImpl { + private static final Condition condition = new LifeCompareCondition(TargetController.YOU, ComparisonType.OR_GREATER, 50); + public TestOfEndurance(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); // At the beginning of your upkeep, if you have 50 or more life, you win the game. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new FiftyOrMoreLifeCondition(), "At the beginning of your upkeep, if you have 50 or more life, you win the game.")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect()).withInterveningIf(condition)); } private TestOfEndurance(final TestOfEndurance card) { @@ -36,12 +35,3 @@ public final class TestOfEndurance extends CardImpl { return new TestOfEndurance(this); } } - - -class FiftyOrMoreLifeCondition implements Condition { - - @Override - public boolean apply(Game game, Ability source) { - return game.getPlayer(source.getControllerId()).getLife() >= 50; - } -} diff --git a/Mage.Sets/src/mage/cards/t/TetsuoImperialChampion.java b/Mage.Sets/src/mage/cards/t/TetsuoImperialChampion.java index 5452d742939..7f250f63ebf 100644 --- a/Mage.Sets/src/mage/cards/t/TetsuoImperialChampion.java +++ b/Mage.Sets/src/mage/cards/t/TetsuoImperialChampion.java @@ -5,11 +5,9 @@ import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.EquippedSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.GreatestAmongPermanentsValue; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.cost.CastFromHandForFreeEffect; -import mage.abilities.hint.Hint; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -40,10 +38,9 @@ public final class TetsuoImperialChampion extends CardImpl { } static final GreatestAmongPermanentsValue xValue = new GreatestAmongPermanentsValue(GreatestAmongPermanentsValue.Quality.ManaValue, filterEquipment); - private static final Hint hint = xValue.getHint(); private static final FilterCard filter = new FilterInstantOrSorceryCard( "an instant or sorcery spell from your hand with mana value " + - "less than or equal to the highest mana value among Equipment attached to {this}" + "less than or equal to the greatest mana value among Equipment attached to {this}" ); static { @@ -61,19 +58,16 @@ public final class TetsuoImperialChampion extends CardImpl { // Whenever Tetsuo, Imperial Champion attacks, if it's equipped, choose one -- // * Tetsuo deals damage equal to the greatest mana value among Equipment attached to it to any target. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new DamageTargetEffect( - xValue, "it" - ).setText("{this} deals damage equal to the greatest mana value " + - "among Equipment attached to it to any target") - ).setTriggerPhrase("Whenever {this} attacks, if it's equipped, "), - EquippedSourceCondition.instance, null - ); + Ability ability = new AttacksTriggeredAbility( + new DamageTargetEffect(xValue, "it") + .setText("{this} deals damage equal to the greatest mana value " + + "among Equipment attached to it to any target") + ).withInterveningIf(EquippedSourceCondition.instance); ability.addTarget(new TargetAnyTarget()); // * You may cast an instant or sorcery spell from your hand with mana value less than or equal to the greatest mana value among Equipment attached to Tetsuo without paying its mana cost. ability.addMode(new Mode(new CastFromHandForFreeEffect(filter))); - this.addAbility(ability); + this.addAbility(ability.addHint(xValue.getHint())); } private TetsuoImperialChampion(final TetsuoImperialChampion card) { @@ -94,4 +88,4 @@ enum TetsuoImperialChampionPredicate implements ObjectSourcePlayerPredicate("{U}{B}{B}{R}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(creatureFilter)); + ability.addTarget(new TargetPermanent(creatureFilter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TezzeretCruelCaptain.java b/Mage.Sets/src/mage/cards/t/TezzeretCruelCaptain.java new file mode 100644 index 00000000000..6f00f74a9b7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TezzeretCruelCaptain.java @@ -0,0 +1,99 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GetEmblemEffect; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterArtifactCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.command.emblems.TezzeretCruelCaptainEmblem; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInLibrary; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TezzeretCruelCaptain extends CardImpl { + + private static final FilterCard filter = new FilterArtifactCard("an artifact card with mana value 1 or less"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 2)); + } + + public TezzeretCruelCaptain(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{3}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.TEZZERET); + this.setStartingLoyalty(4); + + // Whenever an artifact you control enters, put a loyalty counter on Tezzeret. + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new AddCountersSourceEffect(CounterType.LOYALTY.createInstance()), + StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT + )); + + // 0: Untap target artifact or creature. If it's an artifact creature, put a +1/+1 counter on it. + Ability ability = new LoyaltyAbility(new UntapTargetEffect(), 0); + ability.addEffect(new TezzeretCruelCaptainEffect()); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE)); + this.addAbility(ability); + + // -3: Search your library for an artifact card with mana value 1 or less, reveal it, put it in your hand, then shuffle. + this.addAbility(new LoyaltyAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true), -3)); + + // -7: You get an emblem with "At the beginning of combat on your turn, put three +1/+1 counters on target artifact you control. If it's not a creature, it becomes a 0/0 Robot artifact creature." + this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new TezzeretCruelCaptainEmblem()), -7)); + } + + private TezzeretCruelCaptain(final TezzeretCruelCaptain card) { + super(card); + } + + @Override + public TezzeretCruelCaptain copy() { + return new TezzeretCruelCaptain(this); + } +} + +class TezzeretCruelCaptainEffect extends OneShotEffect { + + TezzeretCruelCaptainEffect() { + super(Outcome.Benefit); + staticText = "If it's an artifact creature, put a +1/+1 counter on it"; + } + + private TezzeretCruelCaptainEffect(final TezzeretCruelCaptainEffect effect) { + super(effect); + } + + @Override + public TezzeretCruelCaptainEffect copy() { + return new TezzeretCruelCaptainEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return Optional + .ofNullable(this.getTargetPointer().getFirst(game, source)) + .map(game::getPermanent) + .filter(permanent -> permanent.isArtifact(game) && permanent.isCreature(game)) + .filter(permanent -> permanent.addCounters(CounterType.P1P1.createInstance(), source, game)) + .isPresent(); + } +} diff --git a/Mage.Sets/src/mage/cards/t/ThatWhichWasTaken.java b/Mage.Sets/src/mage/cards/t/ThatWhichWasTaken.java index 88a616a5cac..b0e872417dd 100644 --- a/Mage.Sets/src/mage/cards/t/ThatWhichWasTaken.java +++ b/Mage.Sets/src/mage/cards/t/ThatWhichWasTaken.java @@ -1,7 +1,6 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -16,12 +15,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SuperType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.TargetPermanent; +import java.util.UUID; + /** @@ -29,7 +29,7 @@ import mage.target.TargetPermanent; */ public final class ThatWhichWasTaken extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("permanent other than That Which Was Taken"); + private static final FilterPermanent filter = new FilterPermanent("permanent other than {this}"); private static final FilterPermanent filterIndestructible = new FilterPermanent("Each permanent with a divinity counter on it"); diff --git a/Mage.Sets/src/mage/cards/t/ThaumaticCompass.java b/Mage.Sets/src/mage/cards/t/ThaumaticCompass.java index 9775d9890cd..9f87ab86bfc 100644 --- a/Mage.Sets/src/mage/cards/t/ThaumaticCompass.java +++ b/Mage.Sets/src/mage/cards/t/ThaumaticCompass.java @@ -1,33 +1,36 @@ - package mage.cards.t; -import java.util.UUID; - import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.abilities.hint.common.LandsYouControlHint; import mage.abilities.keyword.TransformAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.filter.common.FilterLandPermanent; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** * @author TheElk801 */ public final class ThaumaticCompass extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterLandPermanent("you control seven or more lands"), + ComparisonType.MORE_THAN, 6, true + ); + public ThaumaticCompass(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); this.secondSideCardClazz = mage.cards.s.SpiresOfOrazca.class; @@ -41,11 +44,8 @@ public final class ThaumaticCompass extends CardImpl { // At the beginning of your end step, if you control seven or more lands, transform Thaumatic Compass. this.addAbility(new TransformAbility()); - TriggeredAbility ability2 = new BeginningOfEndStepTriggeredAbility(new TransformSourceEffect()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - ability2, - new PermanentsOnTheBattlefieldCondition(new FilterLandPermanent(), ComparisonType.MORE_THAN, 6, true), - "At the beginning of your end step, if you control seven or more lands, transform {this}.")); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new TransformSourceEffect()) + .withInterveningIf(condition).addHint(LandsYouControlHint.instance)); } private ThaumaticCompass(final ThaumaticCompass card) { diff --git a/Mage.Sets/src/mage/cards/t/TheAbyss.java b/Mage.Sets/src/mage/cards/t/TheAbyss.java index 6dd1e11a16b..be31f6b28fa 100644 --- a/Mage.Sets/src/mage/cards/t/TheAbyss.java +++ b/Mage.Sets/src/mage/cards/t/TheAbyss.java @@ -1,35 +1,42 @@ - package mage.cards.t; -import java.util.UUID; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; -import mage.game.events.GameEvent; -import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; +import mage.target.targetpointer.FirstTargetPointer; + +import java.util.UUID; /** - * * @author emerald000 */ public final class TheAbyss extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent("nonartifact creature that player controls of their choice"); + public TheAbyss(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}"); this.supertype.add(SuperType.WORLD); // At the beginning of each player's upkeep, destroy target nonartifact creature that player controls of their choice. It can't be regenerated. - this.addAbility(new TheAbyssTriggeredAbility()); + Ability ability = new BeginningOfUpkeepTriggeredAbility(TargetController.EACH_PLAYER, + new DestroyTargetEffect(true), false).withTargetPointerSet(true); + ability.addTarget(new TargetPermanent(filter)); // Only used for text generation + ability.setTargetAdjuster(TheAbyssTargetAdjuster.instance); + this.addAbility(ability); } private TheAbyss(final TheAbyss card) { @@ -42,45 +49,25 @@ public final class TheAbyss extends CardImpl { } } -class TheAbyssTriggeredAbility extends TriggeredAbilityImpl { +enum TheAbyssTargetAdjuster implements TargetAdjuster { + instance; - TheAbyssTriggeredAbility() { - super(Zone.BATTLEFIELD, new DestroyTargetEffect(true), false); - } - - private TheAbyssTriggeredAbility(final TheAbyssTriggeredAbility ability) { - super(ability); + private static final FilterPermanent filter + = new FilterCreaturePermanent("nonartifact creature that player controls of their choice"); + static { + filter.add(Predicates.not(CardType.ARTIFACT.getPredicate())); } @Override - public TheAbyssTriggeredAbility copy() { - return new TheAbyssTriggeredAbility(this); - } + public void adjustTargets(Ability ability, Game game) { + UUID playerId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability); + ability.getTargets().clear(); + ability.getAllEffects().setTargetPointer(new FirstTargetPointer()); - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Player player = game.getPlayer(event.getPlayerId()); - if (player != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("nonartifact creature you control"); - filter.add(Predicates.not(CardType.ARTIFACT.getPredicate())); - filter.add(new ControllerIdPredicate(player.getId())); - Target target = new TargetCreaturePermanent(filter); - target.setAbilityController(getControllerId()); - target.setTargetController(player.getId()); - this.getTargets().clear(); - this.getTargets().add(target); - return true; - } - return false; - } - - @Override - public String getRule() { - return "At the beginning of each player's upkeep, destroy target nonartifact creature that player controls of their choice. It can't be regenerated."; + FilterPermanent adjustedFilter = filter.copy(); + adjustedFilter.add(new ControllerIdPredicate(playerId)); + Target newTarget = new TargetPermanent(adjustedFilter); + newTarget.setTargetController(playerId); + ability.addTarget(newTarget); } } diff --git a/Mage.Sets/src/mage/cards/t/TheAesirEscapeValhalla.java b/Mage.Sets/src/mage/cards/t/TheAesirEscapeValhalla.java index 0095d30b9ae..59e83c71b2d 100644 --- a/Mage.Sets/src/mage/cards/t/TheAesirEscapeValhalla.java +++ b/Mage.Sets/src/mage/cards/t/TheAesirEscapeValhalla.java @@ -1,15 +1,13 @@ package mage.cards.t; -import java.util.UUID; - import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SagaAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; -import mage.constants.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.*; import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.ExileZone; @@ -20,6 +18,8 @@ import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetControlledCreaturePermanent; import mage.util.CardUtil; +import java.util.UUID; + /** * * @author Grath @@ -140,7 +140,7 @@ class TheAesirEscapeValhallaThreeEffect extends OneShotEffect { TheAesirEscapeValhallaThreeEffect() { super(Outcome.Neutral); - staticText = "Return The Aesir Escape Valhalla and the exiled card to their owner's hand."; + staticText = "Return {this} and the exiled card to their owner's hand."; } private TheAesirEscapeValhallaThreeEffect(final TheAesirEscapeValhallaThreeEffect effect) { diff --git a/Mage.Sets/src/mage/cards/t/TheApprenticesFolly.java b/Mage.Sets/src/mage/cards/t/TheApprenticesFolly.java index d5c884bddb4..36ae2a78dd1 100644 --- a/Mage.Sets/src/mage/cards/t/TheApprenticesFolly.java +++ b/Mage.Sets/src/mage/cards/t/TheApprenticesFolly.java @@ -17,7 +17,7 @@ import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -53,7 +53,7 @@ public final class TheApprenticesFolly extends CardImpl { .setText("choose target nontoken creature you control that doesn't have the same name as a " + "token you control. Create a token that's a copy of it, except it isn't legendary, " + "is a Reflection in addition to its other types, and has haste"), - new TargetControlledCreaturePermanent(filter) + new TargetPermanent(filter) ); // III -- Sacrifice all Reflections you control. @@ -88,4 +88,4 @@ enum TheApprenticesFollyPredicate implements ObjectSourcePlayerPredicate { } } -class TheLordOfPainTriggeredAbility extends SpellCastAllTriggeredAbility { - private static final FilterSpell filter = new FilterSpell("their first spell each turn"); - - static { - filter.add(TheLordOfPainPredicate.instance); - } - - public TheLordOfPainTriggeredAbility() { - super(new TheLordOfPainEffect(), filter, false, SetTargetPointer.PLAYER); - } - - protected TheLordOfPainTriggeredAbility(final TheLordOfPainTriggeredAbility ability) { - super(ability); - } +enum TheLordOfPainTargetAdjuster implements TargetAdjuster { + instance; @Override - public TheLordOfPainTriggeredAbility copy() { - return new TheLordOfPainTriggeredAbility(this); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (super.checkTrigger(event, game)) { - Player controller = game.getPlayer(getControllerId()); - Spell spell = (Spell)getEffects().get(0).getValue("spellCast"); - if (controller != null) { - FilterPlayer filter2 = new FilterPlayer("another target player"); - filter2.add(Predicates.not(new MageObjectReferencePredicate(spell.getControllerId(), game))); - TargetPlayer target = new TargetPlayer(1, 1, false, filter2); - controller.choose(Outcome.Damage, target, this, game); - getEffects().setTargetPointer(new FixedTarget(target.getFirstTarget())); - return true; - } - } - return false; + public void adjustTargets(Ability ability, Game game) { + UUID opponentId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability); + ability.getTargets().clear(); + ability.getAllEffects().setTargetPointer(new FirstTargetPointer()); + FilterPlayer filter = new FilterPlayer("another target player"); + filter.add(Predicates.not(new PlayerIdPredicate(opponentId))); + Target newTarget = new TargetPlayer(filter); + ability.addTarget(newTarget); } } -class TheLordOfPainEffect extends OneShotEffect { - - TheLordOfPainEffect() { - super(Outcome.Benefit); - staticText = "choose another target player. {this} deals damage equal to that spell's mana value to the chosen player"; - } - - private TheLordOfPainEffect(final TheLordOfPainEffect effect) { - super(effect); - } +enum TheLordOfPainValue implements DynamicValue { + instance; @Override - public TheLordOfPainEffect copy() { - return new TheLordOfPainEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Spell spell = (Spell)this.getValue("spellCast"); - if (spell != null) { - int cost = spell.getManaValue(); - Player target = game.getPlayer(getTargetPointer().getFirst(game, source)); - if (target != null) { - target.damage(cost, source.getSourceId(), source, game); - return true; - } + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Object spell = effect.getValue("spellCast"); + if (spell instanceof Spell) { + return ((Spell) spell).getManaValue(); } - return false; } + return 0; + } + + @Override + public TheLordOfPainValue copy() { + return instance; + } + + @Override + public String getMessage() { + return "that spell's mana value"; + } } diff --git a/Mage.Sets/src/mage/cards/t/TheMyriadPools.java b/Mage.Sets/src/mage/cards/t/TheMyriadPools.java index 7d9e8b3e7f8..bcde9f4288f 100644 --- a/Mage.Sets/src/mage/cards/t/TheMyriadPools.java +++ b/Mage.Sets/src/mage/cards/t/TheMyriadPools.java @@ -1,38 +1,39 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; +import mage.abilities.common.CastSpellPaidBySourceTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CopyEffect; import mage.abilities.mana.BlueManaAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.SuperType; -import mage.constants.WatcherScope; -import mage.constants.Zone; +import mage.filter.FilterSpell; import mage.filter.StaticFilters; +import mage.filter.predicate.mageobject.PermanentPredicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; import mage.game.stack.Spell; import mage.players.Player; import mage.target.TargetPermanent; -import mage.target.targetpointer.FixedTarget; -import mage.watchers.Watcher; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public class TheMyriadPools extends CardImpl { + private static final FilterSpell filter = new FilterSpell("a permanent spell"); + + static { + filter.add(PermanentPredicate.instance); + } + public TheMyriadPools(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.LAND}, null); this.supertype.add(SuperType.LEGENDARY); @@ -41,11 +42,12 @@ public class TheMyriadPools extends CardImpl { this.nightCard = true; // {T}: Add {U}. - Ability ability = new BlueManaAbility(); - // Whenever you cast a permanent spell using mana produced by The Myriad Pools, up to one other target permanent you control becomes a copy of that spell until end of turn. - this.addAbility(ability, new TheMyriadPoolsWatcher(ability.getOriginalId().toString())); - this.addAbility(new TheMyriadPoolsTriggeredAbility()); + this.addAbility(new BlueManaAbility()); + // Whenever you cast a permanent spell using mana produced by The Myriad Pools, up to one other target permanent you control becomes a copy of that spell until end of turn. + Ability ability = new CastSpellPaidBySourceTriggeredAbility(new TheMyriadPoolsCopyEffect(), filter, false); + ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_TARGET_PERMANENT)); + this.addAbility(ability); } private TheMyriadPools(final TheMyriadPools card) { @@ -58,90 +60,11 @@ public class TheMyriadPools extends CardImpl { } } -class TheMyriadPoolsWatcher extends Watcher { - - private UUID permanentId = UUID.randomUUID(); - private final String originalId; - - public TheMyriadPoolsWatcher(String originalId) { - super(WatcherScope.CARD); - this.originalId = originalId; - } - - public boolean manaUsedToCastPermanentPart(UUID id) { - return permanentId.equals(id); - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.MANA_PAID) { - if (event.getData() != null - && event.getData().equals(originalId)) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null - && spell.isPermanent(game)) { - Card card = spell.getCard(); - permanentId = card.getId(); - } - } - } - } - - @Override - public void reset() { - super.reset(); - } -} - -class TheMyriadPoolsTriggeredAbility extends TriggeredAbilityImpl { - - public TheMyriadPoolsTriggeredAbility() { - super(Zone.BATTLEFIELD, new TheMyriadPoolsCopyEffect()); - } - - private TheMyriadPoolsTriggeredAbility(final TheMyriadPoolsTriggeredAbility ability) { - super(ability); - } - - @Override - public TheMyriadPoolsTriggeredAbility copy() { - return new TheMyriadPoolsTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.SPELL_CAST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - TheMyriadPoolsWatcher watcher = game.getState().getWatcher(TheMyriadPoolsWatcher.class, this.getSourceId()); - if (watcher != null - && watcher.manaUsedToCastPermanentPart(event.getSourceId())) { - Spell spell = game.getSpell(event.getSourceId()); - if (spell != null - && spell.isControlledBy(getControllerId())) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getSourceId())); - } - return true; - } - } - return false; - } - - @Override - public String getRule() { - return "Whenever you cast a permanent spell using mana produced by {this}, up to one other target permanent you control becomes a copy of that spell until end of turn."; - } - -} - class TheMyriadPoolsCopyEffect extends OneShotEffect { TheMyriadPoolsCopyEffect() { super(Outcome.Neutral); - this.staticText = "copy of card on stack"; + this.staticText = "up to one other target permanent you control becomes a copy of that spell until end of turn"; } private TheMyriadPoolsCopyEffect(final TheMyriadPoolsCopyEffect effect) { @@ -155,28 +78,18 @@ class TheMyriadPoolsCopyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent targetPermanentToCopyTo = null; + Permanent targetPermanentToCopyTo = game.getPermanent(getTargetPointer().getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { + Object spell = getValue("spellCast"); + if (controller == null || targetPermanentToCopyTo == null || !(spell instanceof Spell)) { return false; } - TargetPermanent target = new TargetPermanent(0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_PERMANENT, false); - if (controller.choose(Outcome.Neutral, target, source, game)) { - targetPermanentToCopyTo = game.getPermanent(target.getFirstTarget()); - } - Card copyFromCardOnStack = game.getCard(getTargetPointer().getFirst(game, source)); - Permanent newBluePrint = null; - if (targetPermanentToCopyTo != null) { - if (copyFromCardOnStack != null) { - newBluePrint = new PermanentCard(copyFromCardOnStack, source.getControllerId(), game); - newBluePrint.assignNewId(); - CopyEffect copyEffect = new CopyEffect(Duration.EndOfTurn, newBluePrint, targetPermanentToCopyTo.getId()); - Ability newAbility = source.copy(); - copyEffect.init(newAbility, game); - game.addEffect(copyEffect, newAbility); - } - return true; - } - return false; + Permanent newBluePrint = new PermanentCard(((Spell)spell).getCard(), source.getControllerId(), game); + newBluePrint.assignNewId(); + CopyEffect copyEffect = new CopyEffect(Duration.EndOfTurn, newBluePrint, targetPermanentToCopyTo.getId()); + Ability newAbility = source.copy(); + copyEffect.init(newAbility, game); + game.addEffect(copyEffect, newAbility); + return true; } } diff --git a/Mage.Sets/src/mage/cards/t/TheNinthDoctor.java b/Mage.Sets/src/mage/cards/t/TheNinthDoctor.java index 9b791bfdeb7..eaa7ab95595 100644 --- a/Mage.Sets/src/mage/cards/t/TheNinthDoctor.java +++ b/Mage.Sets/src/mage/cards/t/TheNinthDoctor.java @@ -2,14 +2,16 @@ package mage.cards.t; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.condition.Condition; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.InspiredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.game.Game; import mage.game.turn.TurnMod; import mage.game.turn.UpkeepStep; @@ -21,8 +23,6 @@ import java.util.UUID; */ public final class TheNinthDoctor extends CardImpl { - private static final Condition condition = new IsStepCondition(PhaseStep.UNTAP); - public TheNinthDoctor(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{R}"); this.supertype.add(SuperType.LEGENDARY); @@ -35,7 +35,7 @@ public final class TheNinthDoctor extends CardImpl { // Into the TARDIS — Whenever The Ninth Doctor becomes untapped during your untap step, you get an additional upkeep step after this step. this.addAbility(new InspiredAbility(new TheNinthDoctorEffect(), false, false) - .withTriggerCondition(condition) + .withTriggerCondition(IsStepCondition.getMyUpkeep()) .withFlavorWord("Into the TARDIS")); } diff --git a/Mage.Sets/src/mage/cards/t/TheOneRing.java b/Mage.Sets/src/mage/cards/t/TheOneRing.java index d587e77731a..3f002df56fc 100644 --- a/Mage.Sets/src/mage/cards/t/TheOneRing.java +++ b/Mage.Sets/src/mage/cards/t/TheOneRing.java @@ -1,12 +1,10 @@ package mage.cards.t; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CountersSourceCount; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -15,6 +13,7 @@ import mage.abilities.effects.common.continuous.GainAbilityControllerEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.IndestructibleAbility; import mage.abilities.keyword.ProtectionFromEverythingAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -40,17 +39,12 @@ public final class TheOneRing extends CardImpl { this.addAbility(IndestructibleAbility.getInstance()); // When The One Ring enters the battlefield, if you cast it, you gain protection from everything until your next turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new GainAbilityControllerEffect( - new ProtectionFromEverythingAbility(), Duration.UntilYourNextTurn - )), CastFromEverywhereSourceCondition.instance, "When {this} enters, " + - "if you cast it, you gain protection from everything until your next turn." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new GainAbilityControllerEffect(new ProtectionFromEverythingAbility(), Duration.UntilYourNextTurn) + ).withInterveningIf(CastFromEverywhereSourceCondition.instance)); // At the beginning of your upkeep, you lose 1 life for each burden counter on The One Ring. - this.addAbility(new BeginningOfUpkeepTriggeredAbility( - new LoseLifeSourceControllerEffect(xValue) - )); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new LoseLifeSourceControllerEffect(xValue))); // {T}: Put a burden counter on The One Ring, then draw a card for each burden counter on The One Ring. Ability ability = new SimpleActivatedAbility( diff --git a/Mage.Sets/src/mage/cards/t/TheOzolith.java b/Mage.Sets/src/mage/cards/t/TheOzolith.java index 54fece77667..5e2df719542 100644 --- a/Mage.Sets/src/mage/cards/t/TheOzolith.java +++ b/Mage.Sets/src/mage/cards/t/TheOzolith.java @@ -1,11 +1,10 @@ package mage.cards.t; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.common.LeavesBattlefieldAllTriggeredAbility; import mage.abilities.condition.common.SourceHasCountersCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -36,12 +35,9 @@ public final class TheOzolith extends CardImpl { this.addAbility(new TheOzolithTriggeredAbility()); // At the beginning of combat on your turn, if The Ozolith has counters on it, you may move all counters from The Ozolith onto target creature. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility( - new TheOzolithMoveCountersEffect(), true - ), SourceHasCountersCondition.instance, "At the beginning of combat on your turn, " + - "if {this} has counters on it, you may move all counters from {this} onto target creature." - ); + Ability ability = new BeginningOfCombatTriggeredAbility( + new TheOzolithMoveCountersEffect(), true + ).withInterveningIf(SourceHasCountersCondition.instance); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } @@ -126,6 +122,7 @@ class TheOzolithMoveCountersEffect extends OneShotEffect { TheOzolithMoveCountersEffect() { super(Outcome.Benefit); + staticText = "you may move all counters from {this} onto target creature"; } private TheOzolithMoveCountersEffect(final TheOzolithMoveCountersEffect effect) { diff --git a/Mage.Sets/src/mage/cards/t/ThePrydwenSteelFlagship.java b/Mage.Sets/src/mage/cards/t/ThePrydwenSteelFlagship.java index 153f2d8d125..f800f0fbea7 100644 --- a/Mage.Sets/src/mage/cards/t/ThePrydwenSteelFlagship.java +++ b/Mage.Sets/src/mage/cards/t/ThePrydwenSteelFlagship.java @@ -1,29 +1,30 @@ package mage.cards.t; -import java.util.UUID; - import mage.MageInt; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterArtifactPermanent; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledArtifactPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.permanent.token.ThePrydwenSteelFlagshipHumanKnightToken; import mage.watchers.common.ArtifactEnteredControllerWatcher; +import java.util.UUID; + /** * @author Cguy7777 */ public final class ThePrydwenSteelFlagship extends CardImpl { - private static final FilterArtifactPermanent filter = new FilterArtifactPermanent("another nontoken artifact"); + private static final FilterPermanent filter = new FilterControlledArtifactPermanent("another nontoken artifact you control"); static { filter.add(AnotherPredicate.instance); @@ -44,14 +45,12 @@ public final class ThePrydwenSteelFlagship extends CardImpl { // Whenever another nontoken artifact you control enters, // create a 2/2 white Human Knight creature token with // "This creature gets +2/+2 as long as an artifact entered the battlefield under your control this turn." - this.addAbility( - new EntersBattlefieldControlledTriggeredAbility( - new CreateTokenEffect(new ThePrydwenSteelFlagshipHumanKnightToken()), filter), - new ArtifactEnteredControllerWatcher()); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new CreateTokenEffect(new ThePrydwenSteelFlagshipHumanKnightToken()), filter + ), new ArtifactEnteredControllerWatcher()); // Crew 2 this.addAbility(new CrewAbility(2)); - } private ThePrydwenSteelFlagship(final ThePrydwenSteelFlagship card) { diff --git a/Mage.Sets/src/mage/cards/t/TheRani.java b/Mage.Sets/src/mage/cards/t/TheRani.java index ee7a0524a4d..0b8a8845d3f 100644 --- a/Mage.Sets/src/mage/cards/t/TheRani.java +++ b/Mage.Sets/src/mage/cards/t/TheRani.java @@ -14,10 +14,13 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.GoadedPredicate; import mage.game.Game; import mage.game.permanent.token.MarkOfTheRaniToken; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_ANOTHER_CREATURE; + /** * * @author grimreap124 @@ -42,7 +45,7 @@ public final class TheRani extends CardImpl { // Whenever The Rani enters the battlefield or attacks, create a red Aura enchantment token named Mark of the Rani attached to another target creature. That token has enchant creature and "Enchanted creature gets +2/+2 and is goaded." Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility( new TheRaniEffect()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_CREATURE)); this.addAbility(ability); // Whenever a goaded creature deals combat damage to one of your opponents, investigate. diff --git a/Mage.Sets/src/mage/cards/t/TheRevelationsOfEzio.java b/Mage.Sets/src/mage/cards/t/TheRevelationsOfEzio.java index cc52367e98d..8be85eeb84c 100644 --- a/Mage.Sets/src/mage/cards/t/TheRevelationsOfEzio.java +++ b/Mage.Sets/src/mage/cards/t/TheRevelationsOfEzio.java @@ -21,6 +21,7 @@ import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -52,7 +53,7 @@ public final class TheRevelationsOfEzio extends CardImpl { this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_I, ability -> { ability.addEffect(new DestroyTargetEffect()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); } ); // II -- Whenever an Assassin you control attacks this turn, put a +1/+1 counter on it. diff --git a/Mage.Sets/src/mage/cards/t/TheScorpionGod.java b/Mage.Sets/src/mage/cards/t/TheScorpionGod.java index 8a03884f9e0..67ecd405fac 100644 --- a/Mage.Sets/src/mage/cards/t/TheScorpionGod.java +++ b/Mage.Sets/src/mage/cards/t/TheScorpionGod.java @@ -29,9 +29,12 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * * @author spjspj @@ -51,7 +54,7 @@ public final class TheScorpionGod extends CardImpl { // {1}{B}{R}: Put a -1/-1 counter on another target creature. Ability ability = new SimpleActivatedAbility(new AddCountersTargetEffect(CounterType.M1M1.createInstance()), new ManaCostsImpl<>("{1}{B}{R}")); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); // When The Scorpion God dies, return it to its owner's hand at the beginning of the next end step. diff --git a/Mage.Sets/src/mage/cards/t/TheSeaDevils.java b/Mage.Sets/src/mage/cards/t/TheSeaDevils.java index 09a21f3471d..213074a76eb 100644 --- a/Mage.Sets/src/mage/cards/t/TheSeaDevils.java +++ b/Mage.Sets/src/mage/cards/t/TheSeaDevils.java @@ -21,6 +21,7 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.permanent.token.AlienSalamanderToken; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; import mage.util.GameLog; @@ -106,7 +107,7 @@ class TheSeaDevilsTrigger extends DelayedTriggeredAbility { this.getTargets().clear(); FilterCreaturePermanent filterTarget = new FilterCreaturePermanent("creature " + player.getName() + " controls"); filterTarget.add(new ControllerIdPredicate(player.getId())); - this.addTarget(new TargetCreaturePermanent(filterTarget)); + this.addTarget(new TargetPermanent(filterTarget)); int amount = event.getAmount(); @@ -175,4 +176,4 @@ class TheSeaDevilsEffect extends OneShotEffect { target.damage(amount, salamander.getId(), source, game); return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/t/TheSeedcore.java b/Mage.Sets/src/mage/cards/t/TheSeedcore.java index 3f84b2fb9a2..de8b134f54c 100644 --- a/Mage.Sets/src/mage/cards/t/TheSeedcore.java +++ b/Mage.Sets/src/mage/cards/t/TheSeedcore.java @@ -7,7 +7,7 @@ import mage.abilities.Ability; import mage.abilities.condition.common.CorruptedCondition; import mage.abilities.costs.Cost; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.mana.ColorlessManaAbility; import mage.abilities.mana.ConditionalAnyColorManaAbility; @@ -20,6 +20,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.filter.predicate.mageobject.ToughnessPredicate; import mage.game.Game; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -43,16 +44,16 @@ public final class TheSeedcore extends CardImpl { // {T}: Add {C}. this.addAbility(new ColorlessManaAbility()); + // {T}: Add one mana of any color. Spend this mana only to cast Phyrexian creature spells. this.addAbility(new ConditionalAnyColorManaAbility(new TapSourceCost(), 1, new TheSeedcoreManaBuilder(), true)); + // Corrupted -- {T}: Target 1/1 creature gets +2/+1 until end of turn. Activate only if an opponent has three or more poison counters. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, + Ability ability = new ActivateIfConditionActivatedAbility( new BoostTargetEffect(2, 1, Duration.EndOfTurn), - new TapSourceCost(), - CorruptedCondition.instance + new TapSourceCost(), CorruptedCondition.instance ).setAbilityWord(AbilityWord.CORRUPTED).addHint(CorruptedCondition.getHint()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } @@ -103,4 +104,3 @@ class TheSeedcoreManaCondition extends CreatureCastManaCondition { return false; } } - diff --git a/Mage.Sets/src/mage/cards/t/TheSeriema.java b/Mage.Sets/src/mage/cards/t/TheSeriema.java new file mode 100644 index 00000000000..de7229e4af5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheSeriema.java @@ -0,0 +1,74 @@ +package mage.cards.t; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.StationAbility; +import mage.abilities.keyword.StationLevelAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreatureCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheSeriema extends CardImpl { + + private static final FilterCard filter = new FilterCreatureCard("legendary creature card"); + private static final FilterPermanent filter2 = new FilterCreaturePermanent("tapped legendary creatures"); + + static { + filter.add(SuperType.LEGENDARY.getPredicate()); + filter2.add(TappedPredicate.TAPPED); + filter2.add(SuperType.LEGENDARY.getPredicate()); + } + + public TheSeriema(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{W}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SPACECRAFT); + + // When The Seriema enters, search your library for a legendary creature card, reveal it, put it into your hand, then shuffle. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true) + )); + + // Station + this.addAbility(new StationAbility()); + + // STATION 7+ + // Flying + // Other tapped legendary creatures you control have indestructible. + // 5/5 + this.addAbility(new StationLevelAbility(7) + .withLevelAbility(FlyingAbility.getInstance()) + .withLevelAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield, filter2, true + ))) + .withPT(5, 5)); + } + + private TheSeriema(final TheSeriema card) { + super(card); + } + + @Override + public TheSeriema copy() { + return new TheSeriema(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheTricksterGodsHeist.java b/Mage.Sets/src/mage/cards/t/TheTricksterGodsHeist.java index 6edf1d308f4..a4eb35e9231 100644 --- a/Mage.Sets/src/mage/cards/t/TheTricksterGodsHeist.java +++ b/Mage.Sets/src/mage/cards/t/TheTricksterGodsHeist.java @@ -22,6 +22,9 @@ import java.util.HashSet; import java.util.Set; import java.util.UUID; +import static mage.constants.Duration.EndOfGame; +import static mage.constants.SagaChapter.CHAPTER_I; + /** * @author TheElk801 */ @@ -37,9 +40,9 @@ public final class TheTricksterGodsHeist extends CardImpl { // I — You may exchange control of two target creatures. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_I, + this, CHAPTER_I, CHAPTER_I, new ExchangeControlTargetEffect( - Duration.EndOfGame, "exchange control of two target creatures" + EndOfGame, "exchange control of two target creatures" ), new TargetCreaturePermanent(2), true ); diff --git a/Mage.Sets/src/mage/cards/t/TheWanderingEmperor.java b/Mage.Sets/src/mage/cards/t/TheWanderingEmperor.java index c2b5457b276..94d5bdbeb56 100644 --- a/Mage.Sets/src/mage/cards/t/TheWanderingEmperor.java +++ b/Mage.Sets/src/mage/cards/t/TheWanderingEmperor.java @@ -83,7 +83,7 @@ class TheWanderingEmperorEffect extends AsThoughEffectImpl { TheWanderingEmperorEffect() { super(AsThoughEffectType.ACTIVATE_AS_INSTANT, Duration.WhileOnBattlefield, Outcome.Benefit); - staticText = "as long as {this} entered the battlefield this turn, " + + staticText = "as long as {this} entered this turn, " + "you may activate her loyalty abilities any time you could cast an instant"; } diff --git a/Mage.Sets/src/mage/cards/t/ThelonsCurse.java b/Mage.Sets/src/mage/cards/t/ThelonsCurse.java index f53d5f38a40..a1301f9215d 100644 --- a/Mage.Sets/src/mage/cards/t/ThelonsCurse.java +++ b/Mage.Sets/src/mage/cards/t/ThelonsCurse.java @@ -1,14 +1,13 @@ package mage.cards.t; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DontUntapInControllersUntapStepAllEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -23,10 +22,11 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author spjspj & L_J */ public final class ThelonsCurse extends CardImpl { @@ -85,22 +85,23 @@ class ThelonsCurseEffect extends OneShotEffect { Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (player != null && sourcePermanent != null) { - int countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).size(); - while (player.canRespond() && countBattlefield > 0 && player.chooseUse(Outcome.AIDontUseIt, "Pay {U} and untap a tapped blue creature under your control?", source, game)) { - Target tappedCreatureTarget = new TargetControlledCreaturePermanent(1, 1, filter, true); - if (player.choose(Outcome.Detriment, tappedCreatureTarget, source, game)) { - Cost cost = new ManaCostsImpl<>("{U}"); - Permanent tappedCreature = game.getPermanent(tappedCreatureTarget.getFirstTarget()); - - if (cost.pay(source, game, source, player.getId(), false)) { - tappedCreature.untap(game); - } - } - countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).size(); - } - return true; + if (player == null || sourcePermanent == null) { + return false; } - return false; + int countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).size(); + while (player.canRespond() && countBattlefield > 0 && player.chooseUse(Outcome.AIDontUseIt, "Pay {U} and untap a tapped blue creature under your control?", source, game)) { + Target tappedCreatureTarget = new TargetPermanent(filter); + tappedCreatureTarget.withNotTarget(true); + if (player.choose(Outcome.Detriment, tappedCreatureTarget, source, game)) { + Cost cost = new ManaCostsImpl<>("{U}"); + Permanent tappedCreature = game.getPermanent(tappedCreatureTarget.getFirstTarget()); + + if (cost.pay(source, game, source, player.getId(), false)) { + tappedCreature.untap(game); + } + } + countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).size(); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/t/ThermalDetonator.java b/Mage.Sets/src/mage/cards/t/ThermalDetonator.java index c10c5f6c530..780c65c7051 100644 --- a/Mage.Sets/src/mage/cards/t/ThermalDetonator.java +++ b/Mage.Sets/src/mage/cards/t/ThermalDetonator.java @@ -12,7 +12,7 @@ import mage.constants.CardType; import mage.filter.common.FilterCreatureOrPlayer; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.target.common.TargetCreatureOrPlayer; +import mage.target.common.TargetPermanentOrPlayer; import java.util.UUID; @@ -33,7 +33,7 @@ public final class ThermalDetonator extends CardImpl { // {2}, Sacrifice Thermal Detonator: Thermal Detonator deals 2 damage to target creature without spaceflight or target player. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2), new ManaCostsImpl<>("{2}")); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCreatureOrPlayer(filter)); + ability.addTarget(new TargetPermanentOrPlayer(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/ThicketElemental.java b/Mage.Sets/src/mage/cards/t/ThicketElemental.java index f5e666398a6..87666a32b10 100644 --- a/Mage.Sets/src/mage/cards/t/ThicketElemental.java +++ b/Mage.Sets/src/mage/cards/t/ThicketElemental.java @@ -3,7 +3,6 @@ package mage.cards.t; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.RevealCardsFromLibraryUntilEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; @@ -30,13 +29,11 @@ public final class ThicketElemental extends CardImpl { this.addAbility(new KickerAbility("{1}{G}")); // When Thicket Elemental enters the battlefield, if it was kicked, you may reveal cards from the top of your library until you reveal a creature card. If you do, put that card onto the battlefield and shuffle all other cards revealed this way into your library. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new RevealCardsFromLibraryUntilEffect( - StaticFilters.FILTER_CARD_CREATURE, PutCards.BATTLEFIELD, PutCards.SHUFFLE - )), KickedCondition.ONCE, "When {this} enters, if it was kicked, " + - "you may reveal cards from the top of your library until you reveal a creature card. If you do, " + - "put that card onto the battlefield and shuffle all other cards revealed this way into your library." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new RevealCardsFromLibraryUntilEffect( + StaticFilters.FILTER_CARD_CREATURE, PutCards.BATTLEFIELD, PutCards.SHUFFLE + ).setText("reveal cards from the top of your library until you reveal a creature card. If you do, " + + "put that card onto the battlefield and shuffle all other cards revealed this way into your library"), true + ).withInterveningIf(KickedCondition.ONCE)); } private ThicketElemental(final ThicketElemental card) { diff --git a/Mage.Sets/src/mage/cards/t/ThievingSkydiver.java b/Mage.Sets/src/mage/cards/t/ThievingSkydiver.java index aa40f5be1ca..6ff74d9076a 100644 --- a/Mage.Sets/src/mage/cards/t/ThievingSkydiver.java +++ b/Mage.Sets/src/mage/cards/t/ThievingSkydiver.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.abilities.keyword.FlyingAbility; @@ -44,12 +43,8 @@ public final class ThievingSkydiver extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Thieving Skydiver enters the battlefield, if it was kicked, gain control of target artifact with converted mana cost X or less. If that artifact is an Equipment, attach it to Thieving Skydiver. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new GainControlTargetEffect(Duration.Custom), false), - KickedCondition.ONCE, "When {this} enters, if it was kicked, " + - "gain control of target artifact with mana value X or less. " + - "If that artifact is an Equipment, attach it to {this}." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new GainControlTargetEffect(Duration.Custom) + .setText("gain control of target artifact with mana value X or less")).withInterveningIf(KickedCondition.ONCE); ability.addEffect(new ThievingSkydiverEffect()); ability.addTarget(new TargetArtifactPermanent()); ability.setTargetAdjuster(new XManaValueTargetAdjuster(ComparisonType.OR_LESS)); @@ -70,6 +65,7 @@ class ThievingSkydiverEffect extends OneShotEffect { ThievingSkydiverEffect() { super(Outcome.Benefit); + staticText = "If that artifact is an Equipment, attach it to {this}"; } private ThievingSkydiverEffect(final ThievingSkydiverEffect effect) { @@ -84,11 +80,8 @@ class ThievingSkydiverEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = source.getSourcePermanentIfItStillExists(game); - Permanent artifact = game.getPermanent(source.getFirstTarget()); - if (permanent == null - || artifact == null - || !artifact.isArtifact(game) - || !artifact.hasSubtype(SubType.EQUIPMENT, game)) { + Permanent artifact = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null || artifact == null || !artifact.hasSubtype(SubType.EQUIPMENT, game)) { return false; } game.processAction(); diff --git a/Mage.Sets/src/mage/cards/t/ThirstingAxe.java b/Mage.Sets/src/mage/cards/t/ThirstingAxe.java index bd7e6e56dad..04d3e254892 100644 --- a/Mage.Sets/src/mage/cards/t/ThirstingAxe.java +++ b/Mage.Sets/src/mage/cards/t/ThirstingAxe.java @@ -1,23 +1,18 @@ - package mage.cards.t; import mage.MageObjectReference; import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.CompoundCondition; import mage.abilities.condition.Condition; -import mage.abilities.condition.InvertCondition; -import mage.abilities.condition.common.AttachedCondition; -import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.SacrificeEquippedEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.keyword.EquipAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.WatcherScope; import mage.game.Game; import mage.game.events.DamagedEvent; import mage.game.events.GameEvent; @@ -25,10 +20,9 @@ import mage.game.permanent.Permanent; import mage.watchers.Watcher; import java.util.HashSet; +import java.util.Optional; import java.util.Set; import java.util.UUID; -import mage.target.common.TargetControlledCreaturePermanent; - /** * @author Quercitron @@ -43,17 +37,12 @@ public final class ThirstingAxe extends CardImpl { this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(4, 0))); // At the beginning of your end step, if equipped creature didn't deal combat damage to a creature this turn, sacrifice it. - TriggeredAbility ability = new BeginningOfEndStepTriggeredAbility(new SacrificeEquippedEffect()); - Condition condition = new CompoundCondition( - AttachedCondition.instance, - new InvertCondition(new EquippedDealtCombatDamageToCreatureCondition())); - String triggeredAbilityText = "At the beginning of your end step, if equipped creature " + - "didn't deal combat damage to a creature this turn, sacrifice it."; - ConditionalInterveningIfTriggeredAbility sacrificeTriggeredAbility = new ConditionalInterveningIfTriggeredAbility(ability, condition, triggeredAbilityText); - this.addAbility(sacrificeTriggeredAbility, new CombatDamageToCreatureWatcher()); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new SacrificeEquippedEffect().setText("sacrifice it") + ).withInterveningIf(ThirstingAxeCondition.instance), new ThirstingAxeWatcher()); // Equip {2} - this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(2), new TargetControlledCreaturePermanent(), false)); + this.addAbility(new EquipAbility(2)); } private ThirstingAxe(final ThirstingAxe card) { @@ -66,43 +55,42 @@ public final class ThirstingAxe extends CardImpl { } } -class EquippedDealtCombatDamageToCreatureCondition implements Condition { +enum ThirstingAxeCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { - Permanent equipment = game.getPermanent(source.getSourceId()); - if (equipment != null && equipment.getAttachedTo() != null) { - CombatDamageToCreatureWatcher watcher = - game.getState().getWatcher(CombatDamageToCreatureWatcher.class); - return watcher != null && watcher.dealtDamage(equipment.getAttachedTo(), equipment.getAttachedToZoneChangeCounter(), game); - } - return false; + return Optional + .ofNullable(source.getSourcePermanentOrLKI(game)) + .map(Permanent::getAttachedTo) + .filter(uuid -> ThirstingAxeWatcher.checkCreature(uuid, game)) + .isPresent(); } + @Override + public String toString() { + return "equipped creature didn't deal combat damage to a creature this turn"; + } } -class CombatDamageToCreatureWatcher extends Watcher { +class ThirstingAxeWatcher extends Watcher { // which objects dealt combat damage to creature during the turn - private final Set dealtCombatDamageToCreature; + private final Set dealtCombatDamageToCreature = new HashSet<>(); - public CombatDamageToCreatureWatcher() { + public ThirstingAxeWatcher() { super(WatcherScope.GAME); - dealtCombatDamageToCreature = new HashSet<>(); } @Override public void watch(GameEvent event, Game game) { - if (event.getType() != GameEvent.EventType.DAMAGED_PERMANENT - || !((DamagedEvent) event).isCombatDamage()) { + if (event.getType() != GameEvent.EventType.DAMAGED_PERMANENT || !((DamagedEvent) event).isCombatDamage()) { return; } Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent == null || !permanent.isCreature(game)) { - return; + if (permanent != null && permanent.isCreature(game)) { + dealtCombatDamageToCreature.add(new MageObjectReference(event.getSourceId(), game)); } - MageObjectReference damageSource = new MageObjectReference(event.getSourceId(), game); - dealtCombatDamageToCreature.add(damageSource); } @Override @@ -111,9 +99,12 @@ class CombatDamageToCreatureWatcher extends Watcher { dealtCombatDamageToCreature.clear(); } - public boolean dealtDamage(UUID objectId, int zoneChangeCounter, Game game) { - MageObjectReference reference = new MageObjectReference(objectId, zoneChangeCounter, game); - return dealtCombatDamageToCreature.contains(reference); + static boolean checkCreature(UUID permanentId, Game game) { + return game + .getState() + .getWatcher(ThirstingAxeWatcher.class) + .dealtCombatDamageToCreature + .stream() + .anyMatch(mor -> mor.refersTo(permanentId, game)); } - } diff --git a/Mage.Sets/src/mage/cards/t/ThisIsHowItEnds.java b/Mage.Sets/src/mage/cards/t/ThisIsHowItEnds.java index 15b6ed745aa..b9aaf454eed 100644 --- a/Mage.Sets/src/mage/cards/t/ThisIsHowItEnds.java +++ b/Mage.Sets/src/mage/cards/t/ThisIsHowItEnds.java @@ -1,36 +1,40 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ShuffleIntoLibraryTargetEffect; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.choices.FaceVillainousChoice; import mage.choices.VillainousChoice; -import mage.constants.*; -import mage.game.Game; -import mage.filter.StaticFilters; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * - * @author padfoothelix + * @author padfoothelix */ public final class ThisIsHowItEnds extends CardImpl { public ThisIsHowItEnds(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}"); - - // Target creature's owner shuffles it into their library, then faces a villainous choice -- They lose 5 life, or they shuffle another creature they own into their library. - this.getSpellAbility().addEffect( - new ShuffleIntoLibraryTargetEffect() - .setText("target creature's owner shuffles it into their library,") - ); - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(new ThisIsHowItEndsEffect()); + // Target creature's owner shuffles it into their library, then faces a villainous choice -- They lose 5 life, or they shuffle another creature they own into their library. + this.getSpellAbility().addEffect( + new ShuffleIntoLibraryTargetEffect() + .setText("target creature's owner shuffles it into their library,") + ); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addEffect(new ThisIsHowItEndsEffect()); } private ThisIsHowItEnds(final ThisIsHowItEnds card) { @@ -46,26 +50,26 @@ public final class ThisIsHowItEnds extends CardImpl { class ThisIsHowItEndsEffect extends OneShotEffect { private static final FaceVillainousChoice choice = new FaceVillainousChoice( - Outcome.Removal, new ThisIsHowItEndsFirstChoice(), new ThisIsHowItEndsSecondChoice() - ); + Outcome.Removal, new ThisIsHowItEndsFirstChoice(), new ThisIsHowItEndsSecondChoice() + ); ThisIsHowItEndsEffect() { - super(Outcome.Benefit); - staticText = "then " + choice.generateRule(); + super(Outcome.Benefit); + staticText = "then " + choice.generateRule(); } private ThisIsHowItEndsEffect(final ThisIsHowItEndsEffect effect) { - super(effect); + super(effect); } @Override public ThisIsHowItEndsEffect copy() { - return new ThisIsHowItEndsEffect(this); + return new ThisIsHowItEndsEffect(this); } @Override public boolean apply(Game game, Ability source) { - UUID targetOwnerId = game.getOwnerId(getTargetPointer().getFirst(game, source)); + UUID targetOwnerId = game.getOwnerId(getTargetPointer().getFirst(game, source)); Player targetOwner = game.getPlayer(targetOwnerId); choice.faceChoice(targetOwner, game, source); return true; @@ -74,13 +78,13 @@ class ThisIsHowItEndsEffect extends OneShotEffect { class ThisIsHowItEndsFirstChoice extends VillainousChoice { ThisIsHowItEndsFirstChoice() { - super("They lose 5 life","You lose 5 life"); + super("They lose 5 life", "You lose 5 life"); } @Override public boolean doChoice(Player player, Game game, Ability source) { player.loseLife(5, game, source, false); - return true; + return true; } } @@ -89,7 +93,7 @@ class ThisIsHowItEndsSecondChoice extends VillainousChoice { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you own"); static { - filter.add(TargetController.YOU.getOwnerPredicate()); + filter.add(TargetController.YOU.getOwnerPredicate()); } ThisIsHowItEndsSecondChoice() { @@ -98,11 +102,12 @@ class ThisIsHowItEndsSecondChoice extends VillainousChoice { @Override public boolean doChoice(Player player, Game game, Ability source) { - TargetCreaturePermanent target = new TargetCreaturePermanent(1, 1, filter, true); - target.withChooseHint("to shuffle into your library"); + TargetPermanent target = new TargetPermanent(filter); + target.withNotTarget(true); + target.withChooseHint("to shuffle into your library"); player.chooseTarget(Outcome.Detriment, target, source, game); - Cards cards = new CardsImpl(target.getTargets()); - player.shuffleCardsToLibrary(cards, game, source); - return true; + Cards cards = new CardsImpl(target.getTargets()); + player.shuffleCardsToLibrary(cards, game, source); + return true; } } diff --git a/Mage.Sets/src/mage/cards/t/ThopterAssembly.java b/Mage.Sets/src/mage/cards/t/ThopterAssembly.java index 19c2a15cc72..f1161f4ab40 100644 --- a/Mage.Sets/src/mage/cards/t/ThopterAssembly.java +++ b/Mage.Sets/src/mage/cards/t/ThopterAssembly.java @@ -2,13 +2,12 @@ package mage.cards.t; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.ReturnToHandSourceEffect; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -25,7 +24,7 @@ import java.util.UUID; */ public final class ThopterAssembly extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent(SubType.THOPTER, ""); + private static final FilterPermanent filter = new FilterPermanent(SubType.THOPTER, "you control no Thopters other than {this}"); static { filter.add(AnotherPredicate.instance); @@ -44,15 +43,8 @@ public final class ThopterAssembly extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // At the beginning of your upkeep, if you control no Thopters other than Thopter Assembly, return Thopter Assembly to its owner's hand and create five 1/1 colorless Thopter artifact creature tokens with flying. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - new ReturnToHandSourceEffect(true), false - ), condition, "At the beginning of your upkeep, " + - "if you control no Thopters other than {this}, " + - "return {this} to its owner's hand and create five 1/1 colorless " + - "Thopter artifact creature tokens with flying." - ); - ability.addEffect(new CreateTokenEffect(new ThopterColorlessToken(), 5)); + Ability ability = new BeginningOfUpkeepTriggeredAbility(new ReturnToHandSourceEffect(true)).withInterveningIf(condition); + ability.addEffect(new CreateTokenEffect(new ThopterColorlessToken(), 5).concatBy("and")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/ThornscapeBattlemage.java b/Mage.Sets/src/mage/cards/t/ThornscapeBattlemage.java index ecedd0964c9..05b2edec148 100644 --- a/Mage.Sets/src/mage/cards/t/ThornscapeBattlemage.java +++ b/Mage.Sets/src/mage/cards/t/ThornscapeBattlemage.java @@ -1,12 +1,10 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.KickedCostCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.KickerAbility; @@ -14,17 +12,21 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.target.common.TargetArtifactPermanent; import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetArtifactPermanent; + +import java.util.UUID; /** - * * @author FenrisulfrX */ public final class ThornscapeBattlemage extends CardImpl { + private static final Condition condition = new KickedCostCondition("{R}"); + private static final Condition condition2 = new KickedCostCondition("{W}"); + public ThornscapeBattlemage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.WIZARD); this.power = new MageInt(2); @@ -36,16 +38,16 @@ public final class ThornscapeBattlemage extends CardImpl { this.addAbility(kickerAbility); // When {this} enters, if it was kicked with its {R} kicker, it deals 2 damage to any target. - TriggeredAbility ability1 = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2, "it")); - ability1.addTarget(new TargetAnyTarget()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability1, new KickedCostCondition("{R}"), - "When {this} enters, if it was kicked with its {R} kicker, it deals 2 damage to any target.")); + Ability ability = new EntersBattlefieldTriggeredAbility( + new DamageTargetEffect(2, "it") + ).withInterveningIf(condition); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); // When {this} enters, if it was kicked with its {W} kicker, destroy target artifact. - TriggeredAbility ability2 = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()); - ability2.addTarget(new TargetArtifactPermanent()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability2, new KickedCostCondition("{W}"), - "When {this} enters, if it was kicked with its {W} kicker, destroy target artifact.")); + ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()).withInterveningIf(condition2); + ability.addTarget(new TargetArtifactPermanent()); + this.addAbility(ability); } private ThornscapeBattlemage(final ThornscapeBattlemage card) { diff --git a/Mage.Sets/src/mage/cards/t/ThoughtShucker.java b/Mage.Sets/src/mage/cards/t/ThoughtShucker.java index d5d62db6815..8a0641698dd 100644 --- a/Mage.Sets/src/mage/cards/t/ThoughtShucker.java +++ b/Mage.Sets/src/mage/cards/t/ThoughtShucker.java @@ -1,9 +1,9 @@ package mage.cards.t; import mage.MageInt; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.ThresholdCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; @@ -42,7 +42,7 @@ public final class ThoughtShucker extends CardImpl { } } -class ThoughtShuckerActivatedAbility extends ConditionalActivatedAbility { +class ThoughtShuckerActivatedAbility extends ActivateIfConditionActivatedAbility { ThoughtShuckerActivatedAbility() { super(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new ManaCostsImpl<>("{1}{U}"), ThresholdCondition.instance); @@ -66,4 +66,4 @@ class ThoughtShuckerActivatedAbility extends ConditionalActivatedAbility { int len = rule.length(); return rule.substring(0, len - 1) + " and only once."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/t/ThoughtboundPrimoc.java b/Mage.Sets/src/mage/cards/t/ThoughtboundPrimoc.java index f61dfdb8d02..c248535cb94 100644 --- a/Mage.Sets/src/mage/cards/t/ThoughtboundPrimoc.java +++ b/Mage.Sets/src/mage/cards/t/ThoughtboundPrimoc.java @@ -1,26 +1,28 @@ package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author awjackson */ public final class ThoughtboundPrimoc extends CardImpl { @@ -37,12 +39,8 @@ public final class ThoughtboundPrimoc extends CardImpl { // At the beginning of your upkeep, if a player controls more Wizards than each other player, // the player who controls the most Wizards gains control of Thoughtbound Primoc. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new ThoughtboundPrimocEffect()), - OnePlayerHasTheMostWizards.instance, - "At the beginning of your upkeep, if a player controls more Wizards than each other player, the player who controls the most Wizards gains control of {this}" - )); - + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new ThoughtboundPrimocEffect()) + .withInterveningIf(OnePlayerHasTheMostWizards.instance)); } private ThoughtboundPrimoc(final ThoughtboundPrimoc card) { diff --git a/Mage.Sets/src/mage/cards/t/ThousandFacedShadow.java b/Mage.Sets/src/mage/cards/t/ThousandFacedShadow.java index e3d302ad786..275d60f349c 100644 --- a/Mage.Sets/src/mage/cards/t/ThousandFacedShadow.java +++ b/Mage.Sets/src/mage/cards/t/ThousandFacedShadow.java @@ -101,6 +101,6 @@ class ThousandFacedShadowTriggeredAbility extends TriggeredAbilityImpl { public String getRule() { return "When {this} enters from your hand, if it's attacking, " + "create a token that's a copy of another target attacking creature. " + - "The token enters the battlefield tapped and attacking."; + "The token enters tapped and attacking."; } } diff --git a/Mage.Sets/src/mage/cards/t/ThranQuarry.java b/Mage.Sets/src/mage/cards/t/ThranQuarry.java index 2b2fa0d2921..955dec45d33 100644 --- a/Mage.Sets/src/mage/cards/t/ThranQuarry.java +++ b/Mage.Sets/src/mage/cards/t/ThranQuarry.java @@ -1,36 +1,38 @@ - package mage.cards.t; -import java.util.UUID; -import mage.abilities.TriggeredAbility; -import mage.abilities.common.OnEventTriggeredAbility; -import mage.abilities.condition.common.CreatureCountCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.mana.AnyColorManaAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.TargetController; -import mage.game.events.GameEvent; +import mage.filter.common.FilterControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class ThranQuarry extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledCreaturePermanent("you control no creatures"), ComparisonType.EQUAL_TO, 0 + ); + public ThranQuarry(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // At the beginning of the end step, if you control no creatures, sacrifice Thran Quarry. - TriggeredAbility triggered = new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new SacrificeSourceEffect()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(triggered, new CreatureCountCondition(0, TargetController.YOU), - "At the beginning of the end step, if you control no creatures, sacrifice {this}.")); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.NEXT, new SacrificeSourceEffect(), false, condition + )); // {tap}: Add one mana of any color. this.addAbility(new AnyColorManaAbility()); - } private ThranQuarry(final ThranQuarry card) { diff --git a/Mage.Sets/src/mage/cards/t/ThranTome.java b/Mage.Sets/src/mage/cards/t/ThranTome.java index ddf7b2cd564..974f50258b7 100644 --- a/Mage.Sets/src/mage/cards/t/ThranTome.java +++ b/Mage.Sets/src/mage/cards/t/ThranTome.java @@ -1,6 +1,5 @@ package mage.cards.t; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; @@ -13,11 +12,9 @@ import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; import mage.players.Player; -import mage.target.Target; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetOpponent; -import java.util.Set; import java.util.UUID; /** @@ -31,6 +28,7 @@ public final class ThranTome extends CardImpl { // Reveal the top three cards of your library. Target opponent chooses one of those cards. Put that card into your graveyard, then draw two cards. Ability ability = new SimpleActivatedAbility(new ThranTomeEffect(), new ManaCostsImpl<>("{5}")); ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetOpponent()); this.addAbility(ability); } @@ -62,35 +60,18 @@ class ThranTomeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - // validate source and controller exist + // validate opponent and controller exist Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source); + Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); - if (sourceObject == null || controller == null) { + if (opponent == null || controller == null) { return false; } - // target an opponent, if able - Player opponent; - Set opponents = game.getOpponents(controller.getId()); - opponents.removeIf(opp -> !game.getPlayer(opp).canBeTargetedBy(sourceObject, source.getControllerId(), source, game)); - - if (opponents.isEmpty()) { - return false; - } else { - if (opponents.size() == 1) { - opponent = game.getPlayer(opponents.iterator().next()); - } else { - Target target = new TargetOpponent(); - controller.chooseTarget(Outcome.Detriment, target, source, game); - opponent = game.getPlayer(target.getFirstTarget()); - } - } - // reveal the cards and choose one. put it in the graveyard Card cardToGraveyard; Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 3)); - controller.revealCards(sourceObject.getIdName(), cards, game); + controller.revealCards(source, cards, game); if (cards.size() == 1) { cardToGraveyard = cards.getRandom(game); diff --git a/Mage.Sets/src/mage/cards/t/ThranWeaponry.java b/Mage.Sets/src/mage/cards/t/ThranWeaponry.java index 73ce61f0329..8192c372351 100644 --- a/Mage.Sets/src/mage/cards/t/ThranWeaponry.java +++ b/Mage.Sets/src/mage/cards/t/ThranWeaponry.java @@ -55,7 +55,7 @@ class ThranWeaponryEffect extends BoostAllEffect{ public ThranWeaponryEffect() { super(2, 2, Duration.WhileOnBattlefield); - staticText = "All creatures get +2/+2 for as long as Thran Weaponry remains tapped"; + staticText = "All creatures get +2/+2 for as long as {this} remains tapped"; } private ThranWeaponryEffect(final ThranWeaponryEffect effect) { diff --git a/Mage.Sets/src/mage/cards/t/ThreadsOfDisloyalty.java b/Mage.Sets/src/mage/cards/t/ThreadsOfDisloyalty.java index ce924743d93..c4e82d6e750 100644 --- a/Mage.Sets/src/mage/cards/t/ThreadsOfDisloyalty.java +++ b/Mage.Sets/src/mage/cards/t/ThreadsOfDisloyalty.java @@ -38,7 +38,7 @@ public final class ThreadsOfDisloyalty extends CardImpl { this.subtype.add(SubType.AURA); // Enchant creature with converted mana cost 2 or less - TargetPermanent auraTarget = new TargetCreaturePermanent(filter); + TargetPermanent auraTarget = new TargetPermanent(filter); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.GainControl)); Ability ability = new EnchantAbility(auraTarget); diff --git a/Mage.Sets/src/mage/cards/t/ThroneOfEldraine.java b/Mage.Sets/src/mage/cards/t/ThroneOfEldraine.java index 5b503d04ec9..5d90e113827 100644 --- a/Mage.Sets/src/mage/cards/t/ThroneOfEldraine.java +++ b/Mage.Sets/src/mage/cards/t/ThroneOfEldraine.java @@ -11,9 +11,10 @@ import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ColoredManaCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.ChooseColorEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.mana.ManaEffect; import mage.abilities.mana.SimpleManaAbility; import mage.abilities.mana.builder.ConditionalManaBuilder; @@ -41,14 +42,12 @@ public final class ThroneOfEldraine extends CardImpl { this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new ThroneOfEldraineManaEffect(), new TapSourceCost())); // {3}, {T}: Draw two cards. Spend only mana of the chosen color to activate this ability. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, - new DrawCardSourceControllerEffect(2), - new GenericManaCost(3), - ThroneOfEldraineChosenColorCondition.instance, // disable the ability if no color was chosen or cost is actually {0}. - "{3}, {T}: Draw two cards. Spend only mana of the chosen color to activate this ability." - ); + Ability ability = new ActivateIfConditionActivatedAbility( + new DrawCardSourceControllerEffect(2), new GenericManaCost(3), + ThroneOfEldraineChosenColorCondition.instance // disable the ability if no color was chosen or cost is actually {0}. + ).hideCondition(); ability.addCost(new TapSourceCost()); + ability.addEffect(new InfoEffect("Spend only mana of the chosen color to activate this ability")); ability.setCostAdjuster(ThroneOfEldraineAdjuster.instance); this.addAbility(ability); } @@ -214,4 +213,4 @@ enum ThroneOfEldraineChosenColorCondition implements Condition { ObjectColor color = (ObjectColor) game.getState().getValue(source.getSourceId() + "_color"); return color != null || source.getManaCostsToPay().getMana().count() == 0; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/t/ThrowFromTheSaddle.java b/Mage.Sets/src/mage/cards/t/ThrowFromTheSaddle.java index e010cdcca59..c0de0f4535c 100644 --- a/Mage.Sets/src/mage/cards/t/ThrowFromTheSaddle.java +++ b/Mage.Sets/src/mage/cards/t/ThrowFromTheSaddle.java @@ -13,12 +13,15 @@ import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author Susucr */ @@ -29,7 +32,7 @@ public final class ThrowFromTheSaddle extends CardImpl { // Target creature you control gets +1/+1 until end of turn. Put a +1/+1 counter on it instead if it's a Mount. Then it deals damage equal to its power to target creature you don't control. this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.getSpellAbility().addEffect(new ThrowFromTheSaddleEffect()); this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect("it").concatBy("Then")); } diff --git a/Mage.Sets/src/mage/cards/t/ThrummingHivepool.java b/Mage.Sets/src/mage/cards/t/ThrummingHivepool.java new file mode 100644 index 00000000000..30b6f50133e --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThrummingHivepool.java @@ -0,0 +1,57 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.AffinityAbility; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AffinityType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.game.permanent.token.SliverToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ThrummingHivepool extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.SLIVER, "Slivers"); + + public ThrummingHivepool(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}"); + + // Affinity for Slivers + this.addAbility(new AffinityAbility(AffinityType.SLIVERS)); + + // Slivers you control have double strike and haste. + Ability ability = new SimpleStaticAbility(new GainAbilityControlledEffect( + DoubleStrikeAbility.getInstance(), Duration.WhileOnBattlefield, filter + )); + ability.addEffect(new GainAbilityControlledEffect( + HasteAbility.getInstance(), Duration.WhileOnBattlefield, filter + ).setText("and haste")); + this.addAbility(ability); + + // At the beginning of your upkeep, create two 1/1 colorless Sliver creature tokens. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new SliverToken(), 2))); + } + + private ThrummingHivepool(final ThrummingHivepool card) { + super(card); + } + + @Override + public ThrummingHivepool copy() { + return new ThrummingHivepool(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/Thumbscrews.java b/Mage.Sets/src/mage/cards/t/Thumbscrews.java index a022de33325..95459d549fd 100644 --- a/Mage.Sets/src/mage/cards/t/Thumbscrews.java +++ b/Mage.Sets/src/mage/cards/t/Thumbscrews.java @@ -1,37 +1,32 @@ - package mage.cards.t; -import java.util.UUID; import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInHandCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.target.common.TargetOpponentOrPlaneswalker; +import java.util.UUID; + /** - * * @author fireshoes */ public final class Thumbscrews extends CardImpl { + private static final Condition condition = new CardsInHandCondition(ComparisonType.MORE_THAN, 4); + public Thumbscrews(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // At the beginning of your upkeep, if you have five or more cards in hand, Thumbscrews deals 1 damage to target opponent. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility( - new DamageTargetEffect(1)); + TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new DamageTargetEffect(1)).withInterveningIf(condition); ability.addTarget(new TargetOpponentOrPlaneswalker()); - CardsInHandCondition condition = new CardsInHandCondition(ComparisonType.MORE_THAN, 4); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - ability, condition, - "At the beginning of your upkeep, if you have five or more cards in hand, " - + "{this} deals 1 damage to target opponent or planeswalker." - )); + this.addAbility(ability); } private Thumbscrews(final Thumbscrews card) { diff --git a/Mage.Sets/src/mage/cards/t/ThunderBrute.java b/Mage.Sets/src/mage/cards/t/ThunderBrute.java index bd33753ca5a..e7049fce44f 100644 --- a/Mage.Sets/src/mage/cards/t/ThunderBrute.java +++ b/Mage.Sets/src/mage/cards/t/ThunderBrute.java @@ -1,12 +1,8 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.TributeNotPaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.TrampleAbility; @@ -14,17 +10,18 @@ import mage.abilities.keyword.TributeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class ThunderBrute extends CardImpl { public ThunderBrute(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}{R}"); this.subtype.add(SubType.CYCLOPS); this.power = new MageInt(5); @@ -32,12 +29,14 @@ public final class ThunderBrute extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); - // Tribute 3
+ + // Tribute 3 this.addAbility(new TributeAbility(3)); + // When Thunder Brute enters the battlefield, if tribute wasn't paid, it gains haste until end of turn. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.EndOfTurn), false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, TributeNotPaidCondition.instance, - "When {this} enters, if tribute wasn't paid, it gains haste until end of turn.")); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainAbilitySourceEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("it gains haste until end of turn")).withInterveningIf(TributeNotPaidCondition.instance)); } private ThunderBrute(final ThunderBrute card) { diff --git a/Mage.Sets/src/mage/cards/t/Thunderbolt.java b/Mage.Sets/src/mage/cards/t/Thunderbolt.java index 3f82a044ce4..453a29b60c2 100644 --- a/Mage.Sets/src/mage/cards/t/Thunderbolt.java +++ b/Mage.Sets/src/mage/cards/t/Thunderbolt.java @@ -10,6 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetPlayerOrPlaneswalker; @@ -32,7 +33,7 @@ public final class Thunderbolt extends CardImpl { this.getSpellAbility().addEffect(new DamageTargetEffect(3)); this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); Mode mode = new Mode(new DamageTargetEffect(4)); - mode.addTarget(new TargetCreaturePermanent(filter)); + mode.addTarget(new TargetPermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/t/ThunderscapeBattlemage.java b/Mage.Sets/src/mage/cards/t/ThunderscapeBattlemage.java index 522147150de..4fa6e8cc8ee 100644 --- a/Mage.Sets/src/mage/cards/t/ThunderscapeBattlemage.java +++ b/Mage.Sets/src/mage/cards/t/ThunderscapeBattlemage.java @@ -1,12 +1,10 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.KickedCostCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.keyword.KickerAbility; @@ -17,14 +15,18 @@ import mage.constants.SubType; import mage.target.TargetPlayer; import mage.target.common.TargetEnchantmentPermanent; +import java.util.UUID; + /** - * * @author FenrisulfrX */ public final class ThunderscapeBattlemage extends CardImpl { + private static final Condition condition = new KickedCostCondition("{1}{B}"); + private static final Condition condition2 = new KickedCostCondition("{G}"); + public ThunderscapeBattlemage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(2); @@ -36,16 +38,14 @@ public final class ThunderscapeBattlemage extends CardImpl { this.addAbility(kickerAbility); // When {this} enters, if it was kicked with its {1}{B} kicker, target player discards two cards. - TriggeredAbility ability1 = new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(2)); - ability1.addTarget(new TargetPlayer()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability1, new KickedCostCondition("{1}{B}"), - "When {this} enters, if it was kicked with its {1}{B} kicker, target player discards two cards.")); + Ability ability = new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(2)).withInterveningIf(condition); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); // When {this} enters, if it was kicked with its {G} kicker, destroy target enchantment. - TriggeredAbility ability2 = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()); - ability2.addTarget(new TargetEnchantmentPermanent()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability2, new KickedCostCondition("{G}"), - "When {this} enters, if it was kicked with its {G} kicker, destroy target enchantment.")); + ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()).withInterveningIf(condition2); + ability.addTarget(new TargetEnchantmentPermanent()); + this.addAbility(ability); } private ThunderscapeBattlemage(final ThunderscapeBattlemage card) { diff --git a/Mage.Sets/src/mage/cards/t/Tiamat.java b/Mage.Sets/src/mage/cards/t/Tiamat.java index c72966919ca..9f416373650 100644 --- a/Mage.Sets/src/mage/cards/t/Tiamat.java +++ b/Mage.Sets/src/mage/cards/t/Tiamat.java @@ -3,7 +3,6 @@ package mage.cards.t; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -45,13 +44,9 @@ public final class Tiamat extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Tiamat enters the battlefield, if you cast it, search your library for up to five Dragon cards named Tiama that each have different names, reveal them, put them into your hand, then shuffle. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( - new SearchLibraryPutInHandEffect( - new TargetCardWithDifferentNameInLibrary(0, 5, filter), true - )), CastFromEverywhereSourceCondition.instance, "When {this} enters, " + - "if you cast it, search your library for up to five Dragon cards not named Tiamat " + - "that each have different names, reveal them, put them into your hand, then shuffle." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInHandEffect( + new TargetCardWithDifferentNameInLibrary(0, 5, filter), true + )).withInterveningIf(CastFromEverywhereSourceCondition.instance)); } private Tiamat(final Tiamat card) { diff --git a/Mage.Sets/src/mage/cards/t/TidalSurge.java b/Mage.Sets/src/mage/cards/t/TidalSurge.java index 0a0b749abad..2651c81d2bb 100644 --- a/Mage.Sets/src/mage/cards/t/TidalSurge.java +++ b/Mage.Sets/src/mage/cards/t/TidalSurge.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -10,10 +8,11 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author Quercitron */ public final class TidalSurge extends CardImpl { @@ -23,14 +22,13 @@ public final class TidalSurge extends CardImpl { static { filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); } - - public TidalSurge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{U}"); + public TidalSurge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}"); // Tap up to three target creatures without flying. this.getSpellAbility().addEffect(new TapTargetEffect("tap up to three target creatures without flying")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 3, filter, false)); + this.getSpellAbility().addTarget(new TargetPermanent(0, 3, filter)); } private TidalSurge(final TidalSurge card) { diff --git a/Mage.Sets/src/mage/cards/t/TideShaper.java b/Mage.Sets/src/mage/cards/t/TideShaper.java index 9613c8275a9..8530462aaaa 100644 --- a/Mage.Sets/src/mage/cards/t/TideShaper.java +++ b/Mage.Sets/src/mage/cards/t/TideShaper.java @@ -9,7 +9,6 @@ import mage.abilities.condition.Condition; import mage.abilities.condition.common.KickedCondition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BecomesBasicLandTargetEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.hint.ConditionHint; @@ -18,7 +17,6 @@ import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -54,11 +52,7 @@ public final class TideShaper extends CardImpl { this.addAbility(new KickerAbility("{1}")); // When Tide Shaper enters the battlefield, if it was kicked, target land becomes an Island for as long as Tide Shaper remains on the battlefield. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new TideShaperEffect()), - KickedCondition.ONCE, "When {this} enters, if it was kicked, " + - "target land becomes an Island for as long as {this} remains on the battlefield." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new TideShaperEffect()).withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetLandPermanent()); this.addAbility(ability); @@ -83,6 +77,7 @@ class TideShaperEffect extends BecomesBasicLandTargetEffect { TideShaperEffect() { super(Duration.Custom, false, true, SubType.ISLAND); + staticText = "target land becomes an Island for as long as {this} remains on the battlefield"; } private TideShaperEffect(final TideShaperEffect effect) { @@ -101,6 +96,7 @@ class TideShaperEffect extends BecomesBasicLandTargetEffect { discard(); } } + @Override public boolean queryAffectedObjects(Layer layer, Ability source, Game game, List affectedObjects) { if (source.getSourcePermanentIfItStillExists(game) == null) { diff --git a/Mage.Sets/src/mage/cards/t/TidebinderMage.java b/Mage.Sets/src/mage/cards/t/TidebinderMage.java index ebf8ae0c759..6741c857be3 100644 --- a/Mage.Sets/src/mage/cards/t/TidebinderMage.java +++ b/Mage.Sets/src/mage/cards/t/TidebinderMage.java @@ -16,6 +16,7 @@ import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -48,7 +49,7 @@ public final class TidebinderMage extends CardImpl { // That creature doesn't untap during its controller's untap step for as long as you control Tidebinder Mage. Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect(), false); ability.addEffect(new DontUntapInControllersUntapStepTargetEffect(Duration.WhileControlled)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TidecallerMentor.java b/Mage.Sets/src/mage/cards/t/TidecallerMentor.java index 5100e75d776..53740be2f55 100644 --- a/Mage.Sets/src/mage/cards/t/TidecallerMentor.java +++ b/Mage.Sets/src/mage/cards/t/TidecallerMentor.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.ThresholdCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.MenaceAbility; import mage.cards.CardImpl; @@ -33,11 +32,7 @@ public final class TidecallerMentor extends CardImpl { this.addAbility(new MenaceAbility(false)); // Threshold -- When Tidecaller Mentor enters, if seven or more cards are in your graveyard, return up to one target nonland permanent to its owner's hand. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()), - ThresholdCondition.instance, "When {this} enters, if seven or more cards " + - "are in your graveyard, return up to one target nonland permanent to its owner's hand." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()).withInterveningIf(ThresholdCondition.instance); ability.addTarget(new TargetNonlandPermanent(0, 1)); this.addAbility(ability.setAbilityWord(AbilityWord.THRESHOLD)); } diff --git a/Mage.Sets/src/mage/cards/t/TideforceElemental.java b/Mage.Sets/src/mage/cards/t/TideforceElemental.java index f1028901dfd..2368549edc4 100644 --- a/Mage.Sets/src/mage/cards/t/TideforceElemental.java +++ b/Mage.Sets/src/mage/cards/t/TideforceElemental.java @@ -17,8 +17,11 @@ import mage.constants.SubType; import mage.constants.ColoredManaSymbol; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * * @author Loki @@ -37,7 +40,7 @@ public final class TideforceElemental extends CardImpl { new MayTapOrUntapTargetEffect(), new ColoredManaCost(ColoredManaSymbol.U)); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); // Landfall - Whenever a land you control enters, you may untap Tideforce Elemental. this.addAbility(new LandfallAbility(new UntapSourceEffect(), true)); diff --git a/Mage.Sets/src/mage/cards/t/TideshaperMystic.java b/Mage.Sets/src/mage/cards/t/TideshaperMystic.java index b5821d44d6e..59dd2ce550c 100644 --- a/Mage.Sets/src/mage/cards/t/TideshaperMystic.java +++ b/Mage.Sets/src/mage/cards/t/TideshaperMystic.java @@ -6,13 +6,11 @@ import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.common.continuous.BecomesBasicLandTargetEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.target.common.TargetLandPermanent; import java.util.UUID; @@ -30,10 +28,10 @@ public final class TideshaperMystic extends CardImpl { this.toughness = new MageInt(1); // {T}: Target land becomes the basic land type of your choice until end of turn. Activate this ability only during your turn. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new BecomesBasicLandTargetEffect(Duration.EndOfTurn), new TapSourceCost(), MyTurnCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new BecomesBasicLandTargetEffect(Duration.EndOfTurn), new TapSourceCost(), MyTurnCondition.instance + ); ability.addTarget(new TargetLandPermanent()); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TillerEngine.java b/Mage.Sets/src/mage/cards/t/TillerEngine.java index bcc66d292a7..23b412e6b12 100644 --- a/Mage.Sets/src/mage/cards/t/TillerEngine.java +++ b/Mage.Sets/src/mage/cards/t/TillerEngine.java @@ -11,6 +11,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledLandPermanent; import mage.filter.predicate.permanent.TappedPredicate; @@ -25,7 +26,7 @@ import java.util.UUID; */ public final class TillerEngine extends CardImpl { - private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); + private static final FilterPermanent filter = new FilterControlledLandPermanent(); static { filter.add(TappedPredicate.TAPPED); @@ -40,7 +41,7 @@ public final class TillerEngine extends CardImpl { // Whenever a land enters the battlefield tapped and under your control, choose one — // • Untap that land. Ability ability = new EntersBattlefieldControlledTriggeredAbility(new TillerEngineUntapEffect(), filter) - .setTriggerPhrase("Whenever a land enters the battlefield tapped and under your control, "); + .setTriggerPhrase("Whenever a land you control enters tapped, "); // • Tap target nonland permanent an opponent controls. Mode mode = new Mode(new TapTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/t/TilonallisKnight.java b/Mage.Sets/src/mage/cards/t/TilonallisKnight.java index 4f3a8203a26..6aae7a35233 100644 --- a/Mage.Sets/src/mage/cards/t/TilonallisKnight.java +++ b/Mage.Sets/src/mage/cards/t/TilonallisKnight.java @@ -1,31 +1,27 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.common.FilterControlledPermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class TilonallisKnight extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent(); - - static { - filter.add(SubType.DINOSAUR.getPredicate()); - } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.DINOSAUR, "you control a Dinosaur") + ); public TilonallisKnight(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); @@ -36,12 +32,7 @@ public final class TilonallisKnight extends CardImpl { this.toughness = new MageInt(2); // Whenever Tilonalli's Knight attacks, if you control a Dinosaur, Tilonalli's Knight gets +1/+1 until end of turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn), false), - new PermanentsOnTheBattlefieldCondition(filter), - "Whenever {this} attacks, if you control a Dinosaur, {this} gets +1/+1 until end of turn." - ); - this.addAbility(ability); + this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn)).withInterveningIf(condition)); } private TilonallisKnight(final TilonallisKnight card) { diff --git a/Mage.Sets/src/mage/cards/t/TimeOfIce.java b/Mage.Sets/src/mage/cards/t/TimeOfIce.java index 4b66573aafb..816d39c49ce 100644 --- a/Mage.Sets/src/mage/cards/t/TimeOfIce.java +++ b/Mage.Sets/src/mage/cards/t/TimeOfIce.java @@ -15,10 +15,15 @@ import mage.constants.SubType; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.constants.SagaChapter.CHAPTER_I; +import static mage.constants.SagaChapter.CHAPTER_II; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * @author TheElk801 */ @@ -43,8 +48,8 @@ public final class TimeOfIce extends CardImpl { effects.add(new TapTargetEffect()); effects.add(new DontUntapInControllersUntapStepTargetEffect(Duration.WhileControlled, "It")); sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, effects, - new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE) + this, CHAPTER_I, CHAPTER_II, effects, + new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE) ); // III — Return all tapped creatures to their owners' hands. diff --git a/Mage.Sets/src/mage/cards/t/TimeToReflect.java b/Mage.Sets/src/mage/cards/t/TimeToReflect.java index bd873cff303..1d0ea5e1497 100644 --- a/Mage.Sets/src/mage/cards/t/TimeToReflect.java +++ b/Mage.Sets/src/mage/cards/t/TimeToReflect.java @@ -63,7 +63,7 @@ enum TimeToReflectAdjuster implements TargetAdjuster { } filter.add(Predicates.or(creaturesThatBlockedOrWereBlockedByAZombie)); ability.getTargets().clear(); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); } } diff --git a/Mage.Sets/src/mage/cards/t/TimeVault.java b/Mage.Sets/src/mage/cards/t/TimeVault.java index 9c30a86b26d..64c1fa116cb 100644 --- a/Mage.Sets/src/mage/cards/t/TimeVault.java +++ b/Mage.Sets/src/mage/cards/t/TimeVault.java @@ -1,7 +1,6 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -15,13 +14,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; -import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** * * @author emerald000 @@ -59,7 +58,7 @@ class TimeVaultReplacementEffect extends ReplacementEffectImpl { TimeVaultReplacementEffect() { super(Duration.WhileOnBattlefield, Outcome.Untap); - staticText = "If you would begin your turn while {this} is tapped, you may skip that turn instead. If you do, untap Time Vault."; + staticText = "If you would begin your turn while {this} is tapped, you may skip that turn instead. If you do, untap {this}."; } private TimeVaultReplacementEffect(final TimeVaultReplacementEffect effect) { diff --git a/Mage.Sets/src/mage/cards/t/TimelyHordemate.java b/Mage.Sets/src/mage/cards/t/TimelyHordemate.java index 51548c4efeb..6a100c597ef 100644 --- a/Mage.Sets/src/mage/cards/t/TimelyHordemate.java +++ b/Mage.Sets/src/mage/cards/t/TimelyHordemate.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.hint.common.RaidHint; import mage.cards.CardImpl; @@ -40,13 +39,9 @@ public final class TimelyHordemate extends CardImpl { this.toughness = new MageInt(2); // Raid — When Timely Hordemate enters the battlefield, if you attacked this turn, return target creature card with converted mana cost 2 or less from your graveyard to the battlefield. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()), RaidCondition.instance, - "When {this} enters, if you attacked this turn, return target creature card with mana value 2 or less from your graveyard to the battlefield."); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()).withInterveningIf(RaidCondition.instance); ability.addTarget(new TargetCardInYourGraveyard(filter)); - ability.setAbilityWord(AbilityWord.RAID); - ability.addHint(RaidHint.instance); - this.addAbility(ability, new PlayerAttackedWatcher()); - + this.addAbility(ability.setAbilityWord(AbilityWord.RAID).addHint(RaidHint.instance), new PlayerAttackedWatcher()); } private TimelyHordemate(final TimelyHordemate card) { diff --git a/Mage.Sets/src/mage/cards/t/TimestreamNavigator.java b/Mage.Sets/src/mage/cards/t/TimestreamNavigator.java index 2e53082b8fd..1a6567498b2 100644 --- a/Mage.Sets/src/mage/cards/t/TimestreamNavigator.java +++ b/Mage.Sets/src/mage/cards/t/TimestreamNavigator.java @@ -6,7 +6,7 @@ import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.costs.common.PutSourceOnBottomOwnerLibraryCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.turn.AddExtraTurnControllerEffect; import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; @@ -14,7 +14,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import java.util.UUID; @@ -36,15 +35,12 @@ public final class TimestreamNavigator extends CardImpl { this.addAbility(new AscendAbility()); // {2}{U}{U}, {T}, Put Timestream Navigator on the bottom of its owner's library: Take an extra turn after this one. Activate this ability only if you have the city's blessing. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new AddExtraTurnControllerEffect(), - new ManaCostsImpl<>("{2}{U}{U}"), - CitysBlessingCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new AddExtraTurnControllerEffect(), new ManaCostsImpl<>("{2}{U}{U}"), CitysBlessingCondition.instance + ); ability.addCost(new TapSourceCost()); ability.addCost(new PutSourceOnBottomOwnerLibraryCost()); - ability.addHint(CitysBlessingHint.instance); - this.addAbility(ability); - + this.addAbility(ability.addHint(CitysBlessingHint.instance)); } private TimestreamNavigator(final TimestreamNavigator card) { diff --git a/Mage.Sets/src/mage/cards/t/TinStreetHooligan.java b/Mage.Sets/src/mage/cards/t/TinStreetHooligan.java index d7b6814117d..afbff085379 100644 --- a/Mage.Sets/src/mage/cards/t/TinStreetHooligan.java +++ b/Mage.Sets/src/mage/cards/t/TinStreetHooligan.java @@ -1,28 +1,25 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.ManaWasSpentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.ColoredManaSymbol; import mage.target.common.TargetArtifactPermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class TinStreetHooligan extends CardImpl { public TinStreetHooligan(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); this.subtype.add(SubType.GOBLIN); this.subtype.add(SubType.ROGUE); @@ -30,10 +27,7 @@ public final class TinStreetHooligan extends CardImpl { this.toughness = new MageInt(1); // When Tin Street Hooligan enters the battlefield, if {G} was spent to cast Tin Street Hooligan, destroy target artifact. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()), - ManaWasSpentCondition.GREEN, - "When {this} enters, if {G} was spent to cast it, destroy target artifact."); + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()).withInterveningIf(ManaWasSpentCondition.GREEN); ability.addTarget(new TargetArtifactPermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TinWingChimera.java b/Mage.Sets/src/mage/cards/t/TinWingChimera.java index 82860ddb9fc..ec1cb34f951 100644 --- a/Mage.Sets/src/mage/cards/t/TinWingChimera.java +++ b/Mage.Sets/src/mage/cards/t/TinWingChimera.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -45,7 +46,7 @@ public final class TinWingChimera extends CardImpl { Ability ability = new SimpleActivatedAbility(new AddCountersTargetEffect(CounterType.P2P2.createInstance()), new SacrificeSourceCost()); ability.addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield) .setText("It gains flying. (This effect lasts indefinitely.)")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TinybonesTrinketThief.java b/Mage.Sets/src/mage/cards/t/TinybonesTrinketThief.java index 72189d70295..88169e2b04a 100644 --- a/Mage.Sets/src/mage/cards/t/TinybonesTrinketThief.java +++ b/Mage.Sets/src/mage/cards/t/TinybonesTrinketThief.java @@ -2,14 +2,13 @@ package mage.cards.t; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -37,14 +36,11 @@ public final class TinybonesTrinketThief extends CardImpl { this.toughness = new MageInt(2); // At the beginning of each end step, if an opponent discarded a card this turn, you draw a card and you lose 1 life. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - TargetController.EACH_PLAYER, new DrawCardSourceControllerEffect(1), - false - ), TinybonesTrinketThiefCondition.instance, "At the beginning of each end step, " + - "if an opponent discarded a card this turn, you draw a card and you lose 1 life." + Ability ability = new BeginningOfEndStepTriggeredAbility( + TargetController.ANY, new DrawCardSourceControllerEffect(1, true), + false, TinybonesTrinketThiefCondition.instance ); - ability.addEffect(new LoseLifeSourceControllerEffect(1)); + ability.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and")); this.addAbility(ability, new TinybonesTrinketThiefWatcher()); // {4}{B}{B}: Each opponent with no cards in hand loses 10 life. @@ -69,6 +65,11 @@ enum TinybonesTrinketThiefCondition implements Condition { TinybonesTrinketThiefWatcher watcher = game.getState().getWatcher(TinybonesTrinketThiefWatcher.class); return watcher != null && watcher.checkPlayer(source.getControllerId()); } + + @Override + public String toString() { + return "an opponent discarded a card this turn"; + } } class TinybonesTrinketThiefWatcher extends Watcher { diff --git a/Mage.Sets/src/mage/cards/t/TitanHunter.java b/Mage.Sets/src/mage/cards/t/TitanHunter.java index ad836e76bed..4697836741b 100644 --- a/Mage.Sets/src/mage/cards/t/TitanHunter.java +++ b/Mage.Sets/src/mage/cards/t/TitanHunter.java @@ -2,25 +2,22 @@ package mage.cards.t; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.MorbidCondition; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.hint.common.MorbidHint; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.TargetController; import mage.filter.StaticFilters; -import mage.game.Game; import java.util.UUID; @@ -29,7 +26,7 @@ import java.util.UUID; */ public final class TitanHunter extends CardImpl { - private static final Condition condition = new InvertCondition(MorbidCondition.instance); + private static final Condition condition = new InvertCondition(MorbidCondition.instance, "no creatures died this turn"); public TitanHunter(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); @@ -40,11 +37,10 @@ public final class TitanHunter extends CardImpl { this.toughness = new MageInt(5); // At the beginning of each player's end step, if no creatures died this turn, Titan Hunter deals 4 damage to that player. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - TargetController.EACH_PLAYER, new TitanHunterEffect(), false - ), condition, "At the beginning of each player's end step, " + - "if no creatures died this turn, {this} deals 4 damage to that player." + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.EACH_PLAYER, + new DamageTargetEffect(4, true, "that player"), + false, condition ).addHint(MorbidHint.instance)); // {1}{B}, Sacrifice a creature: You gain 4 life. @@ -62,27 +58,3 @@ public final class TitanHunter extends CardImpl { return new TitanHunter(this); } } - -class TitanHunterEffect extends OneShotEffect { - - TitanHunterEffect() { - super(Outcome.Benefit); - } - - private TitanHunterEffect(final TitanHunterEffect effect) { - super(effect); - } - - @Override - public TitanHunterEffect copy() { - return new TitanHunterEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - return game.damagePlayerOrPermanent( - game.getActivePlayerId(), 4, source.getSourceId(), - source, game, false, true - ) > 0; - } -} diff --git a/Mage.Sets/src/mage/cards/t/TitaniaVoiceOfGaea.java b/Mage.Sets/src/mage/cards/t/TitaniaVoiceOfGaea.java index c7f8c3e5263..97edb8672ca 100644 --- a/Mage.Sets/src/mage/cards/t/TitaniaVoiceOfGaea.java +++ b/Mage.Sets/src/mage/cards/t/TitaniaVoiceOfGaea.java @@ -2,19 +2,21 @@ package mage.cards.t; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.CompoundCondition; import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; import mage.abilities.condition.common.MeldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.MeldEffect; import mage.abilities.keyword.ReachAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; @@ -28,6 +30,8 @@ import java.util.UUID; public final class TitaniaVoiceOfGaea extends CardImpl { private static final Condition condition = new CompoundCondition( + "there are four or more land cards in your graveyard and you " + + "both own and control {this} and a land named Argoth, Sanctum of Nature", new CardsInControllerGraveyardCondition(4, StaticFilters.FILTER_CARD_LAND), new MeldCondition("Argoth, Sanctum of Nature", CardType.LAND) ); @@ -50,13 +54,9 @@ public final class TitaniaVoiceOfGaea extends CardImpl { this.addAbility(new TitaniaVoiceOfGaeaTriggeredAbility()); // At the beginning of your upkeep, if there are four or more land cards in your graveyard and you both own and control Titania, Voice of Gaea and a land named Argoth, Sanctum of Nature, exile them, then meld them into Titania, Gaea Incarnate. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new MeldEffect( - "Argoth, Sanctum of Nature", "Titania, Gaea Incarnate" - )), condition, "At the beginning of your upkeep, " + - "if there are four or more land cards in your graveyard and you both own and control {this} " + - "and a land named Argoth, Sanctum of Nature, exile them, then meld them into Titania, Gaea Incarnate." - )); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new MeldEffect( + "Argoth, Sanctum of Nature", "Titania, Gaea Incarnate" + )).withInterveningIf(condition)); } private TitaniaVoiceOfGaea(final TitaniaVoiceOfGaea card) { diff --git a/Mage.Sets/src/mage/cards/t/TitaniasChosen.java b/Mage.Sets/src/mage/cards/t/TitaniasChosen.java index 99a42b09c06..2e3ce3ff52a 100644 --- a/Mage.Sets/src/mage/cards/t/TitaniasChosen.java +++ b/Mage.Sets/src/mage/cards/t/TitaniasChosen.java @@ -2,37 +2,41 @@ package mage.cards.t; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.ObjectColor; +import mage.abilities.common.SpellCastAllTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.counters.CounterType; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.stack.Spell; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.ColorPredicate; + +import java.util.UUID; /** - * * @author Backfir3 */ public final class TitaniasChosen extends CardImpl { + private static final FilterSpell filter = new FilterSpell("green spell"); + + static { + filter.add(new ColorPredicate(ObjectColor.GREEN)); + } + public TitaniasChosen(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.ARCHER); this.power = new MageInt(1); this.toughness = new MageInt(1); - + // Whenever a player casts a green spell, put a +1/+1 counter on Titania's Chosen. - this.addAbility(new TitaniasChosenAbility()); + this.addAbility(new SpellCastAllTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter, false)); } private TitaniasChosen(final TitaniasChosen card) { @@ -45,36 +49,3 @@ public final class TitaniasChosen extends CardImpl { } } - -class TitaniasChosenAbility extends TriggeredAbilityImpl { - - public TitaniasChosenAbility() { - super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance())); - } - - private TitaniasChosenAbility(final TitaniasChosenAbility ability) { - super(ability); - } - - @Override - public TitaniasChosenAbility copy() { - return new TitaniasChosenAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.SPELL_CAST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - return spell != null && spell.getColor(game).isGreen(); - } - - @Override - public String getRule() { - return "Whenever a player casts a green spell, put a +1/+1 counter on Titania's Chosen."; - } - -} diff --git a/Mage.Sets/src/mage/cards/t/TitanicBrawl.java b/Mage.Sets/src/mage/cards/t/TitanicBrawl.java index e42199ec912..bb682069167 100644 --- a/Mage.Sets/src/mage/cards/t/TitanicBrawl.java +++ b/Mage.Sets/src/mage/cards/t/TitanicBrawl.java @@ -10,11 +10,14 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author TheElk801 */ @@ -33,7 +36,7 @@ public final class TitanicBrawl extends CardImpl { // Target creature you control fights target creature you don't control. this.getSpellAbility().addEffect(new FightTargetsEffect()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); } private TitanicBrawl(final TitanicBrawl card) { diff --git a/Mage.Sets/src/mage/cards/t/ToTheSlaughter.java b/Mage.Sets/src/mage/cards/t/ToTheSlaughter.java index 0b441cf269c..b61f1451dfd 100644 --- a/Mage.Sets/src/mage/cards/t/ToTheSlaughter.java +++ b/Mage.Sets/src/mage/cards/t/ToTheSlaughter.java @@ -26,7 +26,7 @@ public final class ToTheSlaughter extends CardImpl { this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new SacrificeEffect(new FilterCreatureOrPlaneswalkerPermanent(), 1, "Target player"), new InvertCondition(DeliriumCondition.instance), - "Target player sacrifices a creature or planeswalker.")); + "Target player sacrifices a creature or planeswalker of their choice.")); // Delirium — If there are four or more card types among cards in your graveyard, instead that player sacrifices a creature and a planeswalker. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( @@ -35,7 +35,7 @@ public final class ToTheSlaughter extends CardImpl { "
Delirium — If there are four or more card types among cards in your graveyard, instead that player sacrifices a creature")); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new SacrificeEffect(StaticFilters.FILTER_PERMANENT_PLANESWALKER, 1, "Target player"), - DeliriumCondition.instance, "and a planeswalker.")); + DeliriumCondition.instance, "and a planeswalker of their choice.")); this.getSpellAbility().addTarget(new TargetPlayer()); this.getSpellAbility().addHint(CardTypesInGraveyardCount.YOU.getHint()); } diff --git a/Mage.Sets/src/mage/cards/t/ToilTrouble.java b/Mage.Sets/src/mage/cards/t/ToilTrouble.java index c1c2a83838a..e904bbcffe7 100644 --- a/Mage.Sets/src/mage/cards/t/ToilTrouble.java +++ b/Mage.Sets/src/mage/cards/t/ToilTrouble.java @@ -1,6 +1,5 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.dynamicvalue.common.CardsInTargetHandCount; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; @@ -12,6 +11,8 @@ import mage.constants.CardType; import mage.constants.SpellAbilityType; import mage.target.TargetPlayer; +import java.util.UUID; + public final class ToilTrouble extends SplitCard { public ToilTrouble(UUID ownerId, CardSetInfo setInfo) { @@ -26,7 +27,7 @@ public final class ToilTrouble extends SplitCard { // Trouble // Trouble deals damage to target player equal to the number of cards in that player's hand. Effect effect = new DamageTargetEffect(CardsInTargetHandCount.instance); - effect.setText("Trouble deals damage to target player equal to the number of cards in that player's hand"); + effect.setText("{this} deals damage to target player equal to the number of cards in that player's hand"); getRightHalfCard().getSpellAbility().addEffect(effect); getRightHalfCard().getSpellAbility().addTarget(new TargetPlayer().withChooseHint("to deal damage to")); diff --git a/Mage.Sets/src/mage/cards/t/Tolaria.java b/Mage.Sets/src/mage/cards/t/Tolaria.java index 3bec567d677..e913dd389ee 100644 --- a/Mage.Sets/src/mage/cards/t/Tolaria.java +++ b/Mage.Sets/src/mage/cards/t/Tolaria.java @@ -1,30 +1,31 @@ - package mage.cards.t; -import java.util.UUID; import mage.abilities.ActivatedAbilityImpl; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.continuous.LoseAbilityTargetEffect; import mage.abilities.keyword.BandingAbility; import mage.abilities.keyword.BandsWithOtherAbility; import mage.abilities.mana.BlueManaAbility; -import mage.constants.SuperType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.PhaseStep; -import mage.constants.Zone; +import mage.constants.SuperType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author L_J */ public final class Tolaria extends CardImpl { + private static final Condition condition = new IsStepCondition(PhaseStep.UPKEEP, false); + public Tolaria(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); this.supertype.add(SuperType.LEGENDARY); @@ -33,10 +34,15 @@ public final class Tolaria extends CardImpl { this.addAbility(new BlueManaAbility()); // {T}: Target creature loses banding and all "bands with other" abilities until end of turn. Activate this ability only during any upkeep step. - ActivatedAbilityImpl ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new LoseAbilityTargetEffect(BandingAbility.getInstance(), Duration.EndOfTurn), new TapSourceCost(), new IsStepCondition(PhaseStep.UPKEEP, false), - "{T}: Target creature loses banding and all \"bands with other\" abilities until end of turn. Activate only during any upkeep step."); - ability.addEffect(new LoseAbilityTargetEffect(new BandsWithOtherAbility(), Duration.EndOfTurn)); + ActivatedAbilityImpl ability = new ActivateIfConditionActivatedAbility( + new LoseAbilityTargetEffect( + BandingAbility.getInstance(), Duration.EndOfTurn + ).setText("target creature loses banding"), + new TapSourceCost(), condition + ); + ability.addEffect(new LoseAbilityTargetEffect( + new BandsWithOtherAbility(), Duration.EndOfTurn + ).setText("and all \"bands with other\" abilities until end of turn")); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TolarianAcademy.java b/Mage.Sets/src/mage/cards/t/TolarianAcademy.java index a6ed23bf1ac..235e539bdcd 100644 --- a/Mage.Sets/src/mage/cards/t/TolarianAcademy.java +++ b/Mage.Sets/src/mage/cards/t/TolarianAcademy.java @@ -1,36 +1,27 @@ - - package mage.cards.t; -import java.util.UUID; import mage.Mana; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.ArtifactYouControlCount; +import mage.abilities.hint.common.ArtifactYouControlHint; import mage.abilities.mana.DynamicManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SuperType; -import mage.filter.common.FilterControlledPermanent; + +import java.util.UUID; /** - * * @author Backfir3 */ public final class TolarianAcademy extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("artifact you control"); - - static { - filter.add(CardType.ARTIFACT.getPredicate()); - } - public TolarianAcademy(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); this.supertype.add(SuperType.LEGENDARY); - DynamicManaAbility ability = new DynamicManaAbility(Mana.BlueMana(1), new PermanentsOnBattlefieldCount(filter)); - this.addAbility(ability); + this.addAbility(new DynamicManaAbility(Mana.BlueMana(1), ArtifactYouControlCount.instance).addHint(ArtifactYouControlHint.instance)); } private TolarianAcademy(final TolarianAcademy card) { diff --git a/Mage.Sets/src/mage/cards/t/TolarianEmissary.java b/Mage.Sets/src/mage/cards/t/TolarianEmissary.java index f43b025aa89..8ee277fecae 100644 --- a/Mage.Sets/src/mage/cards/t/TolarianEmissary.java +++ b/Mage.Sets/src/mage/cards/t/TolarianEmissary.java @@ -1,12 +1,9 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.KickerAbility; @@ -16,15 +13,15 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.target.common.TargetEnchantmentPermanent; -/** - * - * @author LoneFox +import java.util.UUID; +/** + * @author LoneFox */ public final class TolarianEmissary extends CardImpl { public TolarianEmissary(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(1); @@ -32,13 +29,14 @@ public final class TolarianEmissary extends CardImpl { // Kicker {1}{W} this.addAbility(new KickerAbility("{1}{W}")); + // Flying this.addAbility(FlyingAbility.getInstance()); + // When Tolarian Emissary enters the battlefield, if it was kicked, destroy target enchantment. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()); + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()).withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetEnchantmentPermanent()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.ONCE, - "When {this} enters, if it was kicked, destroy target enchantment.")); + this.addAbility(ability); } private TolarianEmissary(final TolarianEmissary card) { diff --git a/Mage.Sets/src/mage/cards/t/TolarianSerpent.java b/Mage.Sets/src/mage/cards/t/TolarianSerpent.java index 1825888bdf4..ad9cfedd168 100644 --- a/Mage.Sets/src/mage/cards/t/TolarianSerpent.java +++ b/Mage.Sets/src/mage/cards/t/TolarianSerpent.java @@ -1,32 +1,29 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.effects.common.MillCardsControllerEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.events.GameEvent.EventType; + +import java.util.UUID; /** - * * @author fireshoes */ public final class TolarianSerpent extends CardImpl { public TolarianSerpent(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{U}"); this.subtype.add(SubType.SERPENT); this.power = new MageInt(7); this.toughness = new MageInt(7); // At the beginning of your upkeep, put the top seven cards of your library into your graveyard. - this.addAbility(new OnEventTriggeredAbility(EventType.UPKEEP_STEP_PRE, - "beginning of your upkeep", - new MillCardsControllerEffect(7), false)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new MillCardsControllerEffect(7))); + } private TolarianSerpent(final TolarianSerpent card) { diff --git a/Mage.Sets/src/mage/cards/t/TolsimirMidnightsLight.java b/Mage.Sets/src/mage/cards/t/TolsimirMidnightsLight.java index 1a5ed067aa5..e1e848ec08d 100644 --- a/Mage.Sets/src/mage/cards/t/TolsimirMidnightsLight.java +++ b/Mage.Sets/src/mage/cards/t/TolsimirMidnightsLight.java @@ -1,24 +1,17 @@ package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.AttacksAllTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.common.CreateTokenEffect; -import mage.constants.Duration; -import mage.constants.SetTargetPointer; -import mage.constants.SubType; -import mage.constants.SuperType; import mage.abilities.keyword.LifelinkAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.TargetController; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -26,8 +19,9 @@ import mage.game.permanent.token.TolsimirMidnightsLightToken; import mage.target.common.TargetOpponentsCreaturePermanent; import mage.watchers.common.AttackedOrBlockedThisCombatWatcher; +import java.util.UUID; + /** - * * @author DominionSpy */ public final class TolsimirMidnightsLight extends CardImpl { @@ -54,10 +48,10 @@ public final class TolsimirMidnightsLight extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new TolsimirMidnightsLightToken()))); // Whenever a Wolf you control attacks, if Tolsimir attacked this combat, target creature an opponent controls blocks that Wolf this combat if able. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksAllTriggeredAbility(new TolsimirMidnightsLightEffect(), false, filter, SetTargetPointer.PERMANENT, false), - TolsimirMidnightsLightCondition.instance, - "Whenever a Wolf you control attacks, if {this} attacked this combat, target creature an opponent controls blocks that Wolf this combat if able."); + Ability ability = new AttacksAllTriggeredAbility( + new TolsimirMidnightsLightEffect(), false, filter, + SetTargetPointer.PERMANENT, false + ).withInterveningIf(TolsimirMidnightsLightCondition.instance); ability.addTarget(new TargetOpponentsCreaturePermanent()); this.addAbility(ability, new AttackedOrBlockedThisCombatWatcher()); } @@ -92,12 +86,18 @@ enum TolsimirMidnightsLightCondition implements Condition { } return false; } + + @Override + public String toString() { + return "{this} attacked this combat"; + } } class TolsimirMidnightsLightEffect extends RequirementEffect { TolsimirMidnightsLightEffect() { super(Duration.EndOfCombat); + staticText = "target creature an opponent controls blocks that Wolf this combat if able"; } private TolsimirMidnightsLightEffect(final TolsimirMidnightsLightEffect effect) { diff --git a/Mage.Sets/src/mage/cards/t/TombTyrant.java b/Mage.Sets/src/mage/cards/t/TombTyrant.java index 08e8b632ed3..e09f160fca7 100644 --- a/Mage.Sets/src/mage/cards/t/TombTyrant.java +++ b/Mage.Sets/src/mage/cards/t/TombTyrant.java @@ -19,7 +19,10 @@ import mage.abilities.hint.ValueHint; import mage.abilities.hint.common.MyTurnHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; @@ -44,7 +47,7 @@ public final class TombTyrant extends CardImpl { MyTurnCondition.instance, new CardsInControllerGraveyardCondition(3, filter2) ); private static final Hint hint = new ValueHint( - "Zombie creatures in your graveyard", new CardsInControllerGraveyardCount(filter2) + "Zombie creature cards in your graveyard", new CardsInControllerGraveyardCount(filter2) ); public TombTyrant(UUID ownerId, CardSetInfo setInfo) { @@ -62,7 +65,7 @@ public final class TombTyrant extends CardImpl { // {2}{B}, {T}, Sacrifice a creature: Return a Zombie creature card at random from your graveyard to the battlefield. Activate only during your turn and only if there are at least three Zombie creature cards in your graveyard. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new ReturnFromGraveyardAtRandomEffect(filter2, Zone.BATTLEFIELD), + new ReturnFromGraveyardAtRandomEffect(filter2, Zone.BATTLEFIELD), new ManaCostsImpl<>("{2}{B}"), condition ); ability.addCost(new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/t/ToolcraftExemplar.java b/Mage.Sets/src/mage/cards/t/ToolcraftExemplar.java index 0dc88e49103..625984947c9 100644 --- a/Mage.Sets/src/mage/cards/t/ToolcraftExemplar.java +++ b/Mage.Sets/src/mage/cards/t/ToolcraftExemplar.java @@ -1,34 +1,37 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; -import mage.abilities.condition.LockedInCondition; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.MetalcraftCondition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.Effect; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.AddContinuousEffectToGame; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.common.ArtifactYouControlHint; import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.ComparisonType; import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.common.FilterControlledArtifactPermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class ToolcraftExemplar extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledArtifactPermanent("you control an artifact") + ); + public ToolcraftExemplar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); this.subtype.add(SubType.DWARF); this.subtype.add(SubType.ARTIFICER); this.power = new MageInt(1); @@ -36,16 +39,13 @@ public final class ToolcraftExemplar extends CardImpl { // At the beginning of combat on your turn, if you control an artifact, Toolcraft Exemplar gets +2/+1 until end of turn. // If you control at least 3 artifacts, it also gains first strike until end of turn. - Effect effect = new ConditionalContinuousEffect( - new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn), - new LockedInCondition(new PermanentsOnTheBattlefieldCondition(new FilterControlledArtifactPermanent(), ComparisonType.MORE_THAN, 2)), null); - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfCombatTriggeredAbility(new BoostSourceEffect(2, 1, Duration.EndOfTurn)), - new PermanentsOnTheBattlefieldCondition(new FilterControlledArtifactPermanent()), - "At the beginning of combat on your turn, if you control an artifact, {this} gets +2/+1 until end of turn." - + " If you control at least 3 artifacts, it also gains first strike until end of turn."); - ability.addEffect(effect); - this.addAbility(ability); + Ability ability = new BeginningOfCombatTriggeredAbility(new BoostSourceEffect( + 2, 1, Duration.EndOfTurn + )).withInterveningIf(condition); + ability.addEffect(new ConditionalOneShotEffect(new AddContinuousEffectToGame( + new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn) + ), MetalcraftCondition.instance, "If you control three or more artifacts, it also gains first strike until end of turn")); + this.addAbility(ability.addHint(ArtifactYouControlHint.instance)); } private ToolcraftExemplar(final ToolcraftExemplar card) { diff --git a/Mage.Sets/src/mage/cards/t/ToothCollector.java b/Mage.Sets/src/mage/cards/t/ToothCollector.java index 6e032980e2c..87753466bb7 100644 --- a/Mage.Sets/src/mage/cards/t/ToothCollector.java +++ b/Mage.Sets/src/mage/cards/t/ToothCollector.java @@ -1,34 +1,36 @@ package mage.cards.t; -import java.util.UUID; - import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.*; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * @author fireshoes */ public final class ToothCollector extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("creature that player controls"); + + static { + filter.add(TargetController.ACTIVE.getControllerPredicate()); + } + public ToothCollector(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.HUMAN); @@ -38,18 +40,16 @@ public final class ToothCollector extends CardImpl { // When Tooth Collector enters the battlefield, target creature an opponent controls gets -1/-1 until end of turn. Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-1, -1, Duration.EndOfTurn)); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); // {Delirium — At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, // target creature that player controls gets -1/-1 until end of turn. - ability = new ConditionalInterveningIfTriggeredAbility( - new ToothCollectorAbility(), - DeliriumCondition.instance, - "Delirium — At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, " - + "target creature that player controls gets -1/-1 until end of turn."); - ability.addHint(CardTypesInGraveyardCount.YOU.getHint()); - this.addAbility(ability); + ability = new BeginningOfUpkeepTriggeredAbility( + TargetController.OPPONENT, new BoostTargetEffect(-1, -1), false + ).withInterveningIf(DeliriumCondition.instance); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability.setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); } private ToothCollector(final ToothCollector card) { @@ -61,45 +61,3 @@ public final class ToothCollector extends CardImpl { return new ToothCollector(this); } } - -class ToothCollectorAbility extends TriggeredAbilityImpl { - - public ToothCollectorAbility() { - super(Zone.BATTLEFIELD, new BoostTargetEffect(-1, -1, Duration.EndOfTurn)); - } - - private ToothCollectorAbility(final ToothCollectorAbility ability) { - super(ability); - } - - @Override - public ToothCollectorAbility copy() { - return new ToothCollectorAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (game.getOpponents(controllerId).contains(event.getPlayerId())) { - Player opponent = game.getPlayer(event.getPlayerId()); - if (opponent != null) { - FilterCreaturePermanent FILTER = new FilterCreaturePermanent("creature " + opponent.getLogName() + " controls"); - FILTER.add(new ControllerIdPredicate(opponent.getId())); - this.getTargets().clear(); - this.addTarget(new TargetCreaturePermanent(FILTER)); - return true; - } - } - return false; - } - - @Override - public String getRule() { - return "Delirium — At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, " - + "target creature that player controls gets -1/-1 until end of turn."; - } -} diff --git a/Mage.Sets/src/mage/cards/t/TopanAscetic.java b/Mage.Sets/src/mage/cards/t/TopanAscetic.java index 6343817994c..fd469d319a9 100644 --- a/Mage.Sets/src/mage/cards/t/TopanAscetic.java +++ b/Mage.Sets/src/mage/cards/t/TopanAscetic.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapTargetCost; @@ -9,27 +7,19 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author Plopman */ public final class TopanAscetic extends CardImpl { - - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); - static{ - filter.add(TappedPredicate.UNTAPPED); - } - public TopanAscetic(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.MONK); @@ -37,7 +27,10 @@ public final class TopanAscetic extends CardImpl { this.toughness = new MageInt(2); // Tap an untapped creature you control: Topan Ascetic gets +1/+1 until end of turn. - this.addAbility(new SimpleActivatedAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn), new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, true)))); + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(1, 1, Duration.EndOfTurn), + new TapTargetCost(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE) + )); } private TopanAscetic(final TopanAscetic card) { diff --git a/Mage.Sets/src/mage/cards/t/Topple.java b/Mage.Sets/src/mage/cards/t/Topple.java index b5c3d5eb9c9..04b93b63c86 100644 --- a/Mage.Sets/src/mage/cards/t/Topple.java +++ b/Mage.Sets/src/mage/cards/t/Topple.java @@ -1,18 +1,18 @@ package mage.cards.t; -import mage.MageObject; -import mage.abilities.Ability; +import mage.abilities.dynamicvalue.common.GreatestAmongPermanentsValue; import mage.abilities.effects.common.ExileTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; -import java.util.HashSet; -import java.util.List; -import java.util.Set; import java.util.UUID; /** @@ -20,12 +20,19 @@ import java.util.UUID; */ public final class Topple extends CardImpl { + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature with the greatest power among creatures on the battlefield"); + + static { + filter.add(TopplePredicate.instance); + } + public Topple(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}"); // Exile target creature with the greatest power among creatures on the battlefield. this.getSpellAbility().addEffect(new ExileTargetEffect()); - this.getSpellAbility().addTarget(new ToppleTargetCreature()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private Topple(final Topple card) { @@ -38,65 +45,12 @@ public final class Topple extends CardImpl { } } -class ToppleTargetCreature extends TargetCreaturePermanent { - - public ToppleTargetCreature() { - super(); - withTargetName("creature with the greatest power among creatures on the battlefield"); - } - - private ToppleTargetCreature(final ToppleTargetCreature target) { - super(target); - } +enum TopplePredicate implements ObjectSourcePlayerPredicate { + instance; @Override - public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (super.canTarget(controllerId, id, source, game)) { - int maxPower = 0; - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { - if (permanent.getPower().getValue() > maxPower) { - maxPower = permanent.getPower().getValue(); - } - } - Permanent targetPermanent = game.getPermanent(id); - if (targetPermanent != null) { - return targetPermanent.getPower().getValue() == maxPower; - } - } - return false; - } - - @Override - public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { - int maxPower = 0; - List activePermanents = game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game); - Set possibleTargets = new HashSet<>(); - MageObject targetSource = game.getObject(source); - if (targetSource == null) { - return possibleTargets; - } - for (Permanent permanent : activePermanents) { - if (permanent.getPower().getValue() > maxPower) { - maxPower = permanent.getPower().getValue(); - } - } - for (Permanent permanent : activePermanents) { - if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) { - if (permanent.getPower().getValue() == maxPower) { - possibleTargets.add(permanent.getId()); - } - } - } - return possibleTargets; - } - - @Override - public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { - return !possibleTargets(sourceControllerId, source, game).isEmpty(); - } - - @Override - public ToppleTargetCreature copy() { - return new ToppleTargetCreature(this); + public boolean apply(ObjectSourcePlayer input, Game game) { + return input.getObject().getPower().getValue() + >= GreatestAmongPermanentsValue.POWER_ALL_CREATURES.calculate(game, input.getSource(), null); } } diff --git a/Mage.Sets/src/mage/cards/t/Topplegeist.java b/Mage.Sets/src/mage/cards/t/Topplegeist.java index c7123946614..fc2727d38c3 100644 --- a/Mage.Sets/src/mage/cards/t/Topplegeist.java +++ b/Mage.Sets/src/mage/cards/t/Topplegeist.java @@ -1,34 +1,40 @@ package mage.cards.t; -import java.util.UUID; - import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * @author fireshoes */ public final class Topplegeist extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("creature that player controls"); + + static { + filter.add(TargetController.ACTIVE.getControllerPredicate()); + } + public Topplegeist(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); this.subtype.add(SubType.SPIRIT); @@ -40,18 +46,15 @@ public final class Topplegeist extends CardImpl { // When Topplegeist enters the battlefield, tap target creature an opponent controls. Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); // Delirium — At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, // tap target creature that player controls. - ability = new ConditionalInterveningIfTriggeredAbility( - new TopplegeistAbility(), - DeliriumCondition.instance, - "Delirium — At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, " - + "tap target creature that player controls."); - ability.addHint(CardTypesInGraveyardCount.YOU.getHint()); - this.addAbility(ability); + ability = new BeginningOfUpkeepTriggeredAbility(TargetController.OPPONENT, new TapTargetEffect(), false) + .withInterveningIf(DeliriumCondition.instance); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability.setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); } private Topplegeist(final Topplegeist card) { @@ -63,44 +66,3 @@ public final class Topplegeist extends CardImpl { return new Topplegeist(this); } } - -class TopplegeistAbility extends TriggeredAbilityImpl { - - public TopplegeistAbility() { - super(Zone.BATTLEFIELD, new TapTargetEffect()); - } - - private TopplegeistAbility(final TopplegeistAbility ability) { - super(ability); - } - - @Override - public TopplegeistAbility copy() { - return new TopplegeistAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (game.getOpponents(controllerId).contains(event.getPlayerId())) { - Player opponent = game.getPlayer(event.getPlayerId()); - if (opponent != null) { - FilterCreaturePermanent FILTER = new FilterCreaturePermanent("creature " + opponent.getLogName() + " controls"); - FILTER.add(new ControllerIdPredicate(opponent.getId())); - this.getTargets().clear(); - this.addTarget(new TargetCreaturePermanent(FILTER)); - return true; - } - } - return false; - } - - @Override - public String getRule() { - return "At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, tap target creature that player controls."; - } -} diff --git a/Mage.Sets/src/mage/cards/t/ToralfGodOfFury.java b/Mage.Sets/src/mage/cards/t/ToralfGodOfFury.java index 74aee9a3904..3c697cd96e6 100644 --- a/Mage.Sets/src/mage/cards/t/ToralfGodOfFury.java +++ b/Mage.Sets/src/mage/cards/t/ToralfGodOfFury.java @@ -35,6 +35,7 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetAnyTarget; import mage.target.common.TargetPermanentOrPlayer; +import mage.target.targetadjustment.DefineByTriggerTargetAdjuster; import java.util.UUID; @@ -98,6 +99,7 @@ class ToralfGodOfFuryTriggeredAbility extends TriggeredAbilityImpl implements Ba ToralfGodOfFuryTriggeredAbility() { super(Zone.BATTLEFIELD, null); + this.setTargetAdjuster(DefineByTriggerTargetAdjuster.instance); } private ToralfGodOfFuryTriggeredAbility(final ToralfGodOfFuryTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/t/TorchSlinger.java b/Mage.Sets/src/mage/cards/t/TorchSlinger.java index 8baa54da394..5f7114699bb 100644 --- a/Mage.Sets/src/mage/cards/t/TorchSlinger.java +++ b/Mage.Sets/src/mage/cards/t/TorchSlinger.java @@ -1,11 +1,9 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; @@ -14,14 +12,15 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class TorchSlinger extends CardImpl { public TorchSlinger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); this.subtype.add(SubType.GOBLIN); this.subtype.add(SubType.SHAMAN); @@ -31,11 +30,10 @@ public final class TorchSlinger extends CardImpl { // Kicker {1}{R} (You may pay an additional {1}{R} as you cast this spell.) this.addAbility(new KickerAbility("{1}{R}")); - // When Torch Slinger enters the battlefield, if it was kicked, it deals 2 damage to target creature. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2), false); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2, "it")).withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.ONCE, "When {this} enters, if it was kicked, it deals 2 damage to target creature.")); + this.addAbility(ability); } private TorchSlinger(final TorchSlinger card) { diff --git a/Mage.Sets/src/mage/cards/t/TotentanzSwarmPiper.java b/Mage.Sets/src/mage/cards/t/TotentanzSwarmPiper.java index ecbbdf204c0..b3104dc78ef 100644 --- a/Mage.Sets/src/mage/cards/t/TotentanzSwarmPiper.java +++ b/Mage.Sets/src/mage/cards/t/TotentanzSwarmPiper.java @@ -18,7 +18,7 @@ import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.AttackingPredicate; import mage.game.permanent.token.RatCantBlockToken; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -55,7 +55,7 @@ public final class TotentanzSwarmPiper extends CardImpl { new GainAbilityTargetEffect(DeathtouchAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{1}{B}") ); - ability.addTarget(new TargetControlledCreaturePermanent(filterRat)); + ability.addTarget(new TargetPermanent(filterRat)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TourachDreadCantor.java b/Mage.Sets/src/mage/cards/t/TourachDreadCantor.java index 4b7288f163b..ae65816330d 100644 --- a/Mage.Sets/src/mage/cards/t/TourachDreadCantor.java +++ b/Mage.Sets/src/mage/cards/t/TourachDreadCantor.java @@ -6,7 +6,6 @@ import mage.abilities.Ability; import mage.abilities.common.DiscardsACardOpponentTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.keyword.KickerAbility; @@ -47,11 +46,7 @@ public final class TourachDreadCantor extends CardImpl { )); // When Tourach enters the battelfield, if it was kicked, target opponent discards two cards at random. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(2, true)), - KickedCondition.ONCE, "When {this} enters, if it was kicked, " + - "target opponent discards two cards at random." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(2, true)).withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetOpponent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TourachsGate.java b/Mage.Sets/src/mage/cards/t/TourachsGate.java index b59271eef10..fe8268f12f0 100644 --- a/Mage.Sets/src/mage/cards/t/TourachsGate.java +++ b/Mage.Sets/src/mage/cards/t/TourachsGate.java @@ -1,85 +1,84 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.AttachedToMatchesFilterCondition; -import mage.abilities.costs.Cost; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.common.TapAttachedCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; import mage.abilities.keyword.EnchantAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Outcome; -import mage.constants.Duration; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.counters.CounterType; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AttackingPredicate; import mage.filter.predicate.permanent.TappedPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; import mage.target.TargetPermanent; -import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; /** - * * @author L_J */ public final class TourachsGate extends CardImpl { - private static final FilterControlledPermanent filterLand = new FilterControlledPermanent("land you control"); - static { - filterLand.add(CardType.LAND.getPredicate()); - } - - private static final FilterPermanent filterUntapped = new FilterPermanent("enchanted land is untapped"); - static { - filterUntapped.add(TappedPredicate.UNTAPPED); - } - private static final FilterCreaturePermanent filterAttackingCreatures = new FilterCreaturePermanent("attacking creatures you control"); + private static final FilterPermanent filterUntapped = new FilterPermanent("enchanted land is untapped"); + private static final FilterControlledPermanent filterThrull = new FilterControlledPermanent(SubType.THRULL, "a Thrull"); + static { filterAttackingCreatures.add(AttackingPredicate.instance); filterAttackingCreatures.add(TargetController.YOU.getControllerPredicate()); + filterUntapped.add(TappedPredicate.UNTAPPED); } - private static final FilterControlledPermanent filterThrull = new FilterControlledPermanent(SubType.THRULL, "a Thrull"); + private static final Condition condition = new SourceHasCounterCondition(CounterType.TIME, ComparisonType.EQUAL_TO, 0); + private static final Condition condition2 = new AttachedToMatchesFilterCondition(filterUntapped); public TourachsGate(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{B}"); this.subtype.add(SubType.AURA); // Enchant land you control - TargetPermanent auraTarget = new TargetControlledPermanent(filterLand); + TargetPermanent auraTarget = new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); - Ability ability = new EnchantAbility(auraTarget); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget)); // Sacrifice a Thrull: Put three time counters on Tourach's Gate. - this.addAbility(new SimpleActivatedAbility(new AddCountersSourceEffect(CounterType.TIME.createInstance(3)), - new SacrificeTargetCost(filterThrull))); - + this.addAbility(new SimpleActivatedAbility( + new AddCountersSourceEffect(CounterType.TIME.createInstance(3)), + new SacrificeTargetCost(filterThrull) + )); + // At the beginning of your upkeep, remove a time counter from Tourach's Gate. If there are no time counters on Tourach's Gate, sacrifice it. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TourachsGateUpkeepEffect())); + Ability ability = new BeginningOfUpkeepTriggeredAbility( + new RemoveCounterSourceEffect(CounterType.TIME.createInstance()) + ); + ability.addEffect(new ConditionalOneShotEffect( + new SacrificeSourceEffect(), condition, + "If there are no time counters on {this}, sacrifice it" + )); + this.addAbility(ability); // Tap enchanted land: Attacking creatures you control get +2/-1 until end of turn. Activate this ability only if enchanted land is untapped. - Cost cost = new TapAttachedCost(); - cost.setText("Tap enchanted land"); - this.addAbility(new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new BoostAllEffect(2, -1, Duration.EndOfTurn, filterAttackingCreatures, false), - cost, new AttachedToMatchesFilterCondition(filterUntapped))); + this.addAbility(new ActivateIfConditionActivatedAbility(new BoostAllEffect( + 2, -1, Duration.EndOfTurn, + filterAttackingCreatures, false + ), new TapAttachedCost().setText("tap enchanted land"), condition2)); } private TourachsGate(final TourachsGate card) { @@ -91,38 +90,3 @@ public final class TourachsGate extends CardImpl { return new TourachsGate(this); } } - -class TourachsGateUpkeepEffect extends OneShotEffect { - - TourachsGateUpkeepEffect() { - super(Outcome.Sacrifice); - staticText = "remove a time counter from {this}. If there are no time counters on {this}, sacrifice it"; - } - - private TourachsGateUpkeepEffect(final TourachsGateUpkeepEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - int amount = permanent.getCounters(game).getCount(CounterType.TIME); - if (amount > 0) { - permanent.removeCounters(CounterType.TIME.createInstance(), source, game); - } - // is supposed to function similar to Vanishing - amount = permanent.getCounters(game).getCount(CounterType.TIME); - if (amount == 0) { - permanent.sacrifice(source, game); - } - return true; - } - return false; - } - - @Override - public TourachsGateUpkeepEffect copy() { - return new TourachsGateUpkeepEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TovolarDireOverlord.java b/Mage.Sets/src/mage/cards/t/TovolarDireOverlord.java index caed280491a..38c837a9a2b 100644 --- a/Mage.Sets/src/mage/cards/t/TovolarDireOverlord.java +++ b/Mage.Sets/src/mage/cards/t/TovolarDireOverlord.java @@ -2,17 +2,16 @@ package mage.cards.t; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; import mage.abilities.keyword.DayboundAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -31,7 +30,7 @@ import java.util.UUID; */ public final class TovolarDireOverlord extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent("a Wolf or Werewolf you control"); + private static final FilterPermanent filter = new FilterControlledPermanent("you control three or more Wolves and/or Werewolves"); static { filter.add(Predicates.or( @@ -57,15 +56,10 @@ public final class TovolarDireOverlord extends CardImpl { this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility( new DrawCardSourceControllerEffect(1), filter, false, SetTargetPointer.NONE, true - )); + ).setTriggerPhrase("Whenever a Wolf or Werewolf you control deals combat damage to a player, ")); // At the beginning of your upkeep, if you control three or more Wolves and/or Werewolves, it becomes night. Then transform any number of Human Werewolves you control. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - new TovolarDireOverlordEffect(), false - ), condition, "At the beginning of your upkeep, if you control three or more Wolves " + - "and/or Werewolves, it becomes night. Then transform any number of Human Werewolves you control." - )); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TovolarDireOverlordEffect()).withInterveningIf(condition).addHint(hint)); // Daybound this.addAbility(new DayboundAbility()); @@ -92,6 +86,7 @@ class TovolarDireOverlordEffect extends OneShotEffect { TovolarDireOverlordEffect() { super(Outcome.Benefit); + staticText = "it becomes night. Then transform any number of Human Werewolves you control"; } private TovolarDireOverlordEffect(final TovolarDireOverlordEffect effect) { diff --git a/Mage.Sets/src/mage/cards/t/TownGossipmonger.java b/Mage.Sets/src/mage/cards/t/TownGossipmonger.java index 50cbd67ab97..1ebe153eed6 100644 --- a/Mage.Sets/src/mage/cards/t/TownGossipmonger.java +++ b/Mage.Sets/src/mage/cards/t/TownGossipmonger.java @@ -1,8 +1,5 @@ - package mage.cards.t; -import java.util.UUID; - import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -14,22 +11,15 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.filter.StaticFilters; + +import java.util.UUID; /** * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class TownGossipmonger extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); - - static { - filter.add(TappedPredicate.UNTAPPED); - } - public TownGossipmonger(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); this.subtype.add(SubType.HUMAN); @@ -41,7 +31,7 @@ public final class TownGossipmonger extends CardImpl { // {T}, Tap an untapped creature you control: Transform Town Gossipmonger. this.addAbility(new TransformAbility()); Ability ability = new SimpleActivatedAbility(new TransformSourceEffect(), new TapSourceCost()); - ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, true))); + ability.addCost(new TapTargetCost(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/ToxicStench.java b/Mage.Sets/src/mage/cards/t/ToxicStench.java index 444de87702e..3749e340633 100644 --- a/Mage.Sets/src/mage/cards/t/ToxicStench.java +++ b/Mage.Sets/src/mage/cards/t/ToxicStench.java @@ -10,10 +10,13 @@ import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * @author TheElk801 */ @@ -31,7 +34,7 @@ public final class ToxicStench extends CardImpl { AbilityWord.THRESHOLD.formatWord() + "If seven or more cards are in your graveyard, " + "instead destroy that creature. It can't be regenerated." )); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); } private ToxicStench(final ToxicStench card) { diff --git a/Mage.Sets/src/mage/cards/t/TradeCaravan.java b/Mage.Sets/src/mage/cards/t/TradeCaravan.java index a5d4e318f70..3205bd8e757 100644 --- a/Mage.Sets/src/mage/cards/t/TradeCaravan.java +++ b/Mage.Sets/src/mage/cards/t/TradeCaravan.java @@ -1,30 +1,29 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.CompoundCondition; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.condition.common.OnOpponentsTurnCondition; -import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.costs.common.RemoveCountersSourceCost; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.PhaseStep; +import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterLandPermanent; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author L_J */ public final class TradeCaravan extends CardImpl { @@ -35,8 +34,14 @@ public final class TradeCaravan extends CardImpl { filter.add(SuperType.BASIC.getPredicate()); } + private static final Condition condition = new CompoundCondition( + "during an opponent's upkeep", + OnOpponentsTurnCondition.instance, + new IsStepCondition(PhaseStep.UPKEEP, false) + ); + public TradeCaravan(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.NOMAD); this.power = new MageInt(1); @@ -44,10 +49,11 @@ public final class TradeCaravan extends CardImpl { // At the beginning of your upkeep, put a currency counter on Trade Caravan. this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.CURRENCY.createInstance()))); + // Remove two currency counters from Trade Caravan: Untap target basic land. Activate this ability only during an opponent's upkeep. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new UntapTargetEffect(), new RemoveCountersSourceCost(CounterType.CURRENCY.createInstance(2)), - new CompoundCondition(OnOpponentsTurnCondition.instance, new IsStepCondition(PhaseStep.UPKEEP, false)), - "Remove two currency counters from {this}: Untap target basic land. Activate only during an opponent's upkeep."); + Ability ability = new ActivateIfConditionActivatedAbility( + new UntapTargetEffect(), new RemoveCountersSourceCost(CounterType.CURRENCY.createInstance(2)), condition + ); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TradewindRider.java b/Mage.Sets/src/mage/cards/t/TradewindRider.java index f4263b54f89..652ef4bf5ad 100644 --- a/Mage.Sets/src/mage/cards/t/TradewindRider.java +++ b/Mage.Sets/src/mage/cards/t/TradewindRider.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -13,32 +11,27 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; +import mage.filter.StaticFilters; import mage.target.TargetPermanent; -import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; /** * @author Loki */ public final class TradewindRider extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); - - static { - filter.add(TappedPredicate.UNTAPPED); - } - public TradewindRider(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); this.subtype.add(SubType.SPIRIT); this.power = new MageInt(1); this.toughness = new MageInt(4); + this.addAbility(FlyingAbility.getInstance()); + Ability ability = new SimpleActivatedAbility(new ReturnToHandTargetEffect(), new TapSourceCost()); - ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(2, 2, filter, false))); + ability.addCost(new TapTargetCost(2, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES)); ability.addTarget(new TargetPermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TragicTrajectory.java b/Mage.Sets/src/mage/cards/t/TragicTrajectory.java new file mode 100644 index 00000000000..ba467847b25 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TragicTrajectory.java @@ -0,0 +1,46 @@ +package mage.cards.t; + +import mage.abilities.condition.common.VoidCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.AddContinuousEffectToGame; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; +import mage.watchers.common.VoidWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TragicTrajectory extends CardImpl { + + public TragicTrajectory(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); + + // Target creature gets -2/-2 until end of turn. + // Void -- That creature gets -10/-10 until end of turn instead if a nonland permanent left the battlefield this turn or a spell was warped this turn. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new AddContinuousEffectToGame(new BoostTargetEffect(-10, -10)), + new AddContinuousEffectToGame(new BoostTargetEffect(-2, -2)), + VoidCondition.instance, "Target creature gets -2/-2 until end of turn.
" + + AbilityWord.VOID.formatWord() + "That creature gets -10/-10 until end of turn instead " + + "if a nonland permanent left the battlefield this turn or a spell was warped this turn" + )); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addHint(VoidCondition.getHint()); + this.getSpellAbility().addWatcher(new VoidWatcher()); + } + + private TragicTrajectory(final TragicTrajectory card) { + super(card); + } + + @Override + public TragicTrajectory copy() { + return new TragicTrajectory(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TraitorsRoar.java b/Mage.Sets/src/mage/cards/t/TraitorsRoar.java index 7b300ac518c..85f3c87571d 100644 --- a/Mage.Sets/src/mage/cards/t/TraitorsRoar.java +++ b/Mage.Sets/src/mage/cards/t/TraitorsRoar.java @@ -12,6 +12,7 @@ import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -31,7 +32,7 @@ public final class TraitorsRoar extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B/R}"); // Tap target untapped creature. It deals damage equal to its power to its controller. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new TraitorsRoarEffect()); // Conspire diff --git a/Mage.Sets/src/mage/cards/t/Transpose.java b/Mage.Sets/src/mage/cards/t/Transpose.java index fd6a36e7dad..4f1c970d57b 100644 --- a/Mage.Sets/src/mage/cards/t/Transpose.java +++ b/Mage.Sets/src/mage/cards/t/Transpose.java @@ -57,7 +57,7 @@ enum TransposeCondition implements Condition { .map(Ability::getSourceId) .map(game::getSpell) .map(Spell::getFromZone) - .map(Zone.GRAVEYARD::match) + .map(Zone.HAND::match) .orElse(false); } diff --git a/Mage.Sets/src/mage/cards/t/TrapRunner.java b/Mage.Sets/src/mage/cards/t/TrapRunner.java index 1b009185d0f..b51e145b59d 100644 --- a/Mage.Sets/src/mage/cards/t/TrapRunner.java +++ b/Mage.Sets/src/mage/cards/t/TrapRunner.java @@ -7,18 +7,18 @@ import mage.abilities.condition.Condition; import mage.abilities.condition.common.AfterBlockersAreDeclaredCondition; import mage.abilities.condition.common.IsPhaseCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.BecomeBlockedTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TurnPhase; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.AttackingPredicate; import mage.filter.predicate.permanent.BlockedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -50,10 +50,8 @@ public final class TrapRunner extends CardImpl { this.toughness = new MageInt(3); // {T}: Target unblocked attacking creature becomes blocked. Activate this ability only during combat after blockers are declared. - Ability ability = new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new BecomeBlockedTargetEffect(), new TapSourceCost(), condition - ); - ability.addTarget(new TargetCreaturePermanent(filter)); + Ability ability = new ActivateIfConditionActivatedAbility(new BecomeBlockedTargetEffect(), new TapSourceCost(), condition); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TrenzaloreClocktower.java b/Mage.Sets/src/mage/cards/t/TrenzaloreClocktower.java index 6117c0403a5..734c2d9430e 100644 --- a/Mage.Sets/src/mage/cards/t/TrenzaloreClocktower.java +++ b/Mage.Sets/src/mage/cards/t/TrenzaloreClocktower.java @@ -8,7 +8,7 @@ import mage.abilities.costs.common.ExileSourceCost; import mage.abilities.costs.common.RemoveCountersSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; @@ -47,7 +47,7 @@ public final class TrenzaloreClocktower extends CardImpl { // {1}{U}, {T}, Remove twelve time counters from Trenzalore Clocktower and exile it: // Shuffle your graveyard and hand into your library, then draw seven cards. // Activate only if you control a Time Lord. - Ability wheelAbility = new ConditionalActivatedAbility( + Ability wheelAbility = new ActivateIfConditionActivatedAbility( new TrenzaloreClocktowerEffect(), new ManaCostsImpl<>("{1}{U}"), new PermanentsOnTheBattlefieldCondition(filter)); diff --git a/Mage.Sets/src/mage/cards/t/TriadOfFates.java b/Mage.Sets/src/mage/cards/t/TriadOfFates.java index 7018bf840ce..aefb03653b0 100644 --- a/Mage.Sets/src/mage/cards/t/TriadOfFates.java +++ b/Mage.Sets/src/mage/cards/t/TriadOfFates.java @@ -16,10 +16,13 @@ import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * @author LevelX2 */ @@ -43,21 +46,21 @@ public final class TriadOfFates extends CardImpl { // {1}, {T}: Put a fate counter on another target creature. Ability ability = new SimpleActivatedAbility(new AddCountersTargetEffect(CounterType.FATE.createInstance()), new ManaCostsImpl<>("{1}")); ability.addCost(new TapSourceCost()); - Target target = new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE); + Target target = new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE); ability.addTarget(target); this.addAbility(ability); // {W}, {T}: Exile target creature that has a fate counter on it, then return it to the battlefield under its owner's control. ability = new SimpleActivatedAbility(new ExileThenReturnTargetEffect(false, false), new ManaCostsImpl<>("{W}")); ability.addCost(new TapSourceCost()); - target = new TargetCreaturePermanent(filterCounter); + target = new TargetPermanent(filterCounter); ability.addTarget(target); this.addAbility(ability); // {B}, {T}: Exile target creature that has a fate counter on it. Its controller draws two cards. ability = new SimpleActivatedAbility(new ExileTargetEffect(), new ManaCostsImpl<>("{B}")); ability.addCost(new TapSourceCost()); - target = new TargetCreaturePermanent(filterCounter); + target = new TargetPermanent(filterCounter); ability.addTarget(target); ability.addEffect(new DrawCardTargetControllerEffect(2)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/t/TriangleOfWar.java b/Mage.Sets/src/mage/cards/t/TriangleOfWar.java index 00161dbaaf4..71aefc637b4 100644 --- a/Mage.Sets/src/mage/cards/t/TriangleOfWar.java +++ b/Mage.Sets/src/mage/cards/t/TriangleOfWar.java @@ -12,9 +12,12 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author fireshoes @@ -30,7 +33,7 @@ public final class TriangleOfWar extends CardImpl { new ManaCostsImpl<>("{2}")); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetControlledCreaturePermanent()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TriassicEgg.java b/Mage.Sets/src/mage/cards/t/TriassicEgg.java index efb88ddb034..ee831518ef7 100644 --- a/Mage.Sets/src/mage/cards/t/TriassicEgg.java +++ b/Mage.Sets/src/mage/cards/t/TriassicEgg.java @@ -8,7 +8,7 @@ import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; @@ -39,7 +39,7 @@ public final class TriassicEgg extends CardImpl { this.addAbility(ability); // Sacrifice Triassic Egg: Choose one - You may put a creature card from your hand onto the battlefield; - ability = new ConditionalActivatedAbility( + ability = new ActivateIfConditionActivatedAbility( new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_CREATURE_A), new SacrificeSourceCost(), condition ).hideCondition(); diff --git a/Mage.Sets/src/mage/cards/t/TrickShot.java b/Mage.Sets/src/mage/cards/t/TrickShot.java index 8bf34ed7989..9eeb2b6385f 100644 --- a/Mage.Sets/src/mage/cards/t/TrickShot.java +++ b/Mage.Sets/src/mage/cards/t/TrickShot.java @@ -7,6 +7,7 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.other.AnotherTargetPredicate; import mage.filter.predicate.permanent.TokenPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.SecondTargetPointer; @@ -29,7 +30,7 @@ public final class TrickShot extends CardImpl { // Trick Shot deals 6 damage to target creature and 2 damage to up to one other target creature token. this.getSpellAbility().addTarget(new TargetCreaturePermanent().setTargetTag(1)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1, filter, false).setTargetTag(2)); + this.getSpellAbility().addTarget(new TargetPermanent(0, 1, filter).setTargetTag(2)); this.getSpellAbility().addEffect(new DamageTargetEffect(6, true, "", true)); this.getSpellAbility().addEffect( new DamageTargetEffect(2, true, "", true) diff --git a/Mage.Sets/src/mage/cards/t/TripWire.java b/Mage.Sets/src/mage/cards/t/TripWire.java index bdaa8cd194b..702896736fb 100644 --- a/Mage.Sets/src/mage/cards/t/TripWire.java +++ b/Mage.Sets/src/mage/cards/t/TripWire.java @@ -9,6 +9,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -26,7 +27,7 @@ public final class TripWire extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{G}"); // Destroy target creature with horsemanship. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/t/Triskaidekaphile.java b/Mage.Sets/src/mage/cards/t/Triskaidekaphile.java index 4ba44009dff..fcd7a5df6fa 100644 --- a/Mage.Sets/src/mage/cards/t/Triskaidekaphile.java +++ b/Mage.Sets/src/mage/cards/t/Triskaidekaphile.java @@ -1,19 +1,21 @@ package mage.cards.t; import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInHandCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.WinGameSourceControllerEffect; import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.SubType; import java.util.UUID; @@ -39,12 +41,7 @@ public final class Triskaidekaphile extends CardImpl { ))); // At the beginning of your upkeep, if you have exactly thirteen cards in your hand, you win the game. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - new WinGameSourceControllerEffect(), false - ), condition, "At the beginning of your upkeep, " + - "if you have exactly thirteen cards in your hand, you win the game." - )); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect()).withInterveningIf(condition)); // {3}{U}: Draw a card. this.addAbility(new SimpleActivatedAbility( diff --git a/Mage.Sets/src/mage/cards/t/Triskaidekaphobia.java b/Mage.Sets/src/mage/cards/t/Triskaidekaphobia.java index 56990c197fb..b85a311c838 100644 --- a/Mage.Sets/src/mage/cards/t/Triskaidekaphobia.java +++ b/Mage.Sets/src/mage/cards/t/Triskaidekaphobia.java @@ -1,33 +1,34 @@ - package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GainLifeAllEffect; +import mage.abilities.effects.common.LoseLifeAllPlayersEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; -import mage.players.PlayerList; + +import java.util.UUID; /** - * * @author fireshoes */ public final class Triskaidekaphobia extends CardImpl { public Triskaidekaphobia(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}"); // At the beginning of your upkeep, choose one - Each player with exactly 13 life loses the game, then each player gains 1 life. // Each player with exactly 13 life loses the game, then each player loses 1 life. Ability ability = new BeginningOfUpkeepTriggeredAbility(new TriskaidekaphobiaGainLifeEffect()); - Mode mode = new Mode(new TriskaidekaphobiaLoseLifeEffect()); - ability.addMode(mode); + ability.addEffect(new GainLifeAllEffect(1).concatBy(", then")); + ability.addMode(new Mode(new TriskaidekaphobiaGainLifeEffect()) + .addEffect(new LoseLifeAllPlayersEffect(1).concatBy(", then"))); this.addAbility(ability); } @@ -45,7 +46,7 @@ class TriskaidekaphobiaGainLifeEffect extends OneShotEffect { TriskaidekaphobiaGainLifeEffect() { super(Outcome.Neutral); - this.staticText = "Each player with exactly 13 life loses the game, then each player gains 1 life"; + this.staticText = "each player with exactly 13 life loses the game"; } private TriskaidekaphobiaGainLifeEffect(final TriskaidekaphobiaGainLifeEffect effect) { @@ -59,60 +60,10 @@ class TriskaidekaphobiaGainLifeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int life; - PlayerList playerList = game.getState().getPlayersInRange(source.getControllerId(), game); - for (UUID pid : playerList) { - Player player = game.getPlayer(pid); - if (player != null) { - life = player.getLife(); - if (life == 13) { - player.lost(game); - } - } - } - for (UUID pid : playerList) { - Player player = game.getPlayer(pid); - if (player != null) { - player.gainLife(1, game, source); - } - } - return true; - } -} - -class TriskaidekaphobiaLoseLifeEffect extends OneShotEffect { - - TriskaidekaphobiaLoseLifeEffect() { - super(Outcome.Neutral); - this.staticText = "Each player with exactly 13 life loses the game, then each player loses 1 life"; - } - - private TriskaidekaphobiaLoseLifeEffect(final TriskaidekaphobiaLoseLifeEffect effect) { - super(effect); - } - - @Override - public TriskaidekaphobiaLoseLifeEffect copy() { - return new TriskaidekaphobiaLoseLifeEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - int life; - PlayerList playerList = game.getState().getPlayersInRange(source.getControllerId(), game); - for (UUID pid : playerList) { - Player player = game.getPlayer(pid); - if (player != null) { - life = player.getLife(); - if (life == 13) { - player.lost(game); - } - } - } - for (UUID pid : playerList) { - Player player = game.getPlayer(pid); - if (player != null) { - player.loseLife(1, game, source, false); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null && player.getLife() == 13) { + player.lost(game); } } return true; diff --git a/Mage.Sets/src/mage/cards/t/TrollsOfTelJilad.java b/Mage.Sets/src/mage/cards/t/TrollsOfTelJilad.java index 157c8e61170..36f1de7621b 100644 --- a/Mage.Sets/src/mage/cards/t/TrollsOfTelJilad.java +++ b/Mage.Sets/src/mage/cards/t/TrollsOfTelJilad.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -37,7 +38,7 @@ public final class TrollsOfTelJilad extends CardImpl { this.power = new MageInt(5); this.toughness = new MageInt(6); Ability ability = new SimpleActivatedAbility(new RegenerateTargetEffect(), new ManaCostsImpl<>("{1}{G}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TrophyHunter.java b/Mage.Sets/src/mage/cards/t/TrophyHunter.java index 2c1fd9962de..260be60922e 100644 --- a/Mage.Sets/src/mage/cards/t/TrophyHunter.java +++ b/Mage.Sets/src/mage/cards/t/TrophyHunter.java @@ -17,6 +17,7 @@ import mage.constants.CardType; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -41,7 +42,7 @@ public final class TrophyHunter extends CardImpl { // {1}{G}: Trophy Hunter deals 1 damage to target creature with flying. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new ManaCostsImpl<>("{1}{G}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Whenever a creature with flying dealt damage by Trophy Hunter this turn dies, put a +1/+1 counter on Trophy Hunter. diff --git a/Mage.Sets/src/mage/cards/t/TroublemakerOuphe.java b/Mage.Sets/src/mage/cards/t/TroublemakerOuphe.java index 942b154b3cc..f94ad556428 100644 --- a/Mage.Sets/src/mage/cards/t/TroublemakerOuphe.java +++ b/Mage.Sets/src/mage/cards/t/TroublemakerOuphe.java @@ -1,10 +1,9 @@ package mage.cards.t; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.BargainedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.keyword.BargainAbility; import mage.cards.CardImpl; @@ -44,13 +43,10 @@ public final class TroublemakerOuphe extends CardImpl { this.addAbility(new BargainAbility()); // When Troublemaker Ouphe enters the battlefield, if it was bargained, exile target artifact or enchantment an opponent controls. - TriggeredAbility trigger = new EntersBattlefieldTriggeredAbility(new ExileTargetEffect()); - trigger.addTarget(new TargetPermanent(filter)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - trigger, - BargainedCondition.instance, - "When {this} enters, if it was bargained, exile target artifact or enchantment an opponent controls." - )); + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetEffect()) + .withInterveningIf(BargainedCondition.instance); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); } private TroublemakerOuphe(final TroublemakerOuphe card) { diff --git a/Mage.Sets/src/mage/cards/t/TsaboTavoc.java b/Mage.Sets/src/mage/cards/t/TsaboTavoc.java index 3d86fcb903b..68f4d62a453 100644 --- a/Mage.Sets/src/mage/cards/t/TsaboTavoc.java +++ b/Mage.Sets/src/mage/cards/t/TsaboTavoc.java @@ -17,6 +17,7 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -49,7 +50,7 @@ public final class TsaboTavoc extends CardImpl { // {B}{B}, {tap}: Destroy target legendary creature. It can't be regenerated. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(true), new ManaCostsImpl<>("{B}{B}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filterDestroy)); + ability.addTarget(new TargetPermanent(filterDestroy)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TurnBurn.java b/Mage.Sets/src/mage/cards/t/TurnBurn.java index 9c96b0ff772..fcd1e9e2c4a 100644 --- a/Mage.Sets/src/mage/cards/t/TurnBurn.java +++ b/Mage.Sets/src/mage/cards/t/TurnBurn.java @@ -1,7 +1,6 @@ package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; @@ -9,13 +8,15 @@ import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; import mage.cards.CardSetInfo; import mage.cards.SplitCard; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.SpellAbilityType; +import mage.constants.SubType; import mage.game.permanent.token.TokenImpl; import mage.target.common.TargetAnyTarget; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * * @author LevelX2 @@ -34,9 +35,7 @@ public final class TurnBurn extends SplitCard { // Burn // Burn deals 2 damage to any target. - effect = new DamageTargetEffect(2); - effect.setText("Burn deals 2 damage to any target"); - getRightHalfCard().getSpellAbility().addEffect(effect); + getRightHalfCard().getSpellAbility().addEffect(new DamageTargetEffect(2)); getRightHalfCard().getSpellAbility().addTarget(new TargetAnyTarget().withChooseHint("2 damage")); } diff --git a/Mage.Sets/src/mage/cards/t/TurretOgre.java b/Mage.Sets/src/mage/cards/t/TurretOgre.java index a15969c8797..a3cdae59dda 100644 --- a/Mage.Sets/src/mage/cards/t/TurretOgre.java +++ b/Mage.Sets/src/mage/cards/t/TurretOgre.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.keyword.ReachAbility; import mage.cards.CardImpl; @@ -15,8 +14,8 @@ import mage.constants.SubType; import mage.constants.TargetController; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.mageobject.PowerPredicate; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.PowerPredicate; import java.util.UUID; @@ -25,7 +24,7 @@ import java.util.UUID; */ public final class TurretOgre extends CardImpl { - private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("you control another creature with power 4 or greater"); static { filter.add(AnotherPredicate.instance); @@ -46,13 +45,7 @@ public final class TurretOgre extends CardImpl { this.addAbility(ReachAbility.getInstance()); // When Turret Ogre enters the battlefield, if you control another creature with power 4 or greater, Turret Ogre deals 2 damage to each opponent. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility( - new DamagePlayersEffect(2, TargetController.OPPONENT) - ), condition, "When {this} enters, " + - "if you control another creature with power 4 or greater, " + - "{this} deals 2 damage to each opponent." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DamagePlayersEffect(2, TargetController.OPPONENT)).withInterveningIf(condition)); } private TurretOgre(final TurretOgre card) { diff --git a/Mage.Sets/src/mage/cards/t/Twigwalker.java b/Mage.Sets/src/mage/cards/t/Twigwalker.java index 3951117db70..423bbc45daa 100644 --- a/Mage.Sets/src/mage/cards/t/Twigwalker.java +++ b/Mage.Sets/src/mage/cards/t/Twigwalker.java @@ -1,22 +1,21 @@ package mage.cards.t; -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.mana.ManaCostsImpl; import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.StaticFilters; +import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class Twigwalker extends CardImpl { @@ -31,7 +30,7 @@ public final class Twigwalker extends CardImpl { // {1}{G}, Sacrifice Twigwalker: Two target creatures each get +2/+2 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(2, 2, Duration.EndOfTurn), new ManaCostsImpl<>("{1}{G}")); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(2, 2, StaticFilters.FILTER_PERMANENT_CREATURES, false)); + ability.addTarget(new TargetCreaturePermanent(2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TwilightProphet.java b/Mage.Sets/src/mage/cards/t/TwilightProphet.java index 565213a33fa..47bd0e0711b 100644 --- a/Mage.Sets/src/mage/cards/t/TwilightProphet.java +++ b/Mage.Sets/src/mage/cards/t/TwilightProphet.java @@ -3,19 +3,21 @@ package mage.cards.t; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.common.CitysBlessingCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.CardsImpl; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; import mage.game.Game; import mage.players.Player; @@ -42,12 +44,8 @@ public final class TwilightProphet extends CardImpl { // At the beginning of your upkeep, if you have the city's blessing, reveal the top card of your library and put it into your hand. // Each opponent loses X life and you gain X life, where X is that card's converted mana cost. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new BeginningOfUpkeepTriggeredAbility( - new TwilightProphetEffect()), CitysBlessingCondition.instance, - "At the beginning of your upkeep, if you have the city's blessing, reveal the top card of your library and put it into your hand. " - + "Each opponent loses X life and you gain X life, where X is that card's mana value.") - .addHint(CitysBlessingHint.instance)); - + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TwilightProphetEffect()) + .withInterveningIf(CitysBlessingCondition.instance).addHint(CitysBlessingHint.instance)); } private TwilightProphet(final TwilightProphet card) { @@ -64,7 +62,7 @@ class TwilightProphetEffect extends OneShotEffect { TwilightProphetEffect() { super(Outcome.Benefit); - this.staticText = "if you have the city's blessing, reveal the top card of your library and put it into your hand. " + this.staticText = "reveal the top card of your library and put it into your hand. " + "Each opponent loses X life and you gain X life, where X is that card's mana value."; } diff --git a/Mage.Sets/src/mage/cards/t/Twinflame.java b/Mage.Sets/src/mage/cards/t/Twinflame.java index c733b4fa07c..725090855ca 100644 --- a/Mage.Sets/src/mage/cards/t/Twinflame.java +++ b/Mage.Sets/src/mage/cards/t/Twinflame.java @@ -1,7 +1,6 @@ package mage.cards.t; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; import mage.abilities.abilityword.StriveAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -11,7 +10,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -36,8 +34,7 @@ public final class Twinflame extends CardImpl { // Choose any number of target creatures you control. For each of them, create a token that's a copy of that creature, except it has haste. Exile them at the beginning of the next end step. this.getSpellAbility().addEffect(new TwinflameCopyEffect()); - this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, new FilterControlledCreaturePermanent(), false)); - + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE)); } private Twinflame(final Twinflame card) { @@ -69,23 +66,22 @@ class TwinflameCopyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - List toExile = new ArrayList<>(); - for (UUID creatureId : this.getTargetPointer().getTargets(game, source)) { - Permanent creature = game.getPermanentOrLKIBattlefield(creatureId); - if (creature != null) { - CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(source.getControllerId(), null, true); - effect.setTargetPointer(new FixedTarget(creature, game)); - effect.apply(game, source); - toExile.addAll(effect.getAddedPermanents()); - } - } - ExileTargetEffect exileEffect = new ExileTargetEffect(); - exileEffect.setTargetPointer(new FixedTargets(toExile, game)); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - game.addDelayedTriggeredAbility(delayedAbility, source); - return true; + if (controller == null) { + return false; } - return false; + List toExile = new ArrayList<>(); + for (UUID creatureId : this.getTargetPointer().getTargets(game, source)) { + Permanent creature = game.getPermanentOrLKIBattlefield(creatureId); + if (creature != null) { + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(source.getControllerId(), null, true); + effect.setTargetPointer(new FixedTarget(creature, game)); + effect.apply(game, source); + toExile.addAll(effect.getAddedPermanents()); + } + } + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new ExileTargetEffect().setTargetPointer(new FixedTargets(toExile, game)) + ), source); + return true; } } diff --git a/Mage.Sets/src/mage/cards/t/TwiningTwins.java b/Mage.Sets/src/mage/cards/t/TwiningTwins.java index b0406116218..cb8e36f28a1 100644 --- a/Mage.Sets/src/mage/cards/t/TwiningTwins.java +++ b/Mage.Sets/src/mage/cards/t/TwiningTwins.java @@ -12,6 +12,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TokenPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -46,7 +47,7 @@ public final class TwiningTwins extends AdventureCard { // Swift Spiral // Exile target nontoken creature. Return it to the battlefield under its owner’s control at the beginning of the next end step. this.getSpellCard().getSpellAbility().addEffect(new ExileReturnBattlefieldNextEndStepTargetEffect().withTextThatCard(false)); - this.getSpellCard().getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellCard().getSpellAbility().addTarget(new TargetPermanent(filter)); this.finalizeAdventure(); } diff --git a/Mage.Sets/src/mage/cards/t/TwinmawStormbrood.java b/Mage.Sets/src/mage/cards/t/TwinmawStormbrood.java index 41c021b2836..7a8d67bd10f 100644 --- a/Mage.Sets/src/mage/cards/t/TwinmawStormbrood.java +++ b/Mage.Sets/src/mage/cards/t/TwinmawStormbrood.java @@ -14,6 +14,7 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -44,7 +45,7 @@ public final class TwinmawStormbrood extends OmenCard { // Charring Bite // deals 5 damage to target creature without flying. this.getSpellCard().getSpellAbility().addEffect(new DamageTargetEffect(5)); - this.getSpellCard().getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellCard().getSpellAbility().addTarget(new TargetPermanent(filter)); this.finalizeOmen(); } diff --git a/Mage.Sets/src/mage/cards/t/TwistsAndTurns.java b/Mage.Sets/src/mage/cards/t/TwistsAndTurns.java index db69072bc66..76c33e1b534 100644 --- a/Mage.Sets/src/mage/cards/t/TwistsAndTurns.java +++ b/Mage.Sets/src/mage/cards/t/TwistsAndTurns.java @@ -4,8 +4,8 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.keyword.ExploreTargetEffect; @@ -17,6 +17,7 @@ import mage.constants.ComparisonType; import mage.constants.Duration; import mage.constants.Outcome; import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledLandPermanent; import mage.game.Game; import mage.game.events.ExploreEvent; import mage.game.events.GameEvent; @@ -29,6 +30,11 @@ import java.util.UUID; */ public final class TwistsAndTurns extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledLandPermanent("you control seven or more lands"), + ComparisonType.MORE_THAN, 6, true + ); + public TwistsAndTurns(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}"); this.secondSideCardClazz = mage.cards.m.MycoidMaze.class; @@ -43,12 +49,9 @@ public final class TwistsAndTurns extends CardImpl { // When a land you control enters, if you control seven or more lands, transform Twists and Turns. this.addAbility(new TransformAbility()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldControlledTriggeredAbility(new TransformSourceEffect(), StaticFilters.FILTER_LAND), - new PermanentsOnTheBattlefieldCondition(StaticFilters.FILTER_LANDS, ComparisonType.MORE_THAN, 6, true), - "When a land you control enters, if you control seven or more lands, transform {this}." - )); - + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + new TransformSourceEffect(), StaticFilters.FILTER_LAND + ).withInterveningIf(condition).setTriggerPhrase("When a land you control enters, ")); } private TwistsAndTurns(final TwistsAndTurns card) { @@ -89,7 +92,7 @@ class TwistsAndTurnsReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - ExploreEvent exploreEvent = (ExploreEvent)event; + ExploreEvent exploreEvent = (ExploreEvent) event; exploreEvent.addScry(); return false; } diff --git a/Mage.Sets/src/mage/cards/t/TyrantOfValakut.java b/Mage.Sets/src/mage/cards/t/TyrantOfValakut.java index 57049a56d52..35063c1b7be 100644 --- a/Mage.Sets/src/mage/cards/t/TyrantOfValakut.java +++ b/Mage.Sets/src/mage/cards/t/TyrantOfValakut.java @@ -1,11 +1,9 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.SurgedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.SurgeAbility; @@ -15,14 +13,15 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author fireshoes */ public final class TyrantOfValakut extends CardImpl { public TyrantOfValakut(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}{R}"); this.subtype.add(SubType.DRAGON); this.power = new MageInt(5); this.toughness = new MageInt(4); @@ -34,10 +33,10 @@ public final class TyrantOfValakut extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Tyrant of Valakut enters the battlefield, if its surge cost was paid, it deals 3 damage to any target. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(3), false); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(3)) + .withInterveningIf(SurgedCondition.instance).withRuleTextReplacement(true); ability.addTarget(new TargetAnyTarget()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, SurgedCondition.instance, - "When {this} enters, if its surge cost was paid, it deals 3 damage to any target.")); + this.addAbility(ability); } private TyrantOfValakut(final TyrantOfValakut card) { diff --git a/Mage.Sets/src/mage/cards/u/UbulSarGatekeepers.java b/Mage.Sets/src/mage/cards/u/UbulSarGatekeepers.java index 68f61c73924..74d1985a17a 100644 --- a/Mage.Sets/src/mage/cards/u/UbulSarGatekeepers.java +++ b/Mage.Sets/src/mage/cards/u/UbulSarGatekeepers.java @@ -3,18 +3,14 @@ package mage.cards.u; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.YouControlTwoOrMoreGatesCondition; import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.common.GatesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledPermanent; -import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetOpponentsCreaturePermanent; import java.util.UUID; @@ -23,14 +19,6 @@ import java.util.UUID; */ public final class UbulSarGatekeepers extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent(); - - static { - filter.add(SubType.GATE.getPredicate()); - } - - private static final Condition gatesCondition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); - public UbulSarGatekeepers(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.subtype.add(SubType.ZOMBIE); @@ -40,14 +28,10 @@ public final class UbulSarGatekeepers extends CardImpl { this.toughness = new MageInt(4); // Whenever Ubul Sar Gatekeepers enters the battlefield, if you control two or more Gates, target creature an opponent controls gets -2/-2 until end of turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-2, -2, Duration.EndOfTurn)), - gatesCondition, - "When {this} enters, if you control two or more Gates, target creature an opponent controls gets -2/-2 until end of turn."); - Target target = new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE); - ability.addTarget(target); - ability.addHint(new ConditionHint(gatesCondition, "You control two or more Gates")); - this.addAbility(ability); + Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-2, -2)) + .withInterveningIf(YouControlTwoOrMoreGatesCondition.instance); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability.addHint(GatesYouControlHint.instance)); } private UbulSarGatekeepers(final UbulSarGatekeepers card) { diff --git a/Mage.Sets/src/mage/cards/u/UglukOfTheWhiteHand.java b/Mage.Sets/src/mage/cards/u/UglukOfTheWhiteHand.java index 8baa25d6ecc..fe7b1234e62 100644 --- a/Mage.Sets/src/mage/cards/u/UglukOfTheWhiteHand.java +++ b/Mage.Sets/src/mage/cards/u/UglukOfTheWhiteHand.java @@ -70,8 +70,8 @@ class UglukOfTheWhiteHandEffect extends OneShotEffect { public UglukOfTheWhiteHandEffect() { super(Outcome.Benefit); - staticText = "put a +1/+1 counter on Ugluk of the White Hand. " + - "If that creature was a Goblin or Orc, put two +1/+1 counters on Ugluk instead."; + staticText = "put a +1/+1 counter on {this}. " + + "If that creature was a Goblin or Orc, put two +1/+1 counters on {this} instead."; } private UglukOfTheWhiteHandEffect(final UglukOfTheWhiteHandEffect effect) { diff --git a/Mage.Sets/src/mage/cards/u/UlrichsKindred.java b/Mage.Sets/src/mage/cards/u/UlrichsKindred.java index 0f25d20d9e2..65cbf6f93b0 100644 --- a/Mage.Sets/src/mage/cards/u/UlrichsKindred.java +++ b/Mage.Sets/src/mage/cards/u/UlrichsKindred.java @@ -17,6 +17,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.AttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -44,7 +45,7 @@ public final class UlrichsKindred extends CardImpl { SimpleActivatedAbility ability = new SimpleActivatedAbility( new GainAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{3}{G}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/u/UltimatePrice.java b/Mage.Sets/src/mage/cards/u/UltimatePrice.java index c1f7305f23e..4045f770743 100644 --- a/Mage.Sets/src/mage/cards/u/UltimatePrice.java +++ b/Mage.Sets/src/mage/cards/u/UltimatePrice.java @@ -8,6 +8,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.MonocoloredPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -26,7 +27,7 @@ public final class UltimatePrice extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}"); // Destroy target monocolored creature. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/u/UlvenwaldBear.java b/Mage.Sets/src/mage/cards/u/UlvenwaldBear.java index 47756c0e6d1..9a37f7b8f43 100644 --- a/Mage.Sets/src/mage/cards/u/UlvenwaldBear.java +++ b/Mage.Sets/src/mage/cards/u/UlvenwaldBear.java @@ -1,12 +1,9 @@ - package mage.cards.u; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.MorbidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.hint.common.MorbidHint; import mage.cards.CardImpl; @@ -14,26 +11,27 @@ import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Outcome; import mage.counters.CounterType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class UlvenwaldBear extends CardImpl { public UlvenwaldBear(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.subtype.add(SubType.BEAR); this.power = new MageInt(2); this.toughness = new MageInt(2); // Morbid — When Ulvenwald Bear enters the battlefield, if a creature died this turn, put two +1/+1 counters on target creature. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2), Outcome.BoostCreature)), - MorbidCondition.instance, "When {this} enters, if a creature died this turn, put two +1/+1 counters on target creature."); + Ability ability = new EntersBattlefieldTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)) + ).withInterveningIf(MorbidCondition.instance); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability.addHint(MorbidHint.instance).setAbilityWord(AbilityWord.MORBID)); } diff --git a/Mage.Sets/src/mage/cards/u/UlvenwaldTracker.java b/Mage.Sets/src/mage/cards/u/UlvenwaldTracker.java index d45b79ca504..d07df3da42d 100644 --- a/Mage.Sets/src/mage/cards/u/UlvenwaldTracker.java +++ b/Mage.Sets/src/mage/cards/u/UlvenwaldTracker.java @@ -12,11 +12,14 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2; + /** * @author North */ @@ -36,7 +39,7 @@ public final class UlvenwaldTracker extends CardImpl { Target controlledTarget = new TargetControlledCreaturePermanent(); controlledTarget.setTargetTag(1); ability.addTarget(controlledTarget); - Target secondTarget = new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2); + Target secondTarget = new TargetPermanent(FILTER_ANOTHER_CREATURE_TARGET_2); secondTarget.setTargetTag(2); ability.addTarget(secondTarget); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/u/UmbraStalker.java b/Mage.Sets/src/mage/cards/u/UmbraStalker.java index e55e90ad441..0995007199b 100644 --- a/Mage.Sets/src/mage/cards/u/UmbraStalker.java +++ b/Mage.Sets/src/mage/cards/u/UmbraStalker.java @@ -33,7 +33,7 @@ public final class UmbraStalker extends CardImpl { // Chroma - Umbra Stalker's power and toughness are each equal to the number of black mana symbols in the mana costs of cards in your graveyard. DynamicValue xValue = new ChromaUmbraStalkerCount(); Effect effect = new SetBasePowerToughnessSourceEffect(xValue); - effect.setText("Chroma — Umbra Stalker's power and toughness are each equal to the number of black mana symbols in the mana costs of cards in your graveyard."); + effect.setText("Chroma — {this}'s power and toughness are each equal to the number of black mana symbols in the mana costs of cards in your graveyard."); this.addAbility(new SimpleStaticAbility(Zone.ALL, effect) .addHint(new ValueHint("Black mana symbols in your graveyard's permanents", xValue)) ); diff --git a/Mage.Sets/src/mage/cards/u/UndeadGladiator.java b/Mage.Sets/src/mage/cards/u/UndeadGladiator.java index 5ab3069888d..d0ec2c8720d 100644 --- a/Mage.Sets/src/mage/cards/u/UndeadGladiator.java +++ b/Mage.Sets/src/mage/cards/u/UndeadGladiator.java @@ -1,43 +1,41 @@ - package mage.cards.u; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; import mage.abilities.keyword.CyclingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.PhaseStep; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author fireshoes */ public final class UndeadGladiator extends CardImpl { public UndeadGladiator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.BARBARIAN); this.power = new MageInt(3); this.toughness = new MageInt(1); // {1}{B}, Discard a card: Return Undead Gladiator from your graveyard to your hand. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility(Zone.GRAVEYARD, - new ReturnSourceFromGraveyardToHandEffect(), - new ManaCostsImpl<>("{1}{B}"), - new IsStepCondition(PhaseStep.UPKEEP), null); + Ability ability = new ActivateIfConditionActivatedAbility( + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), + new ManaCostsImpl<>("{1}{B}"), IsStepCondition.getMyUpkeep() + ); ability.addCost(new DiscardCardCost()); this.addAbility(ability); - + // Cycling {1}{B} this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{1}{B}"))); } diff --git a/Mage.Sets/src/mage/cards/u/UndercellarSweep.java b/Mage.Sets/src/mage/cards/u/UndercellarSweep.java index 7e098e7423e..0c15fdedc41 100644 --- a/Mage.Sets/src/mage/cards/u/UndercellarSweep.java +++ b/Mage.Sets/src/mage/cards/u/UndercellarSweep.java @@ -4,7 +4,6 @@ import mage.abilities.Ability; import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TakeTheInitiativeEffect; import mage.abilities.hint.common.InitiativeHint; @@ -25,15 +24,14 @@ public final class UndercellarSweep extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{W}"); // When Undercellar Sweep enters the battlefield, you take the initiative. - this.addAbility(new EntersBattlefieldTriggeredAbility(new TakeTheInitiativeEffect()).addHint(InitiativeHint.instance)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new TakeTheInitiativeEffect()) + .addHint(InitiativeHint.instance)); // Whenever you attack, if you or a player you're attacking has the initiative, you create two 1/1 white Soldier creature token that are tapped and attacking. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksWithCreaturesTriggeredAbility( - new CreateTokenEffect(new SoldierToken(), 2, true, true), 1 - ), UndercellarSweepCondition.instance, "Whenever you attack, if you or a player you're attacking " + - "has the initiative, you create two 1/1 white Soldier creature tokens that are tapped and attacking." - )); + this.addAbility(new AttacksWithCreaturesTriggeredAbility( + new CreateTokenEffect(new SoldierToken(), 2, true, true) + .setText("you create two 1/1 white Soldier creature tokens that are tapped and attacking"), 1 + ).withInterveningIf(UndercellarSweepCondition.instance)); } private UndercellarSweep(final UndercellarSweep card) { @@ -63,4 +61,9 @@ enum UndercellarSweepCondition implements Condition { .map(game.getCombat()::getDefenderId) .anyMatch(game.getInitiativeId()::equals); } + + @Override + public String toString() { + return "you or a player you're attacking has the initiative"; + } } diff --git a/Mage.Sets/src/mage/cards/u/UndercityScrounger.java b/Mage.Sets/src/mage/cards/u/UndercityScrounger.java index 56f6f20fbad..dfd6a8e25ac 100644 --- a/Mage.Sets/src/mage/cards/u/UndercityScrounger.java +++ b/Mage.Sets/src/mage/cards/u/UndercityScrounger.java @@ -3,14 +3,13 @@ package mage.cards.u; import mage.MageInt; import mage.abilities.condition.common.MorbidCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.common.MorbidHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.game.permanent.token.TreasureToken; import java.util.UUID; @@ -29,9 +28,8 @@ public final class UndercityScrounger extends CardImpl { this.toughness = new MageInt(4); // {T}: Create a Treasure token. Activate only if a creature died this turn. - this.addAbility(new ConditionalActivatedAbility( - Zone.BATTLEFIELD, new CreateTokenEffect(new TreasureToken()), - new TapSourceCost(), MorbidCondition.instance + this.addAbility(new ActivateIfConditionActivatedAbility( + new CreateTokenEffect(new TreasureToken()), new TapSourceCost(), MorbidCondition.instance ).addHint(MorbidHint.instance)); } diff --git a/Mage.Sets/src/mage/cards/u/UndercityUprising.java b/Mage.Sets/src/mage/cards/u/UndercityUprising.java index a3758ace5ea..bd4739a4b42 100644 --- a/Mage.Sets/src/mage/cards/u/UndercityUprising.java +++ b/Mage.Sets/src/mage/cards/u/UndercityUprising.java @@ -8,11 +8,14 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author TheElk801 */ @@ -30,7 +33,7 @@ public final class UndercityUprising extends CardImpl { .setText("Then target creature you control fights target creature you don't control. " + "(Each deals damage equal to its power to the other.)")); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); } private UndercityUprising(final UndercityUprising card) { diff --git a/Mage.Sets/src/mage/cards/u/UnderhandedDesigns.java b/Mage.Sets/src/mage/cards/u/UnderhandedDesigns.java index a49e49a5049..b4787b9c2e9 100644 --- a/Mage.Sets/src/mage/cards/u/UnderhandedDesigns.java +++ b/Mage.Sets/src/mage/cards/u/UnderhandedDesigns.java @@ -1,10 +1,9 @@ - package mage.cards.u; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.GenericManaCost; @@ -17,31 +16,36 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledArtifactPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class UnderhandedDesigns extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledArtifactPermanent("you control two or more artifacts"), + ComparisonType.MORE_THAN, 1 + ); + public UnderhandedDesigns(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); // Whenever an artifact you control enters, you may pay {1}. If you do, each opponent loses 1 life and you gain 1 life. - DoIfCostPaid doIfCostPaid = new DoIfCostPaid(new LoseLifeOpponentsEffect(1), new GenericManaCost(1)); - doIfCostPaid.addEffect(new GainLifeEffect(1).concatBy("and")); - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, - doIfCostPaid, StaticFilters.FILTER_PERMANENT_ARTIFACT, false)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new DoIfCostPaid(new LoseLifeOpponentsEffect(1), new GenericManaCost(1)) + .addEffect(new GainLifeEffect(1).concatBy("and")), + StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT + )); // {1}{B}, Sacrifice Underhanded Designs: Destroy target creature. Activate this ability only if you control two or more artifacts. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new DestroyTargetEffect(), - new ManaCostsImpl<>("{1}{B}"), - new PermanentsOnTheBattlefieldCondition(new FilterControlledArtifactPermanent("you control two or more artifacts"), ComparisonType.MORE_THAN, 1)); + Ability ability = new ActivateIfConditionActivatedAbility( + new DestroyTargetEffect(), new ManaCostsImpl<>("{1}{B}"), condition + ); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/u/Undo.java b/Mage.Sets/src/mage/cards/u/Undo.java index 7eaa6d0bceb..3eb44b312ec 100644 --- a/Mage.Sets/src/mage/cards/u/Undo.java +++ b/Mage.Sets/src/mage/cards/u/Undo.java @@ -1,21 +1,20 @@ - package mage.cards.u; -import java.util.UUID; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class Undo extends CardImpl { public Undo(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}{U}"); // Return two target creatures to their owners' hands. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/u/UnityOfTheDroids.java b/Mage.Sets/src/mage/cards/u/UnityOfTheDroids.java index 75da54f62b6..5f809955b8c 100644 --- a/Mage.Sets/src/mage/cards/u/UnityOfTheDroids.java +++ b/Mage.Sets/src/mage/cards/u/UnityOfTheDroids.java @@ -12,6 +12,7 @@ import mage.constants.Duration; import mage.constants.PutCards; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -34,7 +35,7 @@ public final class UnityOfTheDroids extends CardImpl { // Choose one - Prevent all damage that would be dealt to target artifact creature this turn. this.getSpellAbility().addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(artifactCreatureFilter)); + this.getSpellAbility().addTarget(new TargetPermanent(artifactCreatureFilter)); // Look at the top four cards of your library. Put one of them into your hand and the rest into your graveyard. Mode mode = new Mode(new LookLibraryAndPickControllerEffect(4, 1, PutCards.HAND, PutCards.GRAVEYARD)); @@ -42,7 +43,7 @@ public final class UnityOfTheDroids extends CardImpl { // Destroy target nonartifact creature. mode = new Mode(new DestroyTargetEffect()); - mode.addTarget(new TargetCreaturePermanent(nonArtifactCreatureFilter)); + mode.addTarget(new TargetPermanent(nonArtifactCreatureFilter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/u/UnlikelyAlliance.java b/Mage.Sets/src/mage/cards/u/UnlikelyAlliance.java index 6c0a2e03eb6..ae647da8d25 100644 --- a/Mage.Sets/src/mage/cards/u/UnlikelyAlliance.java +++ b/Mage.Sets/src/mage/cards/u/UnlikelyAlliance.java @@ -15,6 +15,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.AttackingPredicate; import mage.filter.predicate.permanent.BlockingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -35,7 +36,7 @@ public final class UnlikelyAlliance extends CardImpl { // {1}{W}: Target nonattacking, nonblocking creature gets +0/+2 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(0, 2, Duration.EndOfTurn), new ManaCostsImpl<>("{1}{W}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/u/UnlivingPsychopath.java b/Mage.Sets/src/mage/cards/u/UnlivingPsychopath.java index 1e41474d493..bec4d4e3a79 100644 --- a/Mage.Sets/src/mage/cards/u/UnlivingPsychopath.java +++ b/Mage.Sets/src/mage/cards/u/UnlivingPsychopath.java @@ -1,7 +1,6 @@ package mage.cards.u; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -9,19 +8,20 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ColoredManaCost; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ColoredManaSymbol; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** * @@ -29,7 +29,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class UnlivingPsychopath extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with power less than Unliving Psychopath's power"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with power less than {this}'s power"); static { filter.add(new UnlivingPsychopathPowerLessThanSourcePredicate()); @@ -49,7 +49,7 @@ public final class UnlivingPsychopath extends CardImpl { // {B}, {tap}: Destroy target creature with power less than Unliving Psychopath's power. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ColoredManaCost(ColoredManaSymbol.B)); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } @@ -73,6 +73,6 @@ class UnlivingPsychopathPowerLessThanSourcePredicate implements ObjectSourcePlay @Override public String toString() { - return "power less than Unliving Psychopath's power"; + return "power less than {this}'s power"; } } diff --git a/Mage.Sets/src/mage/cards/u/UnnaturalAggression.java b/Mage.Sets/src/mage/cards/u/UnnaturalAggression.java index cd97cbce9d8..12d8f02b206 100644 --- a/Mage.Sets/src/mage/cards/u/UnnaturalAggression.java +++ b/Mage.Sets/src/mage/cards/u/UnnaturalAggression.java @@ -10,10 +10,13 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.SecondTargetPointer; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -29,7 +32,7 @@ public final class UnnaturalAggression extends CardImpl { // Target creature you control fights target creature an opponent controls. this.getSpellAbility().addEffect(new FightTargetsEffect(false)); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); // If the creature an opponent controls would die this turn, exile it instead. Effect effect = new ExileTargetIfDiesEffect(); effect.setText("If the creature an opponent controls would die this turn, exile it instead"); diff --git a/Mage.Sets/src/mage/cards/u/UnquenchableThirst.java b/Mage.Sets/src/mage/cards/u/UnquenchableThirst.java index adf11e815aa..e914901281d 100644 --- a/Mage.Sets/src/mage/cards/u/UnquenchableThirst.java +++ b/Mage.Sets/src/mage/cards/u/UnquenchableThirst.java @@ -4,7 +4,6 @@ package mage.cards.u; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.DesertControlledOrGraveyardCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.DontUntapInControllersUntapStepEnchantedEffect; import mage.abilities.effects.common.TapEnchantedEffect; @@ -36,11 +35,8 @@ public final class UnquenchableThirst extends CardImpl { this.addAbility(new EnchantAbility(auraTarget)); // When Unquenchable Thirst enters the battlefield, if you control a Desert or there is a Desert card in your graveyard, tap enchanted creature. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new TapEnchantedEffect()), - DesertControlledOrGraveyardCondition.instance, "When {this} enters, " + - "if you control a Desert or there is a Desert card in your graveyard, tap enchanted creature." - ).addHint(DesertControlledOrGraveyardCondition.getHint())); + this.addAbility(new EntersBattlefieldTriggeredAbility(new TapEnchantedEffect()) + .withInterveningIf(DesertControlledOrGraveyardCondition.instance).addHint(DesertControlledOrGraveyardCondition.getHint())); // Enchanted creature doesn't untap during its controller's untap step. this.addAbility(new SimpleStaticAbility(new DontUntapInControllersUntapStepEnchantedEffect())); diff --git a/Mage.Sets/src/mage/cards/u/UnravelingMummy.java b/Mage.Sets/src/mage/cards/u/UnravelingMummy.java index 2badbfe8d63..d20d9886022 100644 --- a/Mage.Sets/src/mage/cards/u/UnravelingMummy.java +++ b/Mage.Sets/src/mage/cards/u/UnravelingMummy.java @@ -18,6 +18,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -44,14 +45,14 @@ public final class UnravelingMummy extends CardImpl { Effect effect = new GainAbilityTargetEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn); effect.setText("Target attacking Zombie gains lifelink until end of turn."); Ability ability = new SimpleActivatedAbility(effect, new ManaCostsImpl<>("{1}{W}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // {1}{B}: Target attacking Zombie gains deathtouch until end of turn. effect = new GainAbilityTargetEffect(DeathtouchAbility.getInstance(), Duration.EndOfTurn); effect.setText("Target attacking Zombie gains deathtouch until end of turn. (Any amount of damage it deals to a creature is enough to destroy it.)"); ability = new SimpleActivatedAbility(effect, new ManaCostsImpl<>("{1}{B}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/u/UnrulyKrasis.java b/Mage.Sets/src/mage/cards/u/UnrulyKrasis.java index b48ac0fe224..0b54128017f 100644 --- a/Mage.Sets/src/mage/cards/u/UnrulyKrasis.java +++ b/Mage.Sets/src/mage/cards/u/UnrulyKrasis.java @@ -17,7 +17,7 @@ import mage.constants.SubType; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -40,7 +40,7 @@ public final class UnrulyKrasis extends CardImpl { // Whenever Unruly Krasis attacks, you may have the base power and toughness of another target creature you control become X/X until end of turn, where X is Unruly Krasis's power. Ability ability = new AttacksTriggeredAbility(new UnrulyKrasisEffect(), true); - ability.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); this.addAbility(ability); // {3}{G}{U}: Adapt 3. @@ -87,4 +87,4 @@ class UnrulyKrasisEffect extends OneShotEffect { game.addEffect(effect, source); return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/u/UnrulySureshot.java b/Mage.Sets/src/mage/cards/u/UnrulySureshot.java index 6facccb4e29..1713ba71d8d 100644 --- a/Mage.Sets/src/mage/cards/u/UnrulySureshot.java +++ b/Mage.Sets/src/mage/cards/u/UnrulySureshot.java @@ -16,6 +16,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponentsCreaturePermanent; @@ -45,7 +46,7 @@ public final class UnrulySureshot extends CardImpl { // {3}{R}: Unruly Sureshot deals 2 damage to target creature with a bounty counter on it. ability = new SimpleActivatedAbility(new DamageTargetEffect(2), new ManaCostsImpl<>("{3}{R}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/u/UnstableGlyphbridge.java b/Mage.Sets/src/mage/cards/u/UnstableGlyphbridge.java index 211b54eddcb..2115fe4af1a 100644 --- a/Mage.Sets/src/mage/cards/u/UnstableGlyphbridge.java +++ b/Mage.Sets/src/mage/cards/u/UnstableGlyphbridge.java @@ -3,7 +3,6 @@ package mage.cards.u; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.CraftAbility; import mage.cards.CardImpl; @@ -20,12 +19,11 @@ import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; /** - * * @author notgreat */ public final class UnstableGlyphbridge extends CardImpl { @@ -35,12 +33,8 @@ public final class UnstableGlyphbridge extends CardImpl { this.secondSideCardClazz = mage.cards.s.SandswirlWanderglyph.class; // When Unstable Glyphbridge enters the battlefield, if you cast it, for each player, choose a creature with power 2 or less that player controls. Then destroy all creatures except creatures chosen this way. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( - new UnstableGlyphbridgeEffect()), CastFromEverywhereSourceCondition.instance, - "When {this} enters, if you cast it, " + - "for each player, choose a creature with power 2 or less that player controls. " + - "Then destroy all creatures except creatures chosen this way." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new UnstableGlyphbridgeEffect()) + .withInterveningIf(CastFromEverywhereSourceCondition.instance)); // Craft with artifact {3}{W}{W} this.addAbility(new CraftAbility("{3}{W}{W}")); @@ -86,9 +80,9 @@ class UnstableGlyphbridgeEffect extends OneShotEffect { continue; } FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with power 2 or less"); - filter.add(new PowerPredicate(ComparisonType.OR_LESS,2)); + filter.add(new PowerPredicate(ComparisonType.OR_LESS, 2)); filter.add(new ControllerIdPredicate(playerId)); - TargetCreaturePermanent target = new TargetCreaturePermanent(filter); + TargetPermanent target = new TargetPermanent(filter); target.withNotTarget(true); target.withChooseHint(player.getName() + " controls"); diff --git a/Mage.Sets/src/mage/cards/u/UnstoppableSlasher.java b/Mage.Sets/src/mage/cards/u/UnstoppableSlasher.java index f3b3386bf50..a769af4e9e6 100644 --- a/Mage.Sets/src/mage/cards/u/UnstoppableSlasher.java +++ b/Mage.Sets/src/mage/cards/u/UnstoppableSlasher.java @@ -5,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.LoseHalfLifeTargetEffect; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldWithCounterEffect; import mage.abilities.keyword.DeathtouchAbility; @@ -39,9 +38,12 @@ public final class UnstoppableSlasher extends CardImpl { .setText("they lose half their life, rounded up"), false, true)); // When Unstoppable Slasher dies, if it had no counters on it, return it to the battlefield tapped under its owner's control with two stun counters on it. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new DiesSourceTriggeredAbility(new ReturnSourceFromGraveyardToBattlefieldWithCounterEffect( - CounterType.STUN.createInstance(2), true, true, false, false - ), false), UnstoppableSlasherCondition.instance, "When {this} dies, if it had no counters on it, return it to the battlefield tapped under its owner's control with two stun counters on it")); + this.addAbility(new DiesSourceTriggeredAbility( + new ReturnSourceFromGraveyardToBattlefieldWithCounterEffect( + CounterType.STUN.createInstance(2), + true, true, false, false + ).setText("return it to the battlefield tapped under its owner's control with two stun counters on it") + ).withInterveningIf(UnstoppableSlasherCondition.instance)); } private UnstoppableSlasher(final UnstoppableSlasher card) { @@ -60,14 +62,17 @@ enum UnstoppableSlasherCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Permanent permanent = source.getSourcePermanentOrLKI(game); - if (permanent == null) { - return false; - } - return permanent + return permanent != null + && permanent .getCounters(game) .values() .stream() .mapToInt(Counter::getCount) .sum() == 0; } + + @Override + public String toString() { + return "it had no counters on it"; + } } diff --git a/Mage.Sets/src/mage/cards/u/UntamedKavu.java b/Mage.Sets/src/mage/cards/u/UntamedKavu.java index 10d381cfaf1..cd04b95d359 100644 --- a/Mage.Sets/src/mage/cards/u/UntamedKavu.java +++ b/Mage.Sets/src/mage/cards/u/UntamedKavu.java @@ -1,7 +1,6 @@ package mage.cards.u; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; @@ -16,6 +15,8 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; +import java.util.UUID; + /** * * @author tcontis @@ -39,7 +40,7 @@ public final class UntamedKavu extends CardImpl { // If Untamed Kavu was kicked, it enters with three +1/+1 counters on it. Ability ability = new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(3)), KickedCondition.ONCE, - "If Untamed Kavu was kicked, it enters with three +1/+1 counters on it.", ""); + "If {this} was kicked, it enters with three +1/+1 counters on it.", ""); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/u/Urabrask.java b/Mage.Sets/src/mage/cards/u/Urabrask.java index 1676c242257..899f4552ec6 100644 --- a/Mage.Sets/src/mage/cards/u/Urabrask.java +++ b/Mage.Sets/src/mage/cards/u/Urabrask.java @@ -6,7 +6,7 @@ import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; import mage.abilities.effects.mana.BasicManaEffect; @@ -51,7 +51,7 @@ public final class Urabrask extends CardImpl { // {R}: Exile Urabrask, then return it to the battlefield transformed under its owner's control. Activate only as a sorcery and only if you've cast three or more instant and/or sorcery spells this turn. this.addAbility(new TransformAbility()); - this.addAbility(new ConditionalActivatedAbility( + this.addAbility(new ActivateIfConditionActivatedAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED), new ManaCostsImpl<>("{R}"), UrabraskCondition.instance ).setTiming(TimingRule.SORCERY)); diff --git a/Mage.Sets/src/mage/cards/u/UrborgEmissary.java b/Mage.Sets/src/mage/cards/u/UrborgEmissary.java index dac2bf6755e..b4ec61712c9 100644 --- a/Mage.Sets/src/mage/cards/u/UrborgEmissary.java +++ b/Mage.Sets/src/mage/cards/u/UrborgEmissary.java @@ -1,12 +1,9 @@ - package mage.cards.u; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; @@ -15,15 +12,15 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.target.TargetPermanent; -/** - * - * @author LoneFox +import java.util.UUID; +/** + * @author LoneFox */ public final class UrborgEmissary extends CardImpl { public UrborgEmissary(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(3); @@ -31,11 +28,12 @@ public final class UrborgEmissary extends CardImpl { // Kicker {1}{U} this.addAbility(new KickerAbility("{1}{U}")); + // When Urborg Emissary enters the battlefield, if it was kicked, return target permanent to its owner's hand. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()) + .withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetPermanent()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.ONCE, - "When {this} enters, if it was kicked, return target permanent to its owner's hand.")); + this.addAbility(ability); } private UrborgEmissary(final UrborgEmissary card) { diff --git a/Mage.Sets/src/mage/cards/u/UrborgStalker.java b/Mage.Sets/src/mage/cards/u/UrborgStalker.java index cc0a2af87e7..e8550aaf34a 100644 --- a/Mage.Sets/src/mage/cards/u/UrborgStalker.java +++ b/Mage.Sets/src/mage/cards/u/UrborgStalker.java @@ -1,36 +1,37 @@ - package mage.cards.u; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; -import mage.constants.SubType; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.constants.TargetController; import mage.filter.FilterPermanent; +import mage.filter.common.FilterNonlandPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class UrborgStalker extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent(); + private static final FilterPermanent filter = new FilterNonlandPermanent("that player controls a nonblack, nonland permanent"); static { filter.add(TargetController.ACTIVE.getControllerPredicate()); filter.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK))); - filter.add(Predicates.not(CardType.LAND.getPredicate())); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + public UrborgStalker(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); @@ -39,13 +40,9 @@ public final class UrborgStalker extends CardImpl { this.toughness = new MageInt(4); // At the beginning of each player's upkeep, if that player controls a nonblack, nonland permanent, Urborg Stalker deals 1 damage to that player. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(TargetController.ANY, new DamageTargetEffect(1), false), - new PermanentsOnTheBattlefieldCondition(filter), - "At the beginning of each player's upkeep, " - + "if that player controls a nonblack, nonland permanent, " - + "{this} deals 1 damage to that player." - )); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.EACH_PLAYER, new DamageTargetEffect(1, true, "that player"), false + ).withInterveningIf(condition)); } private UrborgStalker(final UrborgStalker card) { diff --git a/Mage.Sets/src/mage/cards/u/UrgeToFeed.java b/Mage.Sets/src/mage/cards/u/UrgeToFeed.java index bc572bc69ed..1d5f88995f1 100644 --- a/Mage.Sets/src/mage/cards/u/UrgeToFeed.java +++ b/Mage.Sets/src/mage/cards/u/UrgeToFeed.java @@ -1,7 +1,5 @@ - package mage.cards.u; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; @@ -13,17 +11,19 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class UrgeToFeed extends CardImpl { public UrgeToFeed(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}{B}"); // Target creature gets -3/-3 until end of turn. You may tap any number of untapped Vampire creatures you control. If you do, put a +1/+1 counter on each of those Vampires. this.getSpellAbility().addEffect(new BoostTargetEffect(-3, -3, Duration.EndOfTurn)); @@ -62,14 +62,13 @@ class UrgeToFeedEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - TargetCreaturePermanent target = new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, true); - if (target.canChoose(source.getControllerId(), source, game) && target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), source, game)) { - for (UUID vampireId : target.getTargets()) { - Permanent vampire = game.getPermanent(vampireId); - if (vampire != null) { - vampire.tap(source, game); - vampire.addCounters(CounterType.P1P1.createInstance(), source.getControllerId(), source, game); - } + TargetPermanent target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); + target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), source, game); + for (UUID vampireId : target.getTargets()) { + Permanent vampire = game.getPermanent(vampireId); + if (vampire != null) { + vampire.tap(source, game); + vampire.addCounters(CounterType.P1P1.createInstance(), source.getControllerId(), source, game); } } return true; diff --git a/Mage.Sets/src/mage/cards/u/UrtetRemnantOfMemnarch.java b/Mage.Sets/src/mage/cards/u/UrtetRemnantOfMemnarch.java index abc2a955b88..8b3bebeb2b6 100644 --- a/Mage.Sets/src/mage/cards/u/UrtetRemnantOfMemnarch.java +++ b/Mage.Sets/src/mage/cards/u/UrtetRemnantOfMemnarch.java @@ -3,7 +3,6 @@ package mage.cards.u; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.costs.common.TapSourceCost; @@ -11,10 +10,12 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.UntapAllControllerEffect; import mage.abilities.effects.common.counter.AddCountersAllEffect; -import mage.abilities.hint.common.MyTurnHint; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.counters.CounterType; import mage.filter.FilterSpell; import mage.filter.common.FilterControlledPermanent; @@ -49,9 +50,11 @@ public final class UrtetRemnantOfMemnarch extends CardImpl { this.addAbility(new BeginningOfCombatTriggeredAbility(new UntapAllControllerEffect(filter2, "untap each Myr you control"))); // {W}{U}{B}{R}{G}, {T}: Put three +1/+1 counters on each Myr you control. Activate only during your turn. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new AddCountersAllEffect(CounterType.P1P1.createInstance(3), filter2), new ManaCostsImpl<>("{W}{U}{B}{R}{G}"), MyTurnCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new AddCountersAllEffect(CounterType.P1P1.createInstance(3), filter2), + new ManaCostsImpl<>("{W}{U}{B}{R}{G}"), MyTurnCondition.instance + ); ability.addCost(new TapSourceCost()); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/u/UthrosTitanicGodcore.java b/Mage.Sets/src/mage/cards/u/UthrosTitanicGodcore.java new file mode 100644 index 00000000000..d1228201515 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UthrosTitanicGodcore.java @@ -0,0 +1,57 @@ +package mage.cards.u; + +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.ArtifactYouControlCount; +import mage.abilities.hint.common.ArtifactYouControlHint; +import mage.abilities.keyword.StationAbility; +import mage.abilities.keyword.StationLevelAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.DynamicManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UthrosTitanicGodcore extends CardImpl { + + public UthrosTitanicGodcore(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + this.subtype.add(SubType.PLANET); + + // This land enters tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {U}. + this.addAbility(new BlueManaAbility()); + + // Station + this.addAbility(new StationAbility()); + + // STATION 12+ + // {U}, {T}: Add {U} for each artifact you control. + Ability ability = new DynamicManaAbility( + Mana.BlueMana(1), ArtifactYouControlCount.instance, new ManaCostsImpl<>("{U}") + ); + ability.addCost(new TapSourceCost()); + this.addAbility(new StationLevelAbility(12).withLevelAbility(ability).addHint(ArtifactYouControlHint.instance)); + } + + private UthrosTitanicGodcore(final UthrosTitanicGodcore card) { + super(card); + } + + @Override + public UthrosTitanicGodcore copy() { + return new UthrosTitanicGodcore(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UvildaDeanOfPerfection.java b/Mage.Sets/src/mage/cards/u/UvildaDeanOfPerfection.java index e12ddb9f71c..0ebeb033f7a 100644 --- a/Mage.Sets/src/mage/cards/u/UvildaDeanOfPerfection.java +++ b/Mage.Sets/src/mage/cards/u/UvildaDeanOfPerfection.java @@ -5,16 +5,15 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.*; import mage.constants.*; import mage.counters.CounterType; @@ -58,9 +57,7 @@ public final class UvildaDeanOfPerfection extends ModalDoubleFacedCard { this.getRightHalfCard().setPT(4, 4); // At the beginning of your upkeep, exile the top card of each opponent's library. Until end of turn, you may cast spells from among those exiled cards, and you many spend mana as though it were mana of any color to cast those spells. - this.getRightHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility( - new NassariDeanOfExpressionEffect() - )); + this.getRightHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new NassariDeanOfExpressionEffect())); // Whenever you cast a spell from exile, put a +1/+1 counter on Nassari, Dean of Expression. this.getRightHalfCard().addAbility(SpellCastControllerTriggeredAbility.createWithFromZone( @@ -150,13 +147,11 @@ class UvildaDeanOfPerfectionGainAbilityEffect extends ContinuousEffectImpl { discard(); return true; } - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - Zone.EXILED, TargetController.YOU, new RemoveCounterSourceEffect(CounterType.HONE.createInstance()), - false - ), UvildaDeanOfPerfectionCondition.instance, "At the beginning of your upkeep, " + - "if this card is exiled, remove a hone counter from it." - ); + Ability ability = new BeginningOfUpkeepTriggeredAbility( + Zone.EXILED, TargetController.YOU, + new RemoveCounterSourceEffect(CounterType.HONE.createInstance()) + .setText("remove a hone counter from it"), false + ).withInterveningIf(UvildaDeanOfPerfectionCondition.instance); ability.setSourceId(card.getId()); ability.setControllerId(source.getControllerId()); game.getState().addOtherAbility(card, ability); @@ -175,6 +170,11 @@ enum UvildaDeanOfPerfectionCondition implements Condition { public boolean apply(Game game, Ability source) { return game.getState().getZone(source.getSourceId()) == Zone.EXILED; } + + @Override + public String toString() { + return "this card is exiled"; + } } class UvildaDeanOfPerfectionTriggeredAbility extends TriggeredAbilityImpl { diff --git a/Mage.Sets/src/mage/cards/v/VadersCommand.java b/Mage.Sets/src/mage/cards/v/VadersCommand.java index a1aa2db0f09..4e9181879af 100644 --- a/Mage.Sets/src/mage/cards/v/VadersCommand.java +++ b/Mage.Sets/src/mage/cards/v/VadersCommand.java @@ -51,7 +51,7 @@ public final class VadersCommand extends CardImpl { // Destroy target nonartifact creature. mode = new Mode(new DestroyTargetEffect()); - mode.addTarget(new TargetCreaturePermanent(filterNonArtifact)); + mode.addTarget(new TargetPermanent(filterNonArtifact)); this.getSpellAbility().addMode(mode); // Gain 5 life. diff --git a/Mage.Sets/src/mage/cards/v/VagrantPlowbeasts.java b/Mage.Sets/src/mage/cards/v/VagrantPlowbeasts.java index 86f874ec94f..59c5021cced 100644 --- a/Mage.Sets/src/mage/cards/v/VagrantPlowbeasts.java +++ b/Mage.Sets/src/mage/cards/v/VagrantPlowbeasts.java @@ -14,6 +14,7 @@ import mage.constants.ComparisonType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -38,7 +39,7 @@ public final class VagrantPlowbeasts extends CardImpl { SimpleActivatedAbility ability = new SimpleActivatedAbility( new RegenerateTargetEffect(), new ManaCostsImpl<>("{1}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/ValakutExploration.java b/Mage.Sets/src/mage/cards/v/ValakutExploration.java index a159e3e3cc7..796840a0131 100644 --- a/Mage.Sets/src/mage/cards/v/ValakutExploration.java +++ b/Mage.Sets/src/mage/cards/v/ValakutExploration.java @@ -1,17 +1,19 @@ package mage.cards.v; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.LandfallAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; import mage.game.ExileZone; import mage.game.Game; import mage.game.permanent.Permanent; @@ -34,13 +36,8 @@ public final class ValakutExploration extends CardImpl { this.addAbility(new LandfallAbility(new ValakutExplorationExileEffect())); // At the beginning of your end step, if there are cards exiled with Valakut Exploration, put them into their owner's graveyard, then Valakut Exploration deals that much damage to each opponent. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - new ValakutExplorationDamageEffect() - ), ValakutExplorationCondition.instance, "At the beginning of your end step, " + - "if there are cards exiled with {this}, put them into their owner's graveyard, " + - "then {this} deals that much damage to each opponent." - )); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new ValakutExplorationDamageEffect()) + .withInterveningIf(ValakutExplorationCondition.instance)); } private ValakutExploration(final ValakutExploration card) { @@ -63,6 +60,11 @@ enum ValakutExplorationCondition implements Condition { )); return exileZone != null && !exileZone.isEmpty(); } + + @Override + public String toString() { + return "there are cards exiled with {this}"; + } } class ValakutExplorationExileEffect extends OneShotEffect { @@ -109,6 +111,7 @@ class ValakutExplorationDamageEffect extends OneShotEffect { ValakutExplorationDamageEffect() { super(Outcome.Benefit); + staticText = "put them into their owner's graveyard, then {this} deals that much damage to each opponent"; } private ValakutExplorationDamageEffect(final ValakutExplorationDamageEffect effect) { diff --git a/Mage.Sets/src/mage/cards/v/ValkiGodOfLies.java b/Mage.Sets/src/mage/cards/v/ValkiGodOfLies.java index 421af9c0888..667cebb3c60 100644 --- a/Mage.Sets/src/mage/cards/v/ValkiGodOfLies.java +++ b/Mage.Sets/src/mage/cards/v/ValkiGodOfLies.java @@ -97,7 +97,7 @@ class ValkiGodOfLiesRevealExileEffect extends OneShotEffect { ValkiGodOfLiesRevealExileEffect() { super(Outcome.Benefit); - staticText = "each opponent reveals their hand. For each opponent, exile a creature card they revealed this way until Valki leaves the battlefield."; + staticText = "each opponent reveals their hand. For each opponent, exile a creature card they revealed this way until {this} leaves the battlefield."; } private ValkiGodOfLiesRevealExileEffect(final ValkiGodOfLiesRevealExileEffect effect) { @@ -147,7 +147,7 @@ class ValkiGodOfLiesCopyExiledEffect extends OneShotEffect { ValkiGodOfLiesCopyExiledEffect() { super(Outcome.Benefit); - this.staticText = "Choose a creature card exiled with Valki with mana value X. Valki becomes a copy of that card."; + this.staticText = "Choose a creature card exiled with {this} with mana value X. {this} becomes a copy of that card."; } private ValkiGodOfLiesCopyExiledEffect(final ValkiGodOfLiesCopyExiledEffect effect) { diff --git a/Mage.Sets/src/mage/cards/v/ValkyrieHarbinger.java b/Mage.Sets/src/mage/cards/v/ValkyrieHarbinger.java index 41758484d3d..86d46db191e 100644 --- a/Mage.Sets/src/mage/cards/v/ValkyrieHarbinger.java +++ b/Mage.Sets/src/mage/cards/v/ValkyrieHarbinger.java @@ -1,14 +1,13 @@ package mage.cards.v; import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.YouGainedLifeCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.ControllerGainedLifeCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -42,12 +41,8 @@ public final class ValkyrieHarbinger extends CardImpl { this.addAbility(LifelinkAbility.getInstance()); // At the beginning of each end step, if you gained 4 or more life this turn, create a 4/4 white Angel creature token with flying and vigilance. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - TargetController.ANY, new CreateTokenEffect(new AngelVigilanceToken()), - false - ), condition, "At the beginning of each end step, if you gained 4 or more life this turn, " + - "create a 4/4 white Angel creature token with flying and vigilance." + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.ANY, new CreateTokenEffect(new AngelVigilanceToken()), false, condition ).addHint(ControllerGainedLifeCount.getHint()), new PlayerGainedLifeWatcher()); } diff --git a/Mage.Sets/src/mage/cards/v/ValorousStance.java b/Mage.Sets/src/mage/cards/v/ValorousStance.java index 873f94cf3a4..bd1172f1687 100644 --- a/Mage.Sets/src/mage/cards/v/ValorousStance.java +++ b/Mage.Sets/src/mage/cards/v/ValorousStance.java @@ -14,6 +14,7 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ToughnessPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -39,7 +40,7 @@ public final class ValorousStance extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // or destroy target creature with toughness 4 or greater. Mode mode1 = new Mode(new DestroyTargetEffect()); - mode1.addTarget(new TargetCreaturePermanent(filter)); + mode1.addTarget(new TargetPermanent(filter)); this.getSpellAbility().addMode(mode1); } diff --git a/Mage.Sets/src/mage/cards/v/ValorsFlagship.java b/Mage.Sets/src/mage/cards/v/ValorsFlagship.java index 4bc90315f4f..d72e3615232 100644 --- a/Mage.Sets/src/mage/cards/v/ValorsFlagship.java +++ b/Mage.Sets/src/mage/cards/v/ValorsFlagship.java @@ -1,8 +1,9 @@ package mage.cards.v; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.CycleTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.EffectKeyValue; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.*; import mage.cards.CardImpl; @@ -10,12 +11,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.token.PilotSaddleCrewToken; -import mage.game.stack.StackObject; -import mage.util.CardUtil; import java.util.UUID; @@ -48,7 +44,8 @@ public final class ValorsFlagship extends CardImpl { this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{X}{2}{W}"))); // When you cycle this card, create X 1/1 colorless Pilot creature tokens with "This token saddles Mounts and crews Vehicles as though its power were 2 greater." - this.addAbility(new ValorsFlagshipTriggeredAbility()); + this.addAbility(new CycleTriggeredAbility( + new CreateTokenEffect(new PilotSaddleCrewToken(), new EffectKeyValue("cycleXValue", "X")))); } private ValorsFlagship(final ValorsFlagship card) { @@ -60,45 +57,3 @@ public final class ValorsFlagship extends CardImpl { return new ValorsFlagship(this); } } - -class ValorsFlagshipTriggeredAbility extends TriggeredAbilityImpl { - - ValorsFlagshipTriggeredAbility() { - super(Zone.ALL, null); - } - - private ValorsFlagshipTriggeredAbility(final ValorsFlagshipTriggeredAbility ability) { - super(ability); - } - - @Override - public ValorsFlagshipTriggeredAbility copy() { - return new ValorsFlagshipTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (!event.getSourceId().equals(this.getSourceId())) { - return false; - } - StackObject object = game.getStack().getStackObject(event.getSourceId()); - if (object == null || !(object.getStackAbility() instanceof CyclingAbility)) { - return false; - } - this.getEffects().clear(); - int amount = CardUtil.getSourceCostsTag(game, object.getStackAbility(), "X", 0); - this.addEffect(new CreateTokenEffect(new PilotSaddleCrewToken(), amount)); - return true; - } - - @Override - public String getRule() { - return "When you cycle this card, create X 1/1 colorless Pilot creature tokens with " + - "\"This token saddles Mounts and crews Vehicles as though its power were 2 greater.\""; - } -} diff --git a/Mage.Sets/src/mage/cards/v/VampireSocialite.java b/Mage.Sets/src/mage/cards/v/VampireSocialite.java index f3d3f1a725e..41b9b6d906b 100644 --- a/Mage.Sets/src/mage/cards/v/VampireSocialite.java +++ b/Mage.Sets/src/mage/cards/v/VampireSocialite.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.OpponentsLostLifeCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.decorator.ConditionalReplacementEffect; import mage.abilities.effects.common.EntersWithCountersControlledEffect; import mage.abilities.effects.common.counter.AddCountersAllEffect; @@ -43,11 +42,9 @@ public final class VampireSocialite extends CardImpl { this.addAbility(new MenaceAbility()); // When Vampire Socialite enters the battlefield, if an opponent lost life this turn, put a +1/+1 counter on each other Vampire you control. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter)), - OpponentsLostLifeCondition.instance, - "When {this} enters, if an opponent lost life this turn, put a +1/+1 counter on each other Vampire you control." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter) + ).withInterveningIf(OpponentsLostLifeCondition.instance)); // As long as an opponent lost life this turn, each other Vampire you control enters the battlefield with an additional +1/+1 counter on it. this.addAbility(new SimpleStaticAbility(new ConditionalReplacementEffect( @@ -55,7 +52,7 @@ public final class VampireSocialite extends CardImpl { filter, CounterType.P1P1.createInstance(), true ), OpponentsLostLifeCondition.instance ).setText("as long as an opponent lost life this turn, " + - "each other Vampire you control enters the battlefield with an additional +1/+1 counter on it"))); + "each other Vampire you control enters with an additional +1/+1 counter on it"))); } private VampireSocialite(final VampireSocialite card) { diff --git a/Mage.Sets/src/mage/cards/v/Vanquish.java b/Mage.Sets/src/mage/cards/v/Vanquish.java index b23f8e6ca95..2be4b3340fc 100644 --- a/Mage.Sets/src/mage/cards/v/Vanquish.java +++ b/Mage.Sets/src/mage/cards/v/Vanquish.java @@ -7,6 +7,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterBlockingCreature; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -21,7 +22,7 @@ public final class Vanquish extends CardImpl { // Destroy target blocking creature. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterBlockingCreature())); + this.getSpellAbility().addTarget(new TargetPermanent(new FilterBlockingCreature())); } private Vanquish(final Vanquish card) { diff --git a/Mage.Sets/src/mage/cards/v/VanquishTheFoul.java b/Mage.Sets/src/mage/cards/v/VanquishTheFoul.java index 9786d09d236..b132119e2d2 100644 --- a/Mage.Sets/src/mage/cards/v/VanquishTheFoul.java +++ b/Mage.Sets/src/mage/cards/v/VanquishTheFoul.java @@ -11,6 +11,7 @@ import mage.constants.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -30,7 +31,7 @@ public final class VanquishTheFoul extends CardImpl { // Destroy target creature with power 4 or greater. Scry 1. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); this.getSpellAbility().addTarget(target); this.getSpellAbility().addEffect(new ScryEffect(1)); } diff --git a/Mage.Sets/src/mage/cards/v/VassalsDuty.java b/Mage.Sets/src/mage/cards/v/VassalsDuty.java index f1844c0b0a5..c5ac751485c 100644 --- a/Mage.Sets/src/mage/cards/v/VassalsDuty.java +++ b/Mage.Sets/src/mage/cards/v/VassalsDuty.java @@ -1,7 +1,5 @@ - package mage.cards.v; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.GenericManaCost; @@ -10,32 +8,25 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.SuperType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; +import mage.target.TargetPermanent; import mage.target.TargetPlayer; -import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class VassalsDuty extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("legendary creature you control"); - - static { - filter.add(SuperType.LEGENDARY.getPredicate()); - } - public VassalsDuty(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); // {1}: The next 1 damage that would be dealt to target legendary creature you control this turn is dealt to you instead. - Ability ability = new SimpleActivatedAbility(new VassalsDutyPreventDamageTargetEffect(Duration.EndOfTurn, 1), new GenericManaCost(1)); - ability.addTarget(new TargetControlledCreaturePermanent(1, 1, filter, false)); + Ability ability = new SimpleActivatedAbility(new VassalsDutyPreventDamageTargetEffect(), new GenericManaCost(1)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_CREATURE_LEGENDARY)); this.addAbility(ability); } @@ -51,9 +42,9 @@ public final class VassalsDuty extends CardImpl { class VassalsDutyPreventDamageTargetEffect extends RedirectionEffect { - VassalsDutyPreventDamageTargetEffect(Duration duration, int amount) { - super(duration, amount, UsageType.ONE_USAGE_ABSOLUTE); - staticText = "The next " + amount + " damage that would be dealt to target legendary creature you control this turn is dealt to you instead"; + VassalsDutyPreventDamageTargetEffect() { + super(Duration.EndOfTurn, 1, UsageType.ONE_USAGE_ABSOLUTE); + staticText = "The next 1 damage that would be dealt to target legendary creature you control this turn is dealt to you instead"; } private VassalsDutyPreventDamageTargetEffect(final VassalsDutyPreventDamageTargetEffect effect) { @@ -67,13 +58,13 @@ class VassalsDutyPreventDamageTargetEffect extends RedirectionEffect { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getTargetId().equals(getTargetPointer().getFirst(game, source))) { - TargetPlayer target = new TargetPlayer(); - target.add(source.getControllerId(), game); - redirectTarget = target; - return true; + if (!event.getTargetId().equals(getTargetPointer().getFirst(game, source))) { + return false; } - return false; + TargetPlayer target = new TargetPlayer(); + target.add(source.getControllerId(), game); + redirectTarget = target; + return true; } } diff --git a/Mage.Sets/src/mage/cards/v/Vault87ForcedEvolution.java b/Mage.Sets/src/mage/cards/v/Vault87ForcedEvolution.java index d5346befc1f..845eafcc52a 100644 --- a/Mage.Sets/src/mage/cards/v/Vault87ForcedEvolution.java +++ b/Mage.Sets/src/mage/cards/v/Vault87ForcedEvolution.java @@ -18,11 +18,15 @@ import mage.counters.CounterType; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.constants.Duration.WhileControlled; +import static mage.constants.SagaChapter.CHAPTER_I; + /** * @author Cguy7777 */ @@ -54,9 +58,9 @@ public final class Vault87ForcedEvolution extends CardImpl { // I -- Gain control of target non-Mutant creature for as long as you control Vault 87. sagaAbility.addChapterEffect( this, - SagaChapter.CHAPTER_I, - new GainControlTargetEffect(Duration.WhileControlled), - new TargetCreaturePermanent(filterNonMutant)); + CHAPTER_I, + new GainControlTargetEffect(WhileControlled), + new TargetPermanent(filterNonMutant)); // II -- Put a +1/+1 counter on target creature you control. It becomes a Mutant in addition to its other types. sagaAbility.addChapterEffect( @@ -85,4 +89,4 @@ public final class Vault87ForcedEvolution extends CardImpl { public Vault87ForcedEvolution copy() { return new Vault87ForcedEvolution(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/v/VaultbornTyrant.java b/Mage.Sets/src/mage/cards/v/VaultbornTyrant.java index 5229e88a3e0..bb67b7d2e21 100644 --- a/Mage.Sets/src/mage/cards/v/VaultbornTyrant.java +++ b/Mage.Sets/src/mage/cards/v/VaultbornTyrant.java @@ -4,7 +4,8 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceMatchesFilterCondition; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -19,10 +20,9 @@ import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.permanent.PermanentToken; -import mage.target.targetpointer.FixedTarget; import java.util.UUID; @@ -32,11 +32,15 @@ import java.util.UUID; public final class VaultbornTyrant extends CardImpl { private static final FilterPermanent filter = new FilterControlledCreaturePermanent("creature you control with power 4 or greater"); + private static final FilterPermanent filter2 = new FilterPermanent("it's not a token"); static { filter.add(new PowerPredicate(ComparisonType.OR_GREATER, 4)); + filter2.add(TokenPredicate.FALSE); } + private static final Condition condition = new SourceMatchesFilterCondition(filter2); + public VaultbornTyrant(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}{G}"); @@ -55,15 +59,7 @@ public final class VaultbornTyrant extends CardImpl { this.addAbility(ability); // When Vaultborn Tyrant dies, if it's not a token, create a token that's a copy of it, except it's an artifact in addition to its other types. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new DiesSourceTriggeredAbility( - new VaultbornTyrantCreateCopyEffect(), - false - ), - VaultbornTyrant::checkSource, - "When {this} dies, if it's not a token, create a token that's a copy of it, " - + "except it's an artifact in addition to its other types." - )); + this.addAbility(new DiesSourceTriggeredAbility(new VaultbornTyrantCreateCopyEffect()).withInterveningIf(condition)); } private VaultbornTyrant(final VaultbornTyrant card) { @@ -74,16 +70,13 @@ public final class VaultbornTyrant extends CardImpl { public VaultbornTyrant copy() { return new VaultbornTyrant(this); } - - static boolean checkSource(Game game, Ability source) { - return !(source.getSourcePermanentOrLKI(game) instanceof PermanentToken); - } } class VaultbornTyrantCreateCopyEffect extends OneShotEffect { VaultbornTyrantCreateCopyEffect() { super(Outcome.PutCreatureInPlay); + staticText = "create a token that's a copy of it, except it's an artifact in addition to its other types"; } private VaultbornTyrantCreateCopyEffect(final VaultbornTyrantCreateCopyEffect effect) { @@ -97,14 +90,9 @@ class VaultbornTyrantCreateCopyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (permanent == null) { - return false; - } - CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect( + Permanent permanent = source.getSourcePermanentOrLKI(game); + return permanent != null && new CreateTokenCopyTargetEffect( source.getControllerId(), CardType.ARTIFACT, false - ); - effect.setTargetPointer(new FixedTarget(source.getSourceId(), game)); - return effect.apply(game, source); + ).setSavedPermanent(permanent).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/v/VedalkenCertarch.java b/Mage.Sets/src/mage/cards/v/VedalkenCertarch.java index 4c5a95f70d7..9e12a757502 100644 --- a/Mage.Sets/src/mage/cards/v/VedalkenCertarch.java +++ b/Mage.Sets/src/mage/cards/v/VedalkenCertarch.java @@ -12,14 +12,12 @@ import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; import mage.target.TargetPermanent; import java.util.UUID; - /** * @author Loki */ @@ -41,11 +39,11 @@ public final class VedalkenCertarch extends CardImpl { this.toughness = new MageInt(1); // Metalcraft — {T}: Tap target artifact, creature, or land. Activate this ability only if you control three or more artifacts. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), new TapSourceCost(), MetalcraftCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new TapTargetEffect(), new TapSourceCost(), MetalcraftCondition.instance + ); ability.addTarget(new TargetPermanent(filter)); - ability.setAbilityWord(AbilityWord.METALCRAFT); - ability.addHint(MetalcraftHint.instance); - this.addAbility(ability); + this.addAbility(ability.setAbilityWord(AbilityWord.METALCRAFT).addHint(MetalcraftHint.instance)); } private VedalkenCertarch(final VedalkenCertarch card) { @@ -56,5 +54,4 @@ public final class VedalkenCertarch extends CardImpl { public VedalkenCertarch copy() { return new VedalkenCertarch(this); } - } diff --git a/Mage.Sets/src/mage/cards/v/VedalkenHumiliator.java b/Mage.Sets/src/mage/cards/v/VedalkenHumiliator.java index d6741ad3893..eb0fbf9cc38 100644 --- a/Mage.Sets/src/mage/cards/v/VedalkenHumiliator.java +++ b/Mage.Sets/src/mage/cards/v/VedalkenHumiliator.java @@ -1,10 +1,9 @@ package mage.cards.v; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.MetalcraftCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.LoseAllAbilitiesAllEffect; import mage.abilities.effects.common.continuous.SetBasePowerToughnessAllEffect; import mage.abilities.hint.common.MetalcraftHint; @@ -32,25 +31,14 @@ public final class VedalkenHumiliator extends CardImpl { this.toughness = new MageInt(4); // Metalcraft — Whenever Vedalken Humiliator attacks, if you control three or more artifacts, creatures your opponents control lose all abilities and have base power and toughness 1/1 until end of turn. - TriggeredAbility ability = new AttacksTriggeredAbility( - new SetBasePowerToughnessAllEffect( - 1, 1, Duration.EndOfTurn, - StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE - ), false - ); - ability.addEffect(new LoseAllAbilitiesAllEffect( - StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, - Duration.EndOfTurn - )); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - ability, MetalcraftCondition.instance, - "Whenever {this} attacks, " - + "if you control three or more artifacts, " - + "creatures your opponents control lose all abilities " - + "and have base power and toughness 1/1 until end of turn.") - .setAbilityWord(AbilityWord.METALCRAFT) - .addHint(MetalcraftHint.instance) - ); + Ability ability = new AttacksTriggeredAbility(new LoseAllAbilitiesAllEffect( + StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, Duration.EndOfTurn + ).setText("creatures your opponents control lose all abilities")).withInterveningIf(MetalcraftCondition.instance); + ability.addEffect(new SetBasePowerToughnessAllEffect( + 1, 1, Duration.EndOfTurn, + StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE + ).setText("and have base power and toughness 1/1 until end of turn")); + this.addAbility(ability.setAbilityWord(AbilityWord.METALCRAFT).addHint(MetalcraftHint.instance)); } private VedalkenHumiliator(final VedalkenHumiliator card) { diff --git a/Mage.Sets/src/mage/cards/v/VedalkenShackles.java b/Mage.Sets/src/mage/cards/v/VedalkenShackles.java index 7bf323c778e..81705dd6f62 100644 --- a/Mage.Sets/src/mage/cards/v/VedalkenShackles.java +++ b/Mage.Sets/src/mage/cards/v/VedalkenShackles.java @@ -22,6 +22,7 @@ import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -48,7 +49,7 @@ public final class VedalkenShackles extends CardImpl { "Gain control of target creature with power less than or equal to the number of Islands you control for as long as {this} remains tapped"); Ability ability = new SimpleActivatedAbility(effect, new GenericManaCost(2)); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(controllableCreatures)); + ability.addTarget(new TargetPermanent(controllableCreatures)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/VeilOfBirds.java b/Mage.Sets/src/mage/cards/v/VeilOfBirds.java index 6cf073bbfe3..374b13ce618 100644 --- a/Mage.Sets/src/mage/cards/v/VeilOfBirds.java +++ b/Mage.Sets/src/mage/cards/v/VeilOfBirds.java @@ -1,11 +1,7 @@ package mage.cards.v; -import java.util.UUID; -import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.SpellCastOpponentTriggeredAbility; -import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -13,26 +9,28 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.filter.FilterSpell; import mage.filter.StaticFilters; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class VeilOfBirds extends CardImpl { - private static final FilterSpell filter = new FilterSpell(); - public VeilOfBirds(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); // When an opponent casts a spell, if Veil of Birds is an enchantment, Veil of Birds becomes a 1/1 Bird creature with flying. - TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new VeilOfBirdsToken(), null, Duration.WhileOnBattlefield), - filter, false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), - "When an opponent casts a spell, if {this} is an enchantment, {this} becomes a 1/1 Bird creature with flying.")); + this.addAbility(new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect( + new CreatureToken( + 1, 1, "1/1 Bird creature with flying", SubType.BIRD + ).withAbility(FlyingAbility.getInstance()), null, Duration.WhileOnBattlefield + ), StaticFilters.FILTER_SPELL_A, false) + .withInterveningIf(SourceIsEnchantmentCondition.instance) + .withRuleTextReplacement(true) + .setTriggerPhrase("When an opponent casts a spell, ")); } private VeilOfBirds(final VeilOfBirds card) { @@ -44,23 +42,3 @@ public final class VeilOfBirds extends CardImpl { return new VeilOfBirds(this); } } - -class VeilOfBirdsToken extends TokenImpl { - - public VeilOfBirdsToken() { - super("Bird", "1/1 creature with flying"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.BIRD); - power = new MageInt(1); - toughness = new MageInt(1); - this.addAbility(FlyingAbility.getInstance()); - } - - private VeilOfBirdsToken(final VeilOfBirdsToken token) { - super(token); - } - - public VeilOfBirdsToken copy() { - return new VeilOfBirdsToken(this); - } -} diff --git a/Mage.Sets/src/mage/cards/v/VeilOfSecrecy.java b/Mage.Sets/src/mage/cards/v/VeilOfSecrecy.java index c4829438b5e..dbf44a7a14b 100644 --- a/Mage.Sets/src/mage/cards/v/VeilOfSecrecy.java +++ b/Mage.Sets/src/mage/cards/v/VeilOfSecrecy.java @@ -2,7 +2,6 @@ package mage.cards.v; import mage.ObjectColor; import mage.abilities.costs.common.ReturnToHandChosenControlledPermanentCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.ShroudAbility; @@ -10,42 +9,37 @@ import mage.abilities.keyword.SpliceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.ColorPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** - * * @author LevelX2 */ public final class VeilOfSecrecy extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a blue creature"); + private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("a blue creature"); static { filter.add(new ColorPredicate(ObjectColor.BLUE)); } public VeilOfSecrecy(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); this.subtype.add(SubType.ARCANE); // Target creature gains shroud until end of turn and can't be blocked this turn. - Effect effect = new GainAbilityTargetEffect(ShroudAbility.getInstance(), Duration.EndOfTurn); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(ShroudAbility.getInstance()).setText("target creature gains shroud until end of turn")); + this.getSpellAbility().addEffect(new CantBeBlockedTargetEffect().setText("and can't be blocked this turn")); this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("gains shroud and can't be blocked")); - effect.setText("Target creature gains shroud until end of turn"); - this.getSpellAbility().addEffect(effect); - effect = new CantBeBlockedTargetEffect(); - effect.setText("and can't be blocked this turn"); - this.getSpellAbility().addEffect(effect); - + // Splice onto Arcane-Return a blue creature you control to its owner's hand. - this.addAbility(new SpliceAbility(SpliceAbility.ARCANE, new ReturnToHandChosenControlledPermanentCost(new TargetControlledCreaturePermanent(filter)))); + this.addAbility(new SpliceAbility(SpliceAbility.ARCANE, new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(filter)))); } private VeilOfSecrecy(final VeilOfSecrecy card) { diff --git a/Mage.Sets/src/mage/cards/v/VeiledApparition.java b/Mage.Sets/src/mage/cards/v/VeiledApparition.java index ddb202c6119..0e00a764e22 100644 --- a/Mage.Sets/src/mage/cards/v/VeiledApparition.java +++ b/Mage.Sets/src/mage/cards/v/VeiledApparition.java @@ -1,11 +1,8 @@ package mage.cards.v; -import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.SpellCastOpponentTriggeredAbility; -import mage.abilities.condition.common.SourceMatchesFilterCondition; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.keyword.FlyingAbility; @@ -15,29 +12,31 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.filter.FilterSpell; import mage.filter.StaticFilters; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; import java.util.UUID; /** - * * @author jeffwadsworth */ public final class VeiledApparition extends CardImpl { - - private static final FilterSpell filter = new FilterSpell(); public VeiledApparition(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); // When an opponent casts a spell, if Veiled Apparition is an enchantment, Veiled Apparition becomes a 3/3 Illusion creature with flying and "At the beginning of your upkeep, sacrifice Veiled Apparition unless you pay {1}{U}." - TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new VeiledApparitionToken(), null, Duration.WhileOnBattlefield), - filter, false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), - "When an opponent casts a spell, if {this} is an enchantment, {this} becomes a 3/3 Illusion creature with flying and \"At the beginning of your upkeep, sacrifice Veiled Apparition unless you pay {1}{U}.\"")); - + this.addAbility(new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect( + new CreatureToken( + 3, 3, "3/3 Illusion creature with flying and \"At the beginning " + + "of your upkeep, sacrifice this creature unless you pay {1}{U}.\"", SubType.ILLUSION + ).withAbility(FlyingAbility.getInstance()).withAbility(new BeginningOfUpkeepTriggeredAbility( + new SacrificeSourceUnlessPaysEffect(new ManaCostsImpl<>("{1}{U}")) + )), null, Duration.WhileOnBattlefield + ), StaticFilters.FILTER_SPELL_A, false) + .withInterveningIf(SourceIsEnchantmentCondition.instance) + .withRuleTextReplacement(true) + .setTriggerPhrase("When an opponent casts a spell, ")); } private VeiledApparition(final VeiledApparition card) { @@ -49,26 +48,3 @@ public final class VeiledApparition extends CardImpl { return new VeiledApparition(this); } } - -class VeiledApparitionToken extends TokenImpl { - - VeiledApparitionToken() { - super("Illusion", "3/3 Illusion creature with flying and \"At the beginning of your upkeep, sacrifice Veiled Apparition unless you pay {1}{U}."); - cardType.add(CardType.CREATURE); - subtype.add(SubType.ILLUSION); - power = new MageInt(3); - toughness = new MageInt(3); - this.addAbility(FlyingAbility.getInstance()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility( - new SacrificeSourceUnlessPaysEffect(new ManaCostsImpl<>("{1}{U}")) - )); - } - - private VeiledApparitionToken(final VeiledApparitionToken token) { - super(token); - } - - public VeiledApparitionToken copy() { - return new VeiledApparitionToken(this); - } -} diff --git a/Mage.Sets/src/mage/cards/v/VeiledCrocodile.java b/Mage.Sets/src/mage/cards/v/VeiledCrocodile.java index 66092e37d46..b18d6fc37bc 100644 --- a/Mage.Sets/src/mage/cards/v/VeiledCrocodile.java +++ b/Mage.Sets/src/mage/cards/v/VeiledCrocodile.java @@ -1,7 +1,7 @@ package mage.cards.v; -import mage.MageInt; import mage.abilities.StateTriggeredAbility; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -11,9 +11,11 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; import mage.players.Player; +import java.util.Objects; +import java.util.Set; import java.util.UUID; /** @@ -41,9 +43,14 @@ public final class VeiledCrocodile extends CardImpl { class VeiledCrocodileStateTriggeredAbility extends StateTriggeredAbility { public VeiledCrocodileStateTriggeredAbility() { - super(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new VeilCrocodileToken(), null, Duration.Custom)); - this.withRuleTextReplacement(false); - setTriggerPhrase("When a player has no cards in hand, if {this} is an enchantment, "); + super(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect( + new CreatureToken( + 4, 4, "4/4 Crocodile creature", SubType.CROCODILE + ), null, Duration.Custom + )); + this.withInterveningIf(SourceIsEnchantmentCondition.instance); + this.withRuleTextReplacement(true); + this.setTriggerPhrase("When a player has no cards in hand, "); } private VeiledCrocodileStateTriggeredAbility(final VeiledCrocodileStateTriggeredAbility ability) { @@ -57,41 +64,13 @@ class VeiledCrocodileStateTriggeredAbility extends StateTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - for (UUID playerId : game.getState().getPlayersInRange(controllerId, game)) { - Player player = game.getPlayer(playerId); - if (player != null - && player.getHand().isEmpty()) { - return true; - } - } - return false; - } - - @Override - public boolean checkInterveningIfClause(Game game) { - if (getSourcePermanentIfItStillExists(game) != null) { - return getSourcePermanentIfItStillExists(game).isEnchantment(game); - } - return false; - } - -} - -class VeilCrocodileToken extends TokenImpl { - - public VeilCrocodileToken() { - super("Crocodile", "4/4 Crocodile creature"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.CROCODILE); - power = new MageInt(4); - toughness = new MageInt(4); - } - - private VeilCrocodileToken(final VeilCrocodileToken token) { - super(token); - } - - public VeilCrocodileToken copy() { - return new VeilCrocodileToken(this); + return game + .getState() + .getPlayersInRange(getControllerId(), game) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .map(Player::getHand) + .anyMatch(Set::isEmpty); } } diff --git a/Mage.Sets/src/mage/cards/v/VeiledSentry.java b/Mage.Sets/src/mage/cards/v/VeiledSentry.java index 47e1dafc782..8c6238d454a 100644 --- a/Mage.Sets/src/mage/cards/v/VeiledSentry.java +++ b/Mage.Sets/src/mage/cards/v/VeiledSentry.java @@ -2,14 +2,11 @@ package mage.cards.v; import mage.abilities.Ability; import mage.abilities.common.SpellCastOpponentTriggeredAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.effects.ContinuousEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.stack.Spell; @@ -21,17 +18,14 @@ import java.util.UUID; */ public final class VeiledSentry extends CardImpl { - private static final Condition condition = new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT); - public VeiledSentry(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); // When an opponent casts a spell, if Veiled Sentry is an enchantment, Veiled Sentry becomes an Illusion creature with power and toughness each equal to that spell's converted mana cost. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new SpellCastOpponentTriggeredAbility(new VeiledSentryEffect(), false), - condition, "When an opponent casts a spell, if {this} is an enchantment, " + - "{this} becomes an Illusion creature with power and toughness each equal to that spell's mana value." - )); + this.addAbility(new SpellCastOpponentTriggeredAbility(new VeiledSentryEffect(), false) + .withInterveningIf(SourceIsEnchantmentCondition.instance) + .withRuleTextReplacement(true) + .setTriggerPhrase("When an opponent casts a spell, ")); } private VeiledSentry(final VeiledSentry card) { @@ -50,7 +44,7 @@ class VeiledSentryEffect extends ContinuousEffectImpl { public VeiledSentryEffect() { super(Duration.Custom, Outcome.BecomeCreature); - staticText = "{this} becomes an Illusion creature with power and toughness equal to that spell's mana value"; + staticText = "{this} becomes an Illusion creature with power and toughness each equal to that spell's mana value"; this.dependencyTypes.add(DependencyType.BecomeCreature); } diff --git a/Mage.Sets/src/mage/cards/v/VeiledSerpent.java b/Mage.Sets/src/mage/cards/v/VeiledSerpent.java index 42bf1e8af41..4fbe5a44683 100644 --- a/Mage.Sets/src/mage/cards/v/VeiledSerpent.java +++ b/Mage.Sets/src/mage/cards/v/VeiledSerpent.java @@ -1,13 +1,9 @@ package mage.cards.v; -import java.util.UUID; -import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SpellCastOpponentTriggeredAbility; -import mage.abilities.condition.common.SourceMatchesFilterCondition; +import mage.abilities.condition.common.SourceIsEnchantmentCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.combat.CantAttackUnlessDefenderControllsPermanent; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.keyword.CyclingAbility; @@ -16,30 +12,36 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.FilterSpell; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; -import mage.filter.common.FilterLandPermanent; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class VeiledSerpent extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent(SubType.ISLAND, "an Island"); + public VeiledSerpent(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); // When an opponent casts a spell, if Veiled Serpent is an enchantment, Veiled Serpent becomes a 4/4 Serpent creature that can't attack unless defending player controls an Island. - TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new VeiledSerpentToken(), null, Duration.WhileOnBattlefield), - new FilterSpell(), false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), - "When an opponent casts a spell, if {this} is an enchantment, {this} becomes a 4/4 Serpent creature that can't attack unless defending player controls an Island.")); + this.addAbility(new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect( + new CreatureToken( + 4, 4, "4/4 Serpent creature with " + + "\"This creature can't attack unless defending player controls an Island.\"", + SubType.SERPENT + ).withAbility(new SimpleStaticAbility(new CantAttackUnlessDefenderControllsPermanent(filter))), null, Duration.WhileOnBattlefield + ), StaticFilters.FILTER_SPELL_A, false) + .withInterveningIf(SourceIsEnchantmentCondition.instance) + .withRuleTextReplacement(true) + .setTriggerPhrase("When an opponent casts a spell, ")); // Cycling {2} this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{2}"))); - } private VeiledSerpent(final VeiledSerpent card) { @@ -51,25 +53,3 @@ public final class VeiledSerpent extends CardImpl { return new VeiledSerpent(this); } } - -class VeiledSerpentToken extends TokenImpl { - - public VeiledSerpentToken() { - super("Serpent", "4/4 Serpent creature"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.SERPENT); - power = new MageInt(4); - toughness = new MageInt(4); - this.addAbility(new SimpleStaticAbility( - new CantAttackUnlessDefenderControllsPermanent( - new FilterLandPermanent(SubType.ISLAND, "an Island")))); - } - - private VeiledSerpentToken(final VeiledSerpentToken token) { - super(token); - } - - public VeiledSerpentToken copy() { - return new VeiledSerpentToken(this); - } -} diff --git a/Mage.Sets/src/mage/cards/v/Vendetta.java b/Mage.Sets/src/mage/cards/v/Vendetta.java index e643f7395f5..94280219839 100644 --- a/Mage.Sets/src/mage/cards/v/Vendetta.java +++ b/Mage.Sets/src/mage/cards/v/Vendetta.java @@ -12,8 +12,11 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author North, Loki @@ -24,7 +27,7 @@ public final class Vendetta extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{B}"); // Destroy target nonblack creature. It can't be regenerated. You lose life equal to that creature's toughness. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); this.getSpellAbility().addEffect(new VendettaEffect()); } diff --git a/Mage.Sets/src/mage/cards/v/VenerableWarsinger.java b/Mage.Sets/src/mage/cards/v/VenerableWarsinger.java index 269eb2ba72a..45782471e5b 100644 --- a/Mage.Sets/src/mage/cards/v/VenerableWarsinger.java +++ b/Mage.Sets/src/mage/cards/v/VenerableWarsinger.java @@ -1,7 +1,10 @@ package mage.cards.v; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.dynamicvalue.common.EffectKeyValue; +import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.VigilanceAbility; @@ -10,15 +13,10 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.mageobject.ManaValuePredicate; -import mage.game.Game; -import mage.game.events.DamagedEvent; -import mage.game.events.GameEvent; -import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.ManaValueTargetAdjuster; import java.util.UUID; @@ -27,6 +25,8 @@ import java.util.UUID; */ public final class VenerableWarsinger extends CardImpl { + private static final FilterCard filter = new FilterCreatureCard("creature card with mana value X or less from your graveyard"); + public VenerableWarsinger(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{W}"); @@ -42,7 +42,11 @@ public final class VenerableWarsinger extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Whenever Venerable Warsinger deals combat damage to a player, you may return target creature card with mana value X or less from your graveyard to the battlefield, where X is the amount of damage that Venerable Warsinger dealt to that player. - this.addAbility(new VenerableWarsingerTriggeredAbility()); + Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), true); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + ability.setTargetAdjuster(new ManaValueTargetAdjuster(new EffectKeyValue("damage"), ComparisonType.OR_LESS)); + ability.addEffect(new InfoEffect("where X is the amount of damage {this} dealt to that player").concatBy(",")); + this.addAbility(ability); } private VenerableWarsinger(final VenerableWarsinger card) { @@ -54,48 +58,3 @@ public final class VenerableWarsinger extends CardImpl { return new VenerableWarsinger(this); } } - -class VenerableWarsingerTriggeredAbility extends TriggeredAbilityImpl { - - VenerableWarsingerTriggeredAbility() { - super(Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect(), true); - } - - private VenerableWarsingerTriggeredAbility(final VenerableWarsingerTriggeredAbility ability) { - super(ability); - } - - @Override - public VenerableWarsingerTriggeredAbility copy() { - return new VenerableWarsingerTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Player player = game.getPlayer(event.getPlayerId()); - if (player == null - || !event.getSourceId().equals(getSourceId()) - || !((DamagedEvent) event).isCombatDamage()) { - return false; - } - FilterCard filter = new FilterCreatureCard( - "creature card with mana value " + event.getAmount() + " less from your graveyard" - ); - filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, event.getAmount() + 1)); - this.getTargets().clear(); - this.addTarget(new TargetCardInYourGraveyard(filter)); - return true; - } - - @Override - public String getRule() { - return "Whenever {this} deals combat damage to a player, you may return target creature card " + - "with mana value X or less from your graveyard to the battlefield, " + - "where X is the amount of damage {this} dealt to that player."; - } -} diff --git a/Mage.Sets/src/mage/cards/v/Vengeance.java b/Mage.Sets/src/mage/cards/v/Vengeance.java index b2c7b6185c2..bd1c4ca4530 100644 --- a/Mage.Sets/src/mage/cards/v/Vengeance.java +++ b/Mage.Sets/src/mage/cards/v/Vengeance.java @@ -8,6 +8,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -26,7 +27,7 @@ public final class Vengeance extends CardImpl { // Destroy target tapped creature. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/v/VengeantVampire.java b/Mage.Sets/src/mage/cards/v/VengeantVampire.java index 528316fc75c..91d783f056c 100644 --- a/Mage.Sets/src/mage/cards/v/VengeantVampire.java +++ b/Mage.Sets/src/mage/cards/v/VengeantVampire.java @@ -11,10 +11,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * @author JayDi85 */ @@ -32,7 +35,7 @@ public final class VengeantVampire extends CardImpl { // When Vengeant Vampire dies, destroy target creature an opponent controls and you gain 4 life. Ability ability = new DiesSourceTriggeredAbility(new DestroyTargetEffect()); ability.addEffect(new GainLifeEffect(4).concatBy("and")); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/VengefulDevil.java b/Mage.Sets/src/mage/cards/v/VengefulDevil.java index 5502c231501..69eacef6830 100644 --- a/Mage.Sets/src/mage/cards/v/VengefulDevil.java +++ b/Mage.Sets/src/mage/cards/v/VengefulDevil.java @@ -13,7 +13,6 @@ import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.target.common.TargetAnyTarget; import java.util.UUID; @@ -35,12 +34,10 @@ public final class VengefulDevil extends CardImpl { // Morbid — {T}: Vengeful Devil deals 1 damage to any target. Activate this ability only if a creature died this turn. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new DamageTargetEffect(1), - new TapSourceCost(), MorbidCondition.instance + new DamageTargetEffect(1), new TapSourceCost(), MorbidCondition.instance ); ability.addTarget(new TargetAnyTarget()); - ability.setAbilityWord(AbilityWord.MORBID); - this.addAbility(ability.addHint(MorbidHint.instance)); + this.addAbility(ability.setAbilityWord(AbilityWord.MORBID).addHint(MorbidHint.instance)); } private VengefulDevil(final VengefulDevil card) { diff --git a/Mage.Sets/src/mage/cards/v/VengefulPharaoh.java b/Mage.Sets/src/mage/cards/v/VengefulPharaoh.java index d241d75645a..c16b58cfe3f 100644 --- a/Mage.Sets/src/mage/cards/v/VengefulPharaoh.java +++ b/Mage.Sets/src/mage/cards/v/VengefulPharaoh.java @@ -56,7 +56,7 @@ class VengefulPharaohTriggeredAbility extends TriggeredAbilityImpl implements Ba VengefulPharaohTriggeredAbility() { super(Zone.GRAVEYARD, new DestroyTargetEffect(), false); this.addTarget(new TargetAttackingCreature()); - this.addEffect(new PutOnLibrarySourceEffect(true).setText(", then put {this} on top of your library")); + this.addEffect(new PutOnLibrarySourceEffect(true).setText(", then put this card on top of your library")); this.withInterveningIf(SourceInGraveyardCondition.instance); setTriggerPhrase("Whenever combat damage is dealt to you or a planeswalker you control, "); } @@ -95,5 +95,4 @@ class VengefulPharaohTriggeredAbility extends TriggeredAbilityImpl implements Ba } return false; } - } diff --git a/Mage.Sets/src/mage/cards/v/VenomousBreath.java b/Mage.Sets/src/mage/cards/v/VenomousBreath.java index 6da5caa866d..49a7c85d0a9 100644 --- a/Mage.Sets/src/mage/cards/v/VenomousBreath.java +++ b/Mage.Sets/src/mage/cards/v/VenomousBreath.java @@ -101,7 +101,7 @@ class VenomousBreathEffect extends OneShotEffect { List toDestroy = new ArrayList<>(); for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { if (!creature.getId().equals(targetCreature.getSourceId())) { - if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), targetCreature, game) || watcher.creatureHasBlockedAttacker(targetCreature, new MageObjectReference(creature, game), game)) { + if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), targetCreature) || watcher.creatureHasBlockedAttacker(targetCreature, new MageObjectReference(creature, game))) { toDestroy.add(creature); } } diff --git a/Mage.Sets/src/mage/cards/v/VenomspoutBrackus.java b/Mage.Sets/src/mage/cards/v/VenomspoutBrackus.java index 8c42d93e58b..36775b55f29 100644 --- a/Mage.Sets/src/mage/cards/v/VenomspoutBrackus.java +++ b/Mage.Sets/src/mage/cards/v/VenomspoutBrackus.java @@ -17,6 +17,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterAttackingOrBlockingCreature; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -42,7 +43,7 @@ public final class VenomspoutBrackus extends CardImpl { // {1}{G}, {tap}: Venomspout Brackus deals 5 damage to target attacking or blocking creature with flying. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(5), new ManaCostsImpl<>("{1}{G}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Morph {3}{G}{G} this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{3}{G}{G}"))); diff --git a/Mage.Sets/src/mage/cards/v/VerdelothTheAncient.java b/Mage.Sets/src/mage/cards/v/VerdelothTheAncient.java index 56fd68be9fb..f3fc8285a67 100644 --- a/Mage.Sets/src/mage/cards/v/VerdelothTheAncient.java +++ b/Mage.Sets/src/mage/cards/v/VerdelothTheAncient.java @@ -5,7 +5,6 @@ import mage.MageObject; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; @@ -54,10 +53,9 @@ public final class VerdelothTheAncient extends CardImpl { ))); // When Verdeloth the Ancient enters the battlefield, if it was kicked, create X 1/1 green Saproling creature tokens. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( - new CreateTokenEffect(new SaprolingToken(), GetXValue.instance), false - ), KickedCondition.ONCE, "When {this} enters, " + - "if it was kicked, create X 1/1 green Saproling creature tokens.")); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new CreateTokenEffect(new SaprolingToken(), GetXValue.instance) + ).withInterveningIf(KickedCondition.ONCE)); } private VerdelothTheAncient(final VerdelothTheAncient card) { diff --git a/Mage.Sets/src/mage/cards/v/VerduranEmissary.java b/Mage.Sets/src/mage/cards/v/VerduranEmissary.java index b4cf54eef45..79c6e24a4e7 100644 --- a/Mage.Sets/src/mage/cards/v/VerduranEmissary.java +++ b/Mage.Sets/src/mage/cards/v/VerduranEmissary.java @@ -1,12 +1,9 @@ - package mage.cards.v; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; @@ -15,14 +12,15 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.target.common.TargetArtifactPermanent; +import java.util.UUID; + /** - * * @author FenrisulfrX */ public final class VerduranEmissary extends CardImpl { public VerduranEmissary(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(2); @@ -32,10 +30,9 @@ public final class VerduranEmissary extends CardImpl { this.addAbility(new KickerAbility("{1}{R}")); // When {this} enters, if it was kicked, destroy target artifact. It can't be regenerated. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(true)); + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(true)).withInterveningIf(KickedCondition.ONCE); ability.addTarget(new TargetArtifactPermanent()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.ONCE, - "When {this} enters, if it was kicked, destroy target artifact. It can't be regenerated.")); + this.addAbility(ability); } private VerduranEmissary(final VerduranEmissary card) { diff --git a/Mage.Sets/src/mage/cards/v/VerityCircle.java b/Mage.Sets/src/mage/cards/v/VerityCircle.java index f34265717bc..9cebaf64cc7 100644 --- a/Mage.Sets/src/mage/cards/v/VerityCircle.java +++ b/Mage.Sets/src/mage/cards/v/VerityCircle.java @@ -13,6 +13,7 @@ import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -36,7 +37,7 @@ public final class VerityCircle extends CardImpl { // {4}{U}: Tap target creature without flying. Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new ManaCostsImpl<>("{4}{U}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/VerixBladewing.java b/Mage.Sets/src/mage/cards/v/VerixBladewing.java index 94bb69ff6c8..1fe5e6a02c2 100644 --- a/Mage.Sets/src/mage/cards/v/VerixBladewing.java +++ b/Mage.Sets/src/mage/cards/v/VerixBladewing.java @@ -1,11 +1,8 @@ package mage.cards.v; -import java.util.UUID; - import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.KickerAbility; @@ -16,9 +13,11 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.game.permanent.token.KaroxBladewingDragonToken; +import java.util.UUID; + /** * @author JRHerlehy - * Created on 4/5/18. + * Created on 4/5/18. */ public final class VerixBladewing extends CardImpl { @@ -38,12 +37,7 @@ public final class VerixBladewing extends CardImpl { // When Verix Bladewing enters the battlefield, if it was kicked, create Karox Bladewing, // a legendary 4/4 red Dragon creature token with flying. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility( - new CreateTokenEffect(new KaroxBladewingDragonToken())); - - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.ONCE, - "When {this} enters, if it was kicked, create Karox Bladewing, " + - "a legendary 4/4 red Dragon creature token with flying.")); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new KaroxBladewingDragonToken())).withInterveningIf(KickedCondition.ONCE)); } private VerixBladewing(final VerixBladewing card) { diff --git a/Mage.Sets/src/mage/cards/v/Vertigo.java b/Mage.Sets/src/mage/cards/v/Vertigo.java index 37d06241451..4e51ad30f95 100644 --- a/Mage.Sets/src/mage/cards/v/Vertigo.java +++ b/Mage.Sets/src/mage/cards/v/Vertigo.java @@ -11,6 +11,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -33,7 +34,7 @@ public final class Vertigo extends CardImpl { this.getSpellAbility().addEffect(new DamageTargetEffect(2)); this.getSpellAbility().addEffect(new LoseAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn) .setText("That creature loses flying until end of turn")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private Vertigo(final Vertigo card) { diff --git a/Mage.Sets/src/mage/cards/v/VeryCrypticCommandD.java b/Mage.Sets/src/mage/cards/v/VeryCrypticCommandD.java index 7286e6f419a..5e213c26ee9 100644 --- a/Mage.Sets/src/mage/cards/v/VeryCrypticCommandD.java +++ b/Mage.Sets/src/mage/cards/v/VeryCrypticCommandD.java @@ -69,7 +69,7 @@ public final class VeryCrypticCommandD extends CardImpl { // Turn over target nontoken creature. mode = new Mode(new TurnOverEffect()); - mode.addTarget(new TargetCreaturePermanent(filter2)); + mode.addTarget(new TargetPermanent(filter2)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/v/VesselOfTheAllConsuming.java b/Mage.Sets/src/mage/cards/v/VesselOfTheAllConsuming.java index d0162684638..a4ac3365a20 100644 --- a/Mage.Sets/src/mage/cards/v/VesselOfTheAllConsuming.java +++ b/Mage.Sets/src/mage/cards/v/VesselOfTheAllConsuming.java @@ -5,7 +5,7 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DealsDamageSourceTriggeredAbility; import mage.abilities.common.DealsDamageToAPlayerTriggeredAbility; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.effects.common.LoseGameTargetPlayerEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.TrampleAbility; @@ -49,12 +49,9 @@ public final class VesselOfTheAllConsuming extends CardImpl { this.addAbility(new DealsDamageSourceTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()))); // Whenever Vessel of the All-Consuming deals damage to a player, if it has dealt 10 or more damage to that player this turn, they lose the game. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new DealsDamageToAPlayerTriggeredAbility( - new LoseGameTargetPlayerEffect(), false, true - ), VesselOfTheAllConsumingWatcher::checkPermanent, "Whenever {this} deals damage to a player, " + - "if it has dealt 10 or more damage to that player this turn, they lose the game." - )); + this.addAbility(new DealsDamageToAPlayerTriggeredAbility( + new LoseGameTargetPlayerEffect().setText("they lose the game"), false, true + ).withInterveningIf(VesselOfTheAllConsumingCondition.instance)); } private VesselOfTheAllConsuming(final VesselOfTheAllConsuming card) { @@ -71,6 +68,20 @@ public final class VesselOfTheAllConsuming extends CardImpl { } } +enum VesselOfTheAllConsumingCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return VesselOfTheAllConsumingWatcher.checkPermanent(game, source); + } + + @Override + public String toString() { + return "it has dealt 10 or more damage to that player this turn"; + } +} + class VesselOfTheAllConsumingWatcher extends Watcher { private final Map, Integer> morMap = new HashMap<>(); diff --git a/Mage.Sets/src/mage/cards/v/VesuvanShapeshifter.java b/Mage.Sets/src/mage/cards/v/VesuvanShapeshifter.java index 40f766221b7..bcab5c07bda 100644 --- a/Mage.Sets/src/mage/cards/v/VesuvanShapeshifter.java +++ b/Mage.Sets/src/mage/cards/v/VesuvanShapeshifter.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.AsTurnedFaceUpEffect; @@ -13,16 +12,18 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CopyEffect; import mage.abilities.effects.common.CopyPermanentEffect; import mage.abilities.keyword.MorphAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import mage.util.functions.CopyApplier; import java.util.UUID; @@ -104,11 +105,7 @@ class VesuvanShapeshifterEffect extends OneShotEffect { Permanent copyToCreature = game.getPermanent(source.getSourceId()); if (copyToCreature != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); - filter.add(AnotherPredicate.instance); - - TargetCreaturePermanent target = new TargetCreaturePermanent(0, 1, filter, true); - + TargetPermanent target = new TargetPermanent(0, 1, StaticFilters.FILTER_ANOTHER_CREATURE, true); if (controller != null && controller.chooseTarget(Outcome.BecomeCreature, target, source, game) && !target.getTargets().isEmpty()) { Permanent copyFromCreature = game.getPermanentOrLKIBattlefield(target.getFirstTarget()); if (copyFromCreature != null) { diff --git a/Mage.Sets/src/mage/cards/v/VeteranCathar.java b/Mage.Sets/src/mage/cards/v/VeteranCathar.java index 916d21e0def..d25272fd073 100644 --- a/Mage.Sets/src/mage/cards/v/VeteranCathar.java +++ b/Mage.Sets/src/mage/cards/v/VeteranCathar.java @@ -15,8 +15,11 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.constants.SubType.HUMAN; + /** * * @author LevelX2 @@ -32,7 +35,7 @@ public final class VeteranCathar extends CardImpl { // {3}{W}: Target Human gains double strike until end of turn. Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{3}{W}")); - ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent(SubType.HUMAN, "Human"))); + ability.addTarget(new TargetPermanent(new FilterCreaturePermanent(HUMAN, "Human"))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/VeteransVoice.java b/Mage.Sets/src/mage/cards/v/VeteransVoice.java index fc36117feea..32160ab522a 100644 --- a/Mage.Sets/src/mage/cards/v/VeteransVoice.java +++ b/Mage.Sets/src/mage/cards/v/VeteransVoice.java @@ -10,7 +10,10 @@ import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; @@ -49,7 +52,6 @@ public final class VeteransVoice extends CardImpl { // Tap enchanted creature: Target creature other than the creature tapped this way gets +2/+1 until end of turn. Activate this ability only if enchanted creature is untapped. this.addAbility(new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new BoostTargetEffect(2, 1, Duration.EndOfTurn) .setText("target creature other than the creature tapped this way gets +2/+1 until end of turn"), new TapAttachedCost(), condition diff --git a/Mage.Sets/src/mage/cards/v/ViashinoHeretic.java b/Mage.Sets/src/mage/cards/v/ViashinoHeretic.java index bc04c348b9d..271ab8d64dd 100644 --- a/Mage.Sets/src/mage/cards/v/ViashinoHeretic.java +++ b/Mage.Sets/src/mage/cards/v/ViashinoHeretic.java @@ -11,7 +11,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -53,7 +52,7 @@ class ViashinoHereticEffect extends OneShotEffect { public ViashinoHereticEffect() { super(Outcome.DestroyPermanent); - this.staticText = "Destroy target artifact. Viashino Heretic deals damage to that artifact's controller equal to the artifact's mana value"; + this.staticText = "Destroy target artifact. {this} deals damage to that artifact's controller equal to the artifact's mana value"; } private ViashinoHereticEffect(final ViashinoHereticEffect effect) { diff --git a/Mage.Sets/src/mage/cards/v/ViconiaDrowApostate.java b/Mage.Sets/src/mage/cards/v/ViconiaDrowApostate.java index 4af8640dfef..0bf96e52df6 100644 --- a/Mage.Sets/src/mage/cards/v/ViconiaDrowApostate.java +++ b/Mage.Sets/src/mage/cards/v/ViconiaDrowApostate.java @@ -1,18 +1,20 @@ package mage.cards.v; import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.ChooseABackgroundAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.common.ReturnFromGraveyardAtRandomEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; import mage.filter.StaticFilters; import java.util.UUID; @@ -23,7 +25,7 @@ import java.util.UUID; public final class ViconiaDrowApostate extends CardImpl { private static final Condition condition - = new CardsInControllerGraveyardCondition(4, StaticFilters.FILTER_CARD_CREATURE); + = new CardsInControllerGraveyardCondition(4, StaticFilters.FILTER_CARD_CREATURES); private static final Hint hint = new ValueHint( "Creature cards in your graveyard", new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURE) @@ -39,12 +41,9 @@ public final class ViconiaDrowApostate extends CardImpl { this.toughness = new MageInt(3); // At the beginning of your upkeep, if there are four or more creature cards in your graveyard, return a creature card at random from your graveyard to your hand. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - new ReturnFromGraveyardAtRandomEffect(StaticFilters.FILTER_CARD_CREATURE, Zone.HAND), false - ), condition, "At the beginning of your upkeep, if there are four or more creature cards " + - "in your graveyard, return a creature card at random from your graveyard to your hand." - ).addHint(hint)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new ReturnFromGraveyardAtRandomEffect(StaticFilters.FILTER_CARD_CREATURE, Zone.HAND) + ).withInterveningIf(condition).addHint(hint)); // Choose a Background this.addAbility(ChooseABackgroundAbility.getInstance()); diff --git a/Mage.Sets/src/mage/cards/v/VictimOfNight.java b/Mage.Sets/src/mage/cards/v/VictimOfNight.java index bf58f605bfa..c127f2d6d90 100644 --- a/Mage.Sets/src/mage/cards/v/VictimOfNight.java +++ b/Mage.Sets/src/mage/cards/v/VictimOfNight.java @@ -9,6 +9,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -30,7 +31,7 @@ public final class VictimOfNight extends CardImpl { // Destroy target non-Vampire, non-Werewolf, non-Zombie creature. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/v/VigeanGraftmage.java b/Mage.Sets/src/mage/cards/v/VigeanGraftmage.java index eeb6f55a359..5001b126f5a 100644 --- a/Mage.Sets/src/mage/cards/v/VigeanGraftmage.java +++ b/Mage.Sets/src/mage/cards/v/VigeanGraftmage.java @@ -14,8 +14,11 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_CREATURE_P1P1; + /** * * @author JotaPeRL @@ -35,7 +38,7 @@ public final class VigeanGraftmage extends CardImpl { // {1}{U}: Untap target creature with a +1/+1 counter on it. Ability ability = new SimpleActivatedAbility(new UntapTargetEffect(), new ManaCostsImpl<>("{1}{U}")); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_P1P1)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_P1P1)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/VileManifestation.java b/Mage.Sets/src/mage/cards/v/VileManifestation.java index e00a5399975..ffae65fb4eb 100644 --- a/Mage.Sets/src/mage/cards/v/VileManifestation.java +++ b/Mage.Sets/src/mage/cards/v/VileManifestation.java @@ -16,7 +16,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.AbilityPredicate; @@ -46,7 +45,7 @@ public final class VileManifestation extends CardImpl { // Vile Manifestation gets +1/+0 for each card with cycling in your graveyard. DynamicValue amount = new CardsInControllerGraveyardCount(filter); Effect effect = new BoostSourceEffect(amount, StaticValue.get(0), Duration.WhileOnBattlefield); - effect.setText("Vile Manifestation gets +1/+0 for each card with cycling in your graveyard."); + effect.setText("{this} gets +1/+0 for each card with cycling in your graveyard."); Ability ability = new SimpleStaticAbility(effect); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/v/VillainousWealth.java b/Mage.Sets/src/mage/cards/v/VillainousWealth.java index 15bbf0c8b63..a9da3ab3fb2 100644 --- a/Mage.Sets/src/mage/cards/v/VillainousWealth.java +++ b/Mage.Sets/src/mage/cards/v/VillainousWealth.java @@ -71,6 +71,8 @@ class VillainousWealthEffect extends OneShotEffect { } Cards cards = new CardsImpl(opponent.getLibrary().getTopCards(game, xValue)); opponent.moveCards(cards, Zone.EXILED, source, game); + game.processAction(); + cards.retainZone(Zone.EXILED, game); FilterCard filter = new FilterCard(); filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, CardUtil.getSourceCostsTag(game, source, "X", 0) + 1)); CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, filter); diff --git a/Mage.Sets/src/mage/cards/v/VineshaperProdigy.java b/Mage.Sets/src/mage/cards/v/VineshaperProdigy.java index fcefd11822c..d7964f27e9b 100644 --- a/Mage.Sets/src/mage/cards/v/VineshaperProdigy.java +++ b/Mage.Sets/src/mage/cards/v/VineshaperProdigy.java @@ -3,7 +3,6 @@ package mage.cards.v; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; @@ -30,14 +29,9 @@ public final class VineshaperProdigy extends CardImpl { this.addAbility(new KickerAbility("{1}{U}")); // When Vineshaper Prodigy enters the battlefield, if it was kicked, look at the top three cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility( - new LookLibraryAndPickControllerEffect( - 3, 1, PutCards.HAND, PutCards.BOTTOM_ANY - )), KickedCondition.ONCE, "When {this} enters, " + - "if it was kicked, look at the top three cards of your library. " + - "Put one of them into your hand and the rest on the bottom of your library in any order." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + 3, 1, PutCards.HAND, PutCards.BOTTOM_ANY + )).withInterveningIf(KickedCondition.ONCE)); } private VineshaperProdigy(final VineshaperProdigy card) { diff --git a/Mage.Sets/src/mage/cards/v/VioletPall.java b/Mage.Sets/src/mage/cards/v/VioletPall.java index 66184057da8..d7ba6b14b41 100644 --- a/Mage.Sets/src/mage/cards/v/VioletPall.java +++ b/Mage.Sets/src/mage/cards/v/VioletPall.java @@ -9,8 +9,11 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; import mage.game.permanent.token.FaerieRogueToken; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author Loki @@ -22,7 +25,7 @@ public final class VioletPall extends CardImpl { this.subtype.add(SubType.FAERIE); this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK)); this.getSpellAbility().addEffect(new CreateTokenEffect(new FaerieRogueToken(), 1)); } diff --git a/Mage.Sets/src/mage/cards/v/ViridianScout.java b/Mage.Sets/src/mage/cards/v/ViridianScout.java index e42e1048ae3..3cbf66865ef 100644 --- a/Mage.Sets/src/mage/cards/v/ViridianScout.java +++ b/Mage.Sets/src/mage/cards/v/ViridianScout.java @@ -16,6 +16,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class ViridianScout extends CardImpl { // {2}{G}, Sacrifice Viridian Scout: Viridian Scout deals 2 damage to target creature with flying. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2, "it"), new ManaCostsImpl<>("{2}{G}")); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/VirtueOfCourage.java b/Mage.Sets/src/mage/cards/v/VirtueOfCourage.java index 8abfd96bd49..716290617bb 100644 --- a/Mage.Sets/src/mage/cards/v/VirtueOfCourage.java +++ b/Mage.Sets/src/mage/cards/v/VirtueOfCourage.java @@ -1,16 +1,14 @@ package mage.cards.v; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SourceDealsNoncombatDamageToOpponentTriggeredAbility; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; import mage.cards.AdventureCard; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; -import mage.game.events.GameEvent; +import mage.constants.SetTargetPointer; import mage.target.common.TargetAnyTarget; import java.util.UUID; @@ -24,7 +22,10 @@ public final class VirtueOfCourage extends AdventureCard { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, new CardType[]{CardType.INSTANT}, "{3}{R}{R}", "Embereth Blaze", "{1}{R}"); // Whenever a source you control deals noncombat damage to an opponent, you may exile that many cards from the top of your library. You may play those cards this turn. - this.addAbility(new VirtueOfCourageTriggeredAbility()); + this.addAbility(new SourceDealsNoncombatDamageToOpponentTriggeredAbility( + new ExileTopXMayPlayUntilEffect(SavedDamageValue.MANY, false, Duration.EndOfTurn) + .setText("you may exile that many cards from the top of your library. You may play those cards this turn.") + , true, SetTargetPointer.NONE)); // Embereth Blaze // Embereth Blaze deals 2 damage to any target. @@ -43,44 +44,3 @@ public final class VirtueOfCourage extends AdventureCard { return new VirtueOfCourage(this); } } - -class VirtueOfCourageTriggeredAbility extends TriggeredAbilityImpl { - - VirtueOfCourageTriggeredAbility() { - super(Zone.BATTLEFIELD, null, true); - } - - private VirtueOfCourageTriggeredAbility(final VirtueOfCourageTriggeredAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - DamagedPlayerEvent dEvent = (DamagedPlayerEvent) event; - if (dEvent.isCombatDamage() - || !game.getOpponents(getControllerId()).contains(event.getTargetId()) - || !game.getControllerId(event.getSourceId()).equals(getControllerId())) { - return false; - } - this.getEffects().clear(); - this.addEffect(new ExileTopXMayPlayUntilEffect(event.getAmount(), Duration.EndOfTurn)); - return true; - } - - @Override - public VirtueOfCourageTriggeredAbility copy() { - return new VirtueOfCourageTriggeredAbility(this); - } - - @Override - public String getRule() { - return "whenever a source you control deals noncombat damage to an opponent, " - + "you may exile that many cards from the top of your library. " - + "You may play those cards this turn."; - } -} diff --git a/Mage.Sets/src/mage/cards/v/VirulentSilencer.java b/Mage.Sets/src/mage/cards/v/VirulentSilencer.java new file mode 100644 index 00000000000..2186ec9df40 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VirulentSilencer.java @@ -0,0 +1,53 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; +import mage.abilities.effects.common.counter.AddPoisonCounterTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.TokenPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VirulentSilencer extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent("a nontoken artifact creature you control"); + + static { + filter.add(TokenPredicate.FALSE); + filter.add(CardType.ARTIFACT.getPredicate()); + filter.add(CardType.CREATURE.getPredicate()); + } + + public VirulentSilencer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); + + this.subtype.add(SubType.ROBOT); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Whenever a nontoken artifact creature you control deals combat damage to a player, that player gets two poison counters. + this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility( + new AddPoisonCounterTargetEffect(2), filter, + false, SetTargetPointer.PLAYER, true + )); + } + + private VirulentSilencer(final VirulentSilencer card) { + super(card); + } + + @Override + public VirulentSilencer copy() { + return new VirulentSilencer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VisceridDrone.java b/Mage.Sets/src/mage/cards/v/VisceridDrone.java index ea684250281..c3f01ae7ef8 100644 --- a/Mage.Sets/src/mage/cards/v/VisceridDrone.java +++ b/Mage.Sets/src/mage/cards/v/VisceridDrone.java @@ -18,6 +18,7 @@ import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; @@ -54,7 +55,7 @@ public final class VisceridDrone extends CardImpl { new SacrificeTargetCost(filter2), "Sacrifice a creature and a Swamp" )); - ability.addTarget(new TargetCreaturePermanent(filter1)); + ability.addTarget(new TargetPermanent(filter1)); this.addAbility(ability); // {tap}, Sacrifice a creature and a snow Swamp: Destroy target creature. It can't be regenerated. diff --git a/Mage.Sets/src/mage/cards/v/VisionOfTheUnspeakable.java b/Mage.Sets/src/mage/cards/v/VisionOfTheUnspeakable.java index a93dc245b06..99a77ff529a 100644 --- a/Mage.Sets/src/mage/cards/v/VisionOfTheUnspeakable.java +++ b/Mage.Sets/src/mage/cards/v/VisionOfTheUnspeakable.java @@ -36,8 +36,8 @@ public final class VisionOfTheUnspeakable extends CardImpl { // Vision of the Unspeakable gets +1/+1 for each card in your hand. this.addAbility(new SimpleStaticAbility(new BoostSourceEffect( - CardsInControllerHandCount.ANY, - CardsInControllerHandCount.ANY, + CardsInControllerHandCount.ANY_SINGULAR, + CardsInControllerHandCount.ANY_SINGULAR, Duration.WhileOnBattlefield ))); } diff --git a/Mage.Sets/src/mage/cards/v/VitalSplicer.java b/Mage.Sets/src/mage/cards/v/VitalSplicer.java index 4b180c3a4e1..e0c186fd8b5 100644 --- a/Mage.Sets/src/mage/cards/v/VitalSplicer.java +++ b/Mage.Sets/src/mage/cards/v/VitalSplicer.java @@ -15,6 +15,7 @@ import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.game.permanent.token.PhyrexianGolemToken; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -46,7 +47,7 @@ public final class VitalSplicer extends CardImpl { // {1}: Regenerate target Golem you control. Ability ability = new SimpleActivatedAbility(new RegenerateTargetEffect(), new ManaCostsImpl<>("{1}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/VituGhaziInspector.java b/Mage.Sets/src/mage/cards/v/VituGhaziInspector.java index c0aeffc1fc0..72e65d3c3aa 100644 --- a/Mage.Sets/src/mage/cards/v/VituGhaziInspector.java +++ b/Mage.Sets/src/mage/cards/v/VituGhaziInspector.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CollectedEvidenceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.CollectEvidenceAbility; @@ -38,12 +37,10 @@ public final class VituGhaziInspector extends CardImpl { this.addAbility(ReachAbility.getInstance()); // When Vitu-Ghazi Inspector enters the battlefield, if evidence was collected, put a +1/+1 counter on target creature and you gain 2 life. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())), - CollectedEvidenceCondition.instance, "When {this} enters, if evidence was " + - "collected, put a +1/+1 counter on target creature and you gain 2 life." - ); - ability.addEffect(new GainLifeEffect(2)); + Ability ability = new EntersBattlefieldTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()) + ).withInterveningIf(CollectedEvidenceCondition.instance); + ability.addEffect(new GainLifeEffect(2).concatBy("and")); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/VivienOfTheArkbow.java b/Mage.Sets/src/mage/cards/v/VivienOfTheArkbow.java index f53d67f5017..5ca61378564 100644 --- a/Mage.Sets/src/mage/cards/v/VivienOfTheArkbow.java +++ b/Mage.Sets/src/mage/cards/v/VivienOfTheArkbow.java @@ -15,11 +15,14 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.counters.CounterType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * @author TheElk801 */ @@ -40,7 +43,7 @@ public final class VivienOfTheArkbow extends CardImpl { // −3: Target creature you control deals damage equal to its power to target creature you don't control. ability = new LoyaltyAbility(new DamageWithPowerFromOneToAnotherTargetEffect(), -3); ability.addTarget(new TargetControlledCreaturePermanent()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + ability.addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.addAbility(ability); // −9: Creatures you control get +4/+4 and gain trample until end of turn. diff --git a/Mage.Sets/src/mage/cards/v/ViviensJaguar.java b/Mage.Sets/src/mage/cards/v/ViviensJaguar.java index 8bd8ae4f22f..737c29c7b3b 100644 --- a/Mage.Sets/src/mage/cards/v/ViviensJaguar.java +++ b/Mage.Sets/src/mage/cards/v/ViviensJaguar.java @@ -1,30 +1,29 @@ package mage.cards.v; -import java.util.UUID; import mage.MageInt; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; -import mage.constants.SubType; import mage.abilities.keyword.ReachAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterControlledPlaneswalkerPermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class ViviensJaguar extends CardImpl { - private static final FilterControlledPlaneswalkerPermanent filter - = new FilterControlledPlaneswalkerPermanent( - SubType.VIVIEN, - "a Vivien planeswalker" - ); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPlaneswalkerPermanent(SubType.VIVIEN, "you control a Vivien planeswalker") + ); public ViviensJaguar(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); @@ -38,13 +37,9 @@ public final class ViviensJaguar extends CardImpl { this.addAbility(ReachAbility.getInstance()); // {2}{G}: Return Vivien's Jaguar from your graveyard to your hand. Activate this ability only if you control a Vivien planeswalker. - this.addAbility(new ConditionalActivatedAbility( - Zone.GRAVEYARD, - new ReturnSourceFromGraveyardToHandEffect(), - new ManaCostsImpl<>("{2}{G}"), - new PermanentsOnTheBattlefieldCondition(filter), - "{2}{G}: Return {this} from your graveyard to your hand. " - + "Activate only if you control a Vivien planeswalker." + this.addAbility(new ActivateIfConditionActivatedAbility( + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), + new ManaCostsImpl<>("{2}{G}"), condition )); } diff --git a/Mage.Sets/src/mage/cards/v/VivisectionEvangelist.java b/Mage.Sets/src/mage/cards/v/VivisectionEvangelist.java index 205be888562..e40b39f78d3 100644 --- a/Mage.Sets/src/mage/cards/v/VivisectionEvangelist.java +++ b/Mage.Sets/src/mage/cards/v/VivisectionEvangelist.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CorruptedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; @@ -43,12 +42,8 @@ public final class VivisectionEvangelist extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // Corrupted -- When Vivisection Evangelist enters the battlefield, if an opponent has three or more poison counters, destroy target creature or planeswalker an opponent controls. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), false), - CorruptedCondition.instance, "When {this} enters, " + - "if an opponent has three or more poison counters, " + - "destroy target creature or planeswalker an opponent controls." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()) + .withInterveningIf(CorruptedCondition.instance); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability.setAbilityWord(AbilityWord.CORRUPTED).addHint(CorruptedCondition.getHint())); } diff --git a/Mage.Sets/src/mage/cards/v/VoidGrafter.java b/Mage.Sets/src/mage/cards/v/VoidGrafter.java index c1113515201..0c06de0094a 100644 --- a/Mage.Sets/src/mage/cards/v/VoidGrafter.java +++ b/Mage.Sets/src/mage/cards/v/VoidGrafter.java @@ -1,6 +1,5 @@ package mage.cards.v; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -11,19 +10,20 @@ import mage.abilities.keyword.HexproofAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author fireshoes */ public final class VoidGrafter extends CardImpl { public VoidGrafter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{U}"); this.subtype.add(SubType.ELDRAZI); this.subtype.add(SubType.DRONE); this.power = new MageInt(2); @@ -36,8 +36,10 @@ public final class VoidGrafter extends CardImpl { this.addAbility(FlashAbility.getInstance()); // When Void Grafter enters the battlefield, another target creature you control gain hexproof until end of turn. - Ability ability = new EntersBattlefieldTriggeredAbility(new GainAbilityTargetEffect(HexproofAbility.getInstance(), Duration.EndOfTurn), false); - ability.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + Ability ability = new EntersBattlefieldTriggeredAbility(new GainAbilityTargetEffect( + HexproofAbility.getInstance(), Duration.EndOfTurn + ), false); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/VoidforgedTitan.java b/Mage.Sets/src/mage/cards/v/VoidforgedTitan.java new file mode 100644 index 00000000000..1183f7c3a64 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VoidforgedTitan.java @@ -0,0 +1,47 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.condition.common.VoidCondition; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.watchers.common.VoidWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VoidforgedTitan extends CardImpl { + + public VoidforgedTitan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}{B}"); + + this.subtype.add(SubType.ROBOT); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // Void -- At the beginning of your end step, if a nonland permanent left the battlefield this turn or a spell was warped this turn, you draw a card and lose 1 life. + Ability ability = new BeginningOfEndStepTriggeredAbility( + new DrawCardSourceControllerEffect(1, true) + ).withInterveningIf(VoidCondition.instance); + ability.addEffect(new LoseLifeSourceControllerEffect(1).setText("and lose 1 life")); + this.addAbility(ability.setAbilityWord(AbilityWord.VOID).addHint(VoidCondition.getHint()), new VoidWatcher()); + } + + private VoidforgedTitan(final VoidforgedTitan card) { + super(card); + } + + @Override + public VoidforgedTitan copy() { + return new VoidforgedTitan(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VoldarenAmbusher.java b/Mage.Sets/src/mage/cards/v/VoldarenAmbusher.java index 6a19c5a54ca..c0bdb0337d8 100644 --- a/Mage.Sets/src/mage/cards/v/VoldarenAmbusher.java +++ b/Mage.Sets/src/mage/cards/v/VoldarenAmbusher.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.OpponentsLostLifeCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.DamageTargetEffect; @@ -25,8 +24,9 @@ import java.util.UUID; */ public final class VoldarenAmbusher extends CardImpl { - private static final DynamicValue xValue - = new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.VAMPIRE)); + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount( + new FilterControlledPermanent(SubType.VAMPIRE, "Vampires you control"), null + ); private static final Hint hint = new ValueHint("Vampires you control", xValue); public VoldarenAmbusher(UUID ownerId, CardSetInfo setInfo) { @@ -38,12 +38,8 @@ public final class VoldarenAmbusher extends CardImpl { this.toughness = new MageInt(2); // When Voldaren Ambusher enters the battlefield, if an opponent lost life this turn, it deals X damage to up to one target creature or planeswalker, where X is the number of Vampires you control. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(xValue)), - OpponentsLostLifeCondition.instance, "When {this} enters, " + - "if an opponent lost life this turn, it deals X damage to up to one target " + - "creature or planeswalker, where X is the number of Vampires you control." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(xValue, "it")) + .withInterveningIf(OpponentsLostLifeCondition.instance); ability.addTarget(new TargetCreatureOrPlaneswalker(0, 1)); this.addAbility(ability.addHint(OpponentsLostLifeHint.instance).addHint(hint)); } diff --git a/Mage.Sets/src/mage/cards/v/VoltaicConstruct.java b/Mage.Sets/src/mage/cards/v/VoltaicConstruct.java index 7d08ba87a9c..6d00a6e0d0c 100644 --- a/Mage.Sets/src/mage/cards/v/VoltaicConstruct.java +++ b/Mage.Sets/src/mage/cards/v/VoltaicConstruct.java @@ -14,6 +14,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -34,7 +35,7 @@ public final class VoltaicConstruct extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); Ability ability = new SimpleActivatedAbility(new UntapTargetEffect(), new GenericManaCost(2)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/VonaButcherOfMagan.java b/Mage.Sets/src/mage/cards/v/VonaButcherOfMagan.java index d4ceca02044..024c9a31cf2 100644 --- a/Mage.Sets/src/mage/cards/v/VonaButcherOfMagan.java +++ b/Mage.Sets/src/mage/cards/v/VonaButcherOfMagan.java @@ -7,7 +7,6 @@ import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.costs.common.PayLifeCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.common.DestroyTargetEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.abilities.keyword.LifelinkAbility; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; @@ -15,7 +14,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.target.common.TargetNonlandPermanent; import java.util.UUID; @@ -41,10 +39,11 @@ public final class VonaButcherOfMagan extends CardImpl { this.addAbility(LifelinkAbility.getInstance()); // {T}, Pay 7 life: Destroy target nonland permanent. Activate this ability only during your turn. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new TapSourceCost(), MyTurnCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DestroyTargetEffect(), new TapSourceCost(), MyTurnCondition.instance + ); ability.addCost(new PayLifeCost(7)); ability.addTarget(new TargetNonlandPermanent()); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/VoodooDoll.java b/Mage.Sets/src/mage/cards/v/VoodooDoll.java index 1117c54da00..0698119433b 100644 --- a/Mage.Sets/src/mage/cards/v/VoodooDoll.java +++ b/Mage.Sets/src/mage/cards/v/VoodooDoll.java @@ -1,20 +1,20 @@ package mage.cards.v; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.SourceTappedCondition; import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CountersSourceCount; import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DestroySourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -30,6 +30,8 @@ import java.util.UUID; */ public final class VoodooDoll extends CardImpl { + private static final DynamicValue xValue = new CountersSourceCount(CounterType.PIN); + public VoodooDoll(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}"); @@ -39,18 +41,18 @@ public final class VoodooDoll extends CardImpl { )); // At the beginning of your end step, if Voodoo Doll is untapped, destroy Voodoo Doll and it deals damage to you equal to the number of pin counters on it. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - new DestroySourceEffect() - ), SourceTappedCondition.UNTAPPED, "At the beginning of your end step, " + - "if {this} is untapped, destroy {this} and it deals damage to you equal to the number of pin counters on it." - ); - ability.addEffect(new DamageControllerEffect(new CountersSourceCount(CounterType.PIN))); + Ability ability = new BeginningOfEndStepTriggeredAbility(new DestroySourceEffect()) + .withInterveningIf(SourceTappedCondition.UNTAPPED); + ability.addEffect(new DamageControllerEffect(xValue) + .setText("and it deals damage to you equal to the number of pin counters on it")); this.addAbility(ability); // {X}{X}, {T}: Voodoo Doll deals damage equal to the number of pin counters on it to any target. X is the number of pin counters on Voodoo Doll. ability = new SimpleActivatedAbility( - new DamageTargetEffect(new CountersSourceCount(CounterType.PIN)), new ManaCostsImpl<>("{X}{X}") + new DamageTargetEffect(new CountersSourceCount(CounterType.PIN)) + .setText("{this} deals damage equal to the number of pin counters on it " + + "to any target. X is the number of pin counters on {this}"), + new ManaCostsImpl<>("{X}{X}") ); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetAnyTarget()); diff --git a/Mage.Sets/src/mage/cards/v/VraskasConquistador.java b/Mage.Sets/src/mage/cards/v/VraskasConquistador.java index 14e811ae99d..6aad67376dc 100644 --- a/Mage.Sets/src/mage/cards/v/VraskasConquistador.java +++ b/Mage.Sets/src/mage/cards/v/VraskasConquistador.java @@ -1,19 +1,19 @@ package mage.cards.v; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.AttacksOrBlocksTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterControlledPlaneswalkerPermanent; import mage.target.common.TargetOpponent; import java.util.UUID; @@ -23,12 +23,10 @@ import java.util.UUID; */ public final class VraskasConquistador extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent(); - - static { - filter.add(CardType.PLANESWALKER.getPredicate()); - filter.add(SubType.VRASKA.getPredicate()); - } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPlaneswalkerPermanent(SubType.VRASKA, "you control a Vraska planeswalker") + ); + private static final Hint hint = new ConditionHint(condition); public VraskasConquistador(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); @@ -39,14 +37,12 @@ public final class VraskasConquistador extends CardImpl { this.toughness = new MageInt(1); // Whenever Vraska's Conquistador attacks or blocks, if you control a Vraska planeswalker, target opponent loses 2 life and you gain 2 life. - Condition condition = new PermanentsOnTheBattlefieldCondition(filter); - TriggeredAbility ability = new AttacksOrBlocksTriggeredAbility(new LoseLifeTargetEffect(2), false); + Ability ability = new AttacksOrBlocksTriggeredAbility( + new LoseLifeTargetEffect(2), false + ).withInterveningIf(condition); ability.addEffect(new GainLifeEffect(2).concatBy("and")); ability.addTarget(new TargetOpponent()); - ability.addHint(new ConditionHint(condition, "You control a Vraska planeswalker")); - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - ability, condition, - "Whenever {this} attacks or blocks, if you control a Vraska planeswalker, target opponent loses 2 life and you gain 2 life.")); + this.addAbility(ability.addHint(hint)); } private VraskasConquistador(final VraskasConquistador card) { diff --git a/Mage.Sets/src/mage/cards/w/Wakedancer.java b/Mage.Sets/src/mage/cards/w/Wakedancer.java index bb48fa7c66e..ae1bdd2a4d3 100644 --- a/Mage.Sets/src/mage/cards/w/Wakedancer.java +++ b/Mage.Sets/src/mage/cards/w/Wakedancer.java @@ -1,30 +1,26 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.MorbidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.common.MorbidHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; import mage.game.permanent.token.ZombieToken; +import java.util.UUID; + /** - * * @author Loki */ public final class Wakedancer extends CardImpl { - private static final String staticText = "Morbid — When {this} enters, if a creature died this turn, create a 2/2 black Zombie creature token."; - public Wakedancer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SHAMAN); @@ -33,8 +29,8 @@ public final class Wakedancer extends CardImpl { this.toughness = new MageInt(2); // Morbid — When Wakedancer enters the battlefield, if a creature died this turn, create a 2/2 black Zombie creature token. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ZombieToken())); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, MorbidCondition.instance, staticText).addHint(MorbidHint.instance)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ZombieToken())) + .withInterveningIf(MorbidCondition.instance).setAbilityWord(AbilityWord.MORBID).addHint(MorbidHint.instance)); } private Wakedancer(final Wakedancer card) { diff --git a/Mage.Sets/src/mage/cards/w/WakeningSunsAvatar.java b/Mage.Sets/src/mage/cards/w/WakeningSunsAvatar.java index 8df0e3b6166..4cd44f0e1a4 100644 --- a/Mage.Sets/src/mage/cards/w/WakeningSunsAvatar.java +++ b/Mage.Sets/src/mage/cards/w/WakeningSunsAvatar.java @@ -1,11 +1,8 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromHandSourcePermanentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DestroyAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -15,8 +12,9 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.watchers.common.CastFromHandWatcher; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class WakeningSunsAvatar extends CardImpl { @@ -36,11 +34,8 @@ public final class WakeningSunsAvatar extends CardImpl { this.toughness = new MageInt(7); // When Wakening Sun's Avatar enters the battlefield, if you cast it from you hand, destroy all non-Dinosaur creatures. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(filter), false), - CastFromHandSourcePermanentCondition.instance, - "When {this} enters, if you cast it from your hand, destroy all non-Dinosaur creatures."), - new CastFromHandWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(filter)) + .withInterveningIf(CastFromHandSourcePermanentCondition.instance), new CastFromHandWatcher()); } private WakeningSunsAvatar(final WakeningSunsAvatar card) { diff --git a/Mage.Sets/src/mage/cards/w/WalkThePlank.java b/Mage.Sets/src/mage/cards/w/WalkThePlank.java index b719d45c10b..6e5a0183e8b 100644 --- a/Mage.Sets/src/mage/cards/w/WalkThePlank.java +++ b/Mage.Sets/src/mage/cards/w/WalkThePlank.java @@ -9,6 +9,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class WalkThePlank extends CardImpl { // Destroy target non-Merfolk creature. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private WalkThePlank(final WalkThePlank card) { diff --git a/Mage.Sets/src/mage/cards/w/WalkerOfSecretWays.java b/Mage.Sets/src/mage/cards/w/WalkerOfSecretWays.java index 64e85962af2..91108e59548 100644 --- a/Mage.Sets/src/mage/cards/w/WalkerOfSecretWays.java +++ b/Mage.Sets/src/mage/cards/w/WalkerOfSecretWays.java @@ -6,20 +6,16 @@ import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.LookAtTargetPlayerHandEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.abilities.keyword.NinjutsuAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; -import mage.game.Game; -import mage.players.Player; -import mage.target.common.TargetControlledPermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -28,7 +24,7 @@ import java.util.UUID; */ public final class WalkerOfSecretWays extends CardImpl { - private static final FilterControlledPermanent filterCreature = new FilterControlledPermanent(SubType.NINJA, "Ninja you control"); + private static final FilterPermanent filterCreature = new FilterControlledPermanent(SubType.NINJA, "Ninja you control"); public WalkerOfSecretWays(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); @@ -42,15 +38,16 @@ public final class WalkerOfSecretWays extends CardImpl { this.addAbility(new NinjutsuAbility("{1}{U}")); // Whenever Walker of Secret Ways deals combat damage to a player, look at that player's hand. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new WalkerOfSecretWaysEffect(), false, true)); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new LookAtTargetPlayerHandEffect(), false, true + )); // {1}{U}: Return target Ninja you control to its owner's hand. Activate this ability only during your turn. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl<>("{1}{U}"), MyTurnCondition.instance); - ability.addTarget(new TargetControlledPermanent(filterCreature)); - ability.addHint(MyTurnHint.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new ReturnToHandTargetEffect(), new ManaCostsImpl<>("{1}{U}"), MyTurnCondition.instance + ); + ability.addTarget(new TargetPermanent(filterCreature)); this.addAbility(ability); - - } private WalkerOfSecretWays(final WalkerOfSecretWays card) { @@ -62,30 +59,3 @@ public final class WalkerOfSecretWays extends CardImpl { return new WalkerOfSecretWays(this); } } - -class WalkerOfSecretWaysEffect extends OneShotEffect { - WalkerOfSecretWaysEffect() { - super(Outcome.Detriment); - staticText = "look at that player's hand"; - } - - private WalkerOfSecretWaysEffect(final WalkerOfSecretWaysEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - if (player != null && controller != null) { - controller.lookAtCards("Walker of Secret Ways", player.getHand(), game); - } - return true; - } - - @Override - public WalkerOfSecretWaysEffect copy() { - return new WalkerOfSecretWaysEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/w/WallOfForgottenPharaohs.java b/Mage.Sets/src/mage/cards/w/WallOfForgottenPharaohs.java index 08b743db0d8..5d71e6859be 100644 --- a/Mage.Sets/src/mage/cards/w/WallOfForgottenPharaohs.java +++ b/Mage.Sets/src/mage/cards/w/WallOfForgottenPharaohs.java @@ -11,7 +11,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.target.common.TargetPlayerOrPlaneswalker; import java.util.UUID; @@ -33,8 +32,7 @@ public final class WallOfForgottenPharaohs extends CardImpl { // {T}: Wall of Forgotten Pharaohs deals 1 damage to target player. Activate this ability only if you control a Desert or there is a Desert card in your graveyard. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new DamageTargetEffect(1), - new TapSourceCost(), DesertControlledOrGraveyardCondition.instance + new DamageTargetEffect(1), new TapSourceCost(), DesertControlledOrGraveyardCondition.instance ); ability.addTarget(new TargetPlayerOrPlaneswalker()); this.addAbility(ability.addHint(DesertControlledOrGraveyardCondition.getHint())); diff --git a/Mage.Sets/src/mage/cards/w/WallOfResistance.java b/Mage.Sets/src/mage/cards/w/WallOfResistance.java index 80d0a58cc10..0e06738f15d 100644 --- a/Mage.Sets/src/mage/cards/w/WallOfResistance.java +++ b/Mage.Sets/src/mage/cards/w/WallOfResistance.java @@ -2,12 +2,11 @@ package mage.cards.w; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.DefenderAbility; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -38,13 +37,10 @@ public final class WallOfResistance extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // At the beginning of each end step, if Wall of Resistance was dealt damage this turn, put a +0/+1 counter on it. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - TargetController.ANY, new AddCountersSourceEffect(CounterType.P0P1.createInstance()), - false - ), WallOfResistanceCondition.instance, "At the beginning of each end step, " + - "if {this} was dealt damage this turn, put a +0/+1 counter on it." - )); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.ANY, new AddCountersSourceEffect(CounterType.P0P1.createInstance()), + false, WallOfResistanceCondition.instance + ).withRuleTextReplacement(true)); } private WallOfResistance(final WallOfResistance card) { @@ -65,4 +61,9 @@ enum WallOfResistanceCondition implements Condition { Permanent permanent = source.getSourcePermanentOrLKI(game); return permanent != null && !permanent.getDealtDamageByThisTurn().isEmpty(); } + + @Override + public String toString() { + return "{this} was dealt damage this turn"; + } } diff --git a/Mage.Sets/src/mage/cards/w/WallOfVipers.java b/Mage.Sets/src/mage/cards/w/WallOfVipers.java index 014401a77af..6df17ae8c11 100644 --- a/Mage.Sets/src/mage/cards/w/WallOfVipers.java +++ b/Mage.Sets/src/mage/cards/w/WallOfVipers.java @@ -20,6 +20,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.combat.CombatGroup; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -41,7 +42,7 @@ public final class WallOfVipers extends CardImpl { // {3}: Destroy Wall of Vipers and target creature it's blocking. Any player may activate this ability. SimpleActivatedAbility ability = new SimpleActivatedAbility(new DestroySourceEffect(), new ManaCostsImpl<>("{3}")); ability.addEffect(new DestroyTargetEffect(" and target creature it's blocking")); - ability.addTarget(new TargetCreaturePermanent(new WallOfVipersFilter())); + ability.addTarget(new TargetPermanent(new WallOfVipersFilter())); ability.setMayActivate(TargetController.ANY); ability.addEffect(new InfoEffect("Any player may activate this ability")); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/w/Wallop.java b/Mage.Sets/src/mage/cards/w/Wallop.java index 065a1add221..84b1732ae45 100644 --- a/Mage.Sets/src/mage/cards/w/Wallop.java +++ b/Mage.Sets/src/mage/cards/w/Wallop.java @@ -12,6 +12,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -33,7 +34,7 @@ public final class Wallop extends CardImpl { // Destroy target blue or black creature with flying. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private Wallop(final Wallop card) { diff --git a/Mage.Sets/src/mage/cards/w/WandOfIth.java b/Mage.Sets/src/mage/cards/w/WandOfIth.java index bba33d38036..f35e89212d5 100644 --- a/Mage.Sets/src/mage/cards/w/WandOfIth.java +++ b/Mage.Sets/src/mage/cards/w/WandOfIth.java @@ -7,11 +7,9 @@ import mage.abilities.costs.common.PayLifeCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -28,10 +26,11 @@ public final class WandOfIth extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // {3}, {T}: Target player reveals a card at random from their hand. If it's a land card, that player discards it unless they pay 1 life. If it isn't a land card, the player discards it unless they pay life equal to its converted mana cost. Activate this ability only during your turn. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new WandOfIthEffect(), new GenericManaCost(3), MyTurnCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new WandOfIthEffect(), new GenericManaCost(3), MyTurnCondition.instance + ); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetPlayer()); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WanderingArchaic.java b/Mage.Sets/src/mage/cards/w/WanderingArchaic.java index e31b06ad2f8..2640d7e4012 100644 --- a/Mage.Sets/src/mage/cards/w/WanderingArchaic.java +++ b/Mage.Sets/src/mage/cards/w/WanderingArchaic.java @@ -4,6 +4,7 @@ import mage.abilities.Ability; import mage.abilities.common.SpellCastOpponentTriggeredAbility; import mage.abilities.costs.Cost; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GainLifeAllEffect; import mage.cards.*; import mage.constants.*; import mage.filter.FilterCard; @@ -49,6 +50,7 @@ public final class WanderingArchaic extends ModalDoubleFacedCard { // Sorcery // Each player looks at the top five cards of their library, reveals a land card and/or an instant or sorcery card from among them, then puts the cards they revealed this way into their hand and the rest on the bottom of their library in a random order. Each player gains 3 life. this.getRightHalfCard().getSpellAbility().addEffect(new ExploreTheVastlandsEffect()); + this.getRightHalfCard().getSpellAbility().addEffect(new GainLifeAllEffect(3)); } private WanderingArchaic(final WanderingArchaic card) { @@ -105,7 +107,7 @@ class ExploreTheVastlandsEffect extends OneShotEffect { staticText = "each player looks at the top five cards of their library " + "and may reveal a land card and/or an instant or sorcery card from among them. " + "Each player puts the cards they revealed this way into their hand and the rest " + - "on the bottom of their library in a random order. Each player gains 3 life"; + "on the bottom of their library in a random order."; } private ExploreTheVastlandsEffect(final ExploreTheVastlandsEffect effect) { @@ -133,12 +135,6 @@ class ExploreTheVastlandsEffect extends OneShotEffect { player.moveCards(toHand, Zone.HAND, source, game); player.putCardsOnBottomOfLibrary(cards, game, source, false); } - for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - player.gainLife(3, game, source); - } - } return true; } } diff --git a/Mage.Sets/src/mage/cards/w/WanderingChampion.java b/Mage.Sets/src/mage/cards/w/WanderingChampion.java index 907f3801848..6022841ed54 100644 --- a/Mage.Sets/src/mage/cards/w/WanderingChampion.java +++ b/Mage.Sets/src/mage/cards/w/WanderingChampion.java @@ -2,17 +2,17 @@ package mage.cards.w; import mage.MageInt; import mage.ObjectColor; -import mage.abilities.TriggeredAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.DiscardCardCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; @@ -24,12 +24,17 @@ import java.util.UUID; */ public final class WanderingChampion extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("green permanent"); + private static final FilterPermanent filter = new FilterControlledPermanent("you control a blue or red permanent"); static { - filter.add(Predicates.or(new ColorPredicate(ObjectColor.BLUE), new ColorPredicate(ObjectColor.RED))); + filter.add(Predicates.or( + new ColorPredicate(ObjectColor.BLUE), + new ColorPredicate(ObjectColor.RED) + )); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + public WanderingChampion(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.subtype.add(SubType.HUMAN); @@ -38,10 +43,9 @@ public final class WanderingChampion extends CardImpl { this.toughness = new MageInt(1); // Whenever Wandering Champion deals combat damage to a player, if you control a blue or red permanent, you may discard a card. If you do, draw a card. - TriggeredAbility ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new DiscardCardCost()), false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new PermanentsOnTheBattlefieldCondition(filter), - "Whenever {this} deals combat damage to a player, if you control a blue or red permanent, you may discard a card. If you do, draw a card.")); - + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new DiscardCardCost()) + ).withInterveningIf(condition)); } private WanderingChampion(final WanderingChampion card) { diff --git a/Mage.Sets/src/mage/cards/w/WanderingMage.java b/Mage.Sets/src/mage/cards/w/WanderingMage.java index af772345bdd..662a8afe48d 100644 --- a/Mage.Sets/src/mage/cards/w/WanderingMage.java +++ b/Mage.Sets/src/mage/cards/w/WanderingMage.java @@ -16,6 +16,7 @@ import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetPlayerOrPlaneswalker; @@ -53,7 +54,7 @@ public final class WanderingMage extends CardImpl { // {U}: Prevent the next 1 damage that would be dealt to target Cleric or Wizard creature this turn. ability = new SimpleActivatedAbility( new PreventDamageToTargetEffect(Duration.EndOfTurn, 1), new ManaCostsImpl<>("{U}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // {B}, Put a -1/-1 counter on a creature you control: Prevent the next 2 damage that would be dealt to target player this turn. diff --git a/Mage.Sets/src/mage/cards/w/WanderingTroubadour.java b/Mage.Sets/src/mage/cards/w/WanderingTroubadour.java index 528a864a7d8..39410e4e51a 100644 --- a/Mage.Sets/src/mage/cards/w/WanderingTroubadour.java +++ b/Mage.Sets/src/mage/cards/w/WanderingTroubadour.java @@ -1,20 +1,19 @@ package mage.cards.w; -import java.util.UUID; import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.common.LandfallCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect; import mage.abilities.hint.common.CurrentDungeonHint; -import mage.constants.SubType; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.watchers.common.LandfallWatcher; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class WanderingTroubadour extends CardImpl { @@ -28,11 +27,8 @@ public final class WanderingTroubadour extends CardImpl { this.toughness = new MageInt(2); // At the beginning of your end step, if you had a land enter the battlefield under your control this turn, venture into the dungeon. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility(new VentureIntoTheDungeonEffect()), - LandfallCondition.instance, - "At the beginning of your end step, if you had a land enter the battlefield under your control this turn, venture into the dungeon." - ).addHint(CurrentDungeonHint.instance), new LandfallWatcher()); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new VentureIntoTheDungeonEffect()) + .withInterveningIf(LandfallCondition.instance).addHint(CurrentDungeonHint.instance), new LandfallWatcher()); } private WanderingTroubadour(final WanderingTroubadour card) { diff --git a/Mage.Sets/src/mage/cards/w/WarBarge.java b/Mage.Sets/src/mage/cards/w/WarBarge.java index 007cfdb25e2..943ceb4a26c 100644 --- a/Mage.Sets/src/mage/cards/w/WarBarge.java +++ b/Mage.Sets/src/mage/cards/w/WarBarge.java @@ -1,7 +1,6 @@ package mage.cards.w; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -22,6 +21,8 @@ import mage.game.events.ZoneChangeEvent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** * * @author L_J @@ -83,6 +84,6 @@ class WarBargeDelayedTriggeredAbility extends DelayedTriggeredAbility { @Override public String getRule() { - return "When War Barge leaves the battlefield this turn, destroy that creature. A creature destroyed this way can't be regenerated."; + return "When {this} leaves the battlefield this turn, destroy that creature. A creature destroyed this way can't be regenerated."; } } diff --git a/Mage.Sets/src/mage/cards/w/WarTorchGoblin.java b/Mage.Sets/src/mage/cards/w/WarTorchGoblin.java index f2563f0242d..bf2af820e32 100644 --- a/Mage.Sets/src/mage/cards/w/WarTorchGoblin.java +++ b/Mage.Sets/src/mage/cards/w/WarTorchGoblin.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.ColoredManaSymbol; import mage.constants.Zone; import mage.filter.common.FilterBlockingCreature; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -34,7 +35,7 @@ public final class WarTorchGoblin extends CardImpl { // {R}, Sacrifice War-Torch Goblin: War-Torch Goblin deals 2 damage to target blocking creature. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2, "it"), new ColoredManaCost(ColoredManaSymbol.R)); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(new FilterBlockingCreature())); + ability.addTarget(new TargetPermanent(new FilterBlockingCreature())); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WarchanterSkald.java b/Mage.Sets/src/mage/cards/w/WarchanterSkald.java index 9ab4d48ddd6..7308b19695c 100644 --- a/Mage.Sets/src/mage/cards/w/WarchanterSkald.java +++ b/Mage.Sets/src/mage/cards/w/WarchanterSkald.java @@ -1,20 +1,18 @@ package mage.cards.w; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.BecomesTappedSourceTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.condition.OrCondition; +import mage.abilities.condition.common.EnchantedSourceCondition; +import mage.abilities.condition.common.EquippedSourceCondition; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.Game; -import mage.game.permanent.Permanent; import mage.game.permanent.token.DwarfBerserkerToken; -import java.util.Objects; import java.util.UUID; /** @@ -22,6 +20,12 @@ import java.util.UUID; */ public final class WarchanterSkald extends CardImpl { + private static final Condition condition = new OrCondition( + "it's enchanted or equipped", + new EnchantedSourceCondition(), + EquippedSourceCondition.instance + ); + public WarchanterSkald(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); @@ -31,11 +35,7 @@ public final class WarchanterSkald extends CardImpl { this.toughness = new MageInt(3); // Whenever Warchanter Skald becomes tapped, if it's enchanted or equipped, create a 2/1 red Dwarf Berserker creature token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BecomesTappedSourceTriggeredAbility(new CreateTokenEffect(new DwarfBerserkerToken())), - WarchanterSkaldCondition.instance, "Whenever {this} becomes tapped, " + - "if it's enchanted or equipped, create a 2/1 red Dwarf Berserker creature token." - )); + this.addAbility(new BecomesTappedSourceTriggeredAbility(new CreateTokenEffect(new DwarfBerserkerToken())).withInterveningIf(condition)); } private WarchanterSkald(final WarchanterSkald card) { @@ -47,18 +47,3 @@ public final class WarchanterSkald extends CardImpl { return new WarchanterSkald(this); } } - -enum WarchanterSkaldCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = source.getSourcePermanentOrLKI(game); - return permanent != null && permanent - .getAttachments() - .stream() - .map(game::getPermanent) - .filter(Objects::nonNull) - .anyMatch(p -> p.hasSubtype(SubType.AURA, game) || p.hasSubtype(SubType.EQUIPMENT, game)); - } -} diff --git a/Mage.Sets/src/mage/cards/w/WardenOfTheWall.java b/Mage.Sets/src/mage/cards/w/WardenOfTheWall.java index 80682bee3e0..63549eed066 100644 --- a/Mage.Sets/src/mage/cards/w/WardenOfTheWall.java +++ b/Mage.Sets/src/mage/cards/w/WardenOfTheWall.java @@ -14,7 +14,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.game.permanent.token.TokenImpl; import java.util.UUID; @@ -37,7 +36,7 @@ public final class WardenOfTheWall extends CardImpl { this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( new BecomesCreatureSourceEffect(new GargoyleToken(), CardType.ARTIFACT, Duration.WhileOnBattlefield), NotMyTurnCondition.instance, - "During turns other than yours, Warden of the Wall is a 2/3 Gargoyle artifact creature with flying")) + "During turns other than yours, {this} is a 2/3 Gargoyle artifact creature with flying")) .addHint(NotMyTurnHint.instance)); } diff --git a/Mage.Sets/src/mage/cards/w/WarkiteMarauder.java b/Mage.Sets/src/mage/cards/w/WarkiteMarauder.java index 6ce6825f1dd..de5f5ca75f6 100644 --- a/Mage.Sets/src/mage/cards/w/WarkiteMarauder.java +++ b/Mage.Sets/src/mage/cards/w/WarkiteMarauder.java @@ -16,6 +16,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -45,7 +46,7 @@ public final class WarkiteMarauder extends CardImpl { .setText("target creature defending player controls loses all abilities"), false); ability.addEffect(new SetBasePowerToughnessTargetEffect(0, 1, Duration.EndOfTurn) .setText("and has base power and toughness 0/1 until end of turn")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WarpingWail.java b/Mage.Sets/src/mage/cards/w/WarpingWail.java index 88f62df69ea..32d44adf4fe 100644 --- a/Mage.Sets/src/mage/cards/w/WarpingWail.java +++ b/Mage.Sets/src/mage/cards/w/WarpingWail.java @@ -16,6 +16,7 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.PowerPredicate; import mage.filter.predicate.mageobject.ToughnessPredicate; import mage.game.permanent.token.EldraziScionToken; +import mage.target.TargetPermanent; import mage.target.TargetSpell; import mage.target.common.TargetCreaturePermanent; @@ -42,7 +43,7 @@ public final class WarpingWail extends CardImpl { Effect effect = new ExileTargetEffect(); effect.setText("Exile target creature with power or toughness 1 or less."); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterCreature)); + this.getSpellAbility().addTarget(new TargetPermanent(filterCreature)); // Counter target sorcery spell. Mode mode = new Mode(new CounterTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/w/WarrenPilferers.java b/Mage.Sets/src/mage/cards/w/WarrenPilferers.java index f5bab468061..743ae3ff9bf 100644 --- a/Mage.Sets/src/mage/cards/w/WarrenPilferers.java +++ b/Mage.Sets/src/mage/cards/w/WarrenPilferers.java @@ -1,6 +1,5 @@ package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -16,6 +15,8 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** * * @author LevelX2 @@ -50,7 +51,7 @@ class WarrenPilferersReturnEffect extends OneShotEffect { WarrenPilferersReturnEffect() { super(Outcome.ReturnToHand); - staticText = "return target creature card from your graveyard to your hand. If that card is a Goblin card, Warren Pilferers gains haste until end of turn"; + staticText = "return target creature card from your graveyard to your hand. If that card is a Goblin card, {this} gains haste until end of turn"; } private WarrenPilferersReturnEffect(final WarrenPilferersReturnEffect effect) { diff --git a/Mage.Sets/src/mage/cards/w/WastescapeBattlemage.java b/Mage.Sets/src/mage/cards/w/WastescapeBattlemage.java index 1567b3ee686..75d5e4812b0 100644 --- a/Mage.Sets/src/mage/cards/w/WastescapeBattlemage.java +++ b/Mage.Sets/src/mage/cards/w/WastescapeBattlemage.java @@ -1,9 +1,9 @@ package mage.cards.w; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.KickedCostCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CastSourceTriggeredAbility; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; @@ -14,10 +14,9 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; import mage.filter.FilterPermanent; -import mage.filter.StaticFilters; import mage.filter.common.FilterArtifactOrEnchantmentPermanent; import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; import java.util.UUID; @@ -33,6 +32,9 @@ public final class WastescapeBattlemage extends CardImpl { filter.add(TargetController.OPPONENT.getControllerPredicate()); } + private static final Condition condition = new KickedCostCondition("{G}"); + private static final Condition condition2 = new KickedCostCondition("{1}{U}"); + public WastescapeBattlemage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{C}"); @@ -47,16 +49,14 @@ public final class WastescapeBattlemage extends CardImpl { this.addAbility(kickerAbility); // When you cast this spell, if it was kicked with its {G} kicker, exile target artifact or enchantment an opponent controls. - TriggeredAbility ability = new CastSourceTriggeredAbility(new ExileTargetEffect()); + Ability ability = new CastSourceTriggeredAbility(new ExileTargetEffect()).withInterveningIf(condition); ability.addTarget(new TargetPermanent(filter)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new KickedCostCondition("{G}"), - "When you cast this spell, if it was kicked with its {G} kicker, exile target artifact or enchantment an opponent controls.")); + this.addAbility(ability); // When you cast this spell, if it was kicked with its {1}{U} kicker, return target creature an opponent controls to its owner's hand. - TriggeredAbility ability2 = new CastSourceTriggeredAbility(new ReturnToHandTargetEffect()); - ability2.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability2, new KickedCostCondition("{1}{U}"), - "When you cast this spell, if it was kicked with its {1}{U} kicker, return target creature an opponent controls to its owner's hand.")); + ability = new CastSourceTriggeredAbility(new ReturnToHandTargetEffect()).withInterveningIf(condition2); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); } private WastescapeBattlemage(final WastescapeBattlemage card) { diff --git a/Mage.Sets/src/mage/cards/w/WatcherOfTheSpheres.java b/Mage.Sets/src/mage/cards/w/WatcherOfTheSpheres.java index 636e7aa952d..2789d8db7d7 100644 --- a/Mage.Sets/src/mage/cards/w/WatcherOfTheSpheres.java +++ b/Mage.Sets/src/mage/cards/w/WatcherOfTheSpheres.java @@ -1,7 +1,7 @@ package mage.cards.w; import mage.MageInt; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; @@ -11,7 +11,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreatureCard; @@ -26,8 +25,8 @@ import java.util.UUID; public final class WatcherOfTheSpheres extends CardImpl { - private static final FilterCreatureCard filter = new FilterCreatureCard("Creature spells with flying"); - private static final FilterPermanent filter1 = new FilterControlledCreaturePermanent("another creature with flying"); + private static final FilterCreatureCard filter = new FilterCreatureCard("creature spells with flying"); + private static final FilterPermanent filter1 = new FilterControlledCreaturePermanent("another creature you control with flying"); static { filter.add(new AbilityPredicate(FlyingAbility.class)); @@ -50,7 +49,9 @@ public final class WatcherOfTheSpheres extends CardImpl { this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 1))); // Whenever another creature with flying you control enters, Watcher of the Spheres gets +1/+1 until end of turn. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 1, Duration.EndOfTurn), filter1, false)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new BoostSourceEffect(1, 1, Duration.EndOfTurn), filter1 + )); } private WatcherOfTheSpheres(final WatcherOfTheSpheres card) { diff --git a/Mage.Sets/src/mage/cards/w/WaterspoutElemental.java b/Mage.Sets/src/mage/cards/w/WaterspoutElemental.java index 38716a7d57f..26a3e86450a 100644 --- a/Mage.Sets/src/mage/cards/w/WaterspoutElemental.java +++ b/Mage.Sets/src/mage/cards/w/WaterspoutElemental.java @@ -1,11 +1,9 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnToHandFromBattlefieldAllEffect; import mage.abilities.effects.common.turn.SkipNextTurnSourceEffect; import mage.abilities.keyword.FlyingAbility; @@ -17,8 +15,9 @@ import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import java.util.UUID; + /** - * * @author LoneFox */ public final class WaterspoutElemental extends CardImpl { @@ -30,20 +29,21 @@ public final class WaterspoutElemental extends CardImpl { } public WaterspoutElemental(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(3); this.toughness = new MageInt(4); // Kicker {U} this.addAbility(new KickerAbility("{U}")); + // Flying this.addAbility(FlyingAbility.getInstance()); + // When Waterspout Elemental enters the battlefield, if it was kicked, return all other creatures to their owners' hands and you skip your next turn. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandFromBattlefieldAllEffect(filter)); - ability.addEffect(new SkipNextTurnSourceEffect()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.ONCE, - "When {this} enters, if it was kicked, return all other creatures to their owners' hands and you skip your next turn.")); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandFromBattlefieldAllEffect(filter)).withInterveningIf(KickedCondition.ONCE); + ability.addEffect(new SkipNextTurnSourceEffect().concatBy("and")); + this.addAbility(ability); } private WaterspoutElemental(final WaterspoutElemental card) { diff --git a/Mage.Sets/src/mage/cards/w/WaterspoutWarden.java b/Mage.Sets/src/mage/cards/w/WaterspoutWarden.java index b464c08d1dd..c81394c0420 100644 --- a/Mage.Sets/src/mage/cards/w/WaterspoutWarden.java +++ b/Mage.Sets/src/mage/cards/w/WaterspoutWarden.java @@ -5,7 +5,6 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -35,12 +34,9 @@ public final class WaterspoutWarden extends CardImpl { this.toughness = new MageInt(2); // Whenever Waterspout Warden attacks, if another creature entered the battlefield under your control this turn, Waterspout Warden gains flying until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new GainAbilitySourceEffect( - FlyingAbility.getInstance(), Duration.EndOfTurn - )), WaterspoutWardenCondition.instance, "Whenever {this} attacks, if another creature entered " + - "the battlefield under your control this turn, {this} gains flying until end of turn." - ), new WaterspoutWardenWatcher()); + this.addAbility(new AttacksTriggeredAbility(new GainAbilitySourceEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + )).withInterveningIf(WaterspoutWardenCondition.instance), new WaterspoutWardenWatcher()); } private WaterspoutWarden(final WaterspoutWarden card) { @@ -60,6 +56,11 @@ enum WaterspoutWardenCondition implements Condition { public boolean apply(Game game, Ability source) { return WaterspoutWardenWatcher.checkPermanent(game, source); } + + @Override + public String toString() { + return "another creature entered the battlefield under your control this turn"; + } } class WaterspoutWardenWatcher extends Watcher { diff --git a/Mage.Sets/src/mage/cards/w/WatertrapWeaver.java b/Mage.Sets/src/mage/cards/w/WatertrapWeaver.java index 69117a4272b..baebf8288df 100644 --- a/Mage.Sets/src/mage/cards/w/WatertrapWeaver.java +++ b/Mage.Sets/src/mage/cards/w/WatertrapWeaver.java @@ -11,8 +11,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author TheElk801 @@ -30,7 +33,7 @@ public final class WatertrapWeaver extends CardImpl { // When Watertrap Weaver enters the battlefield, tap target creature an opponent controls. That creature doesn't untap during its controller's next untap step. EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("that creature")); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WaveOfRats.java b/Mage.Sets/src/mage/cards/w/WaveOfRats.java index 76977bd1c24..d45d161bfcd 100644 --- a/Mage.Sets/src/mage/cards/w/WaveOfRats.java +++ b/Mage.Sets/src/mage/cards/w/WaveOfRats.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlSourceEffect; import mage.abilities.keyword.BlitzAbility; import mage.abilities.keyword.TrampleAbility; @@ -34,12 +33,8 @@ public class WaveOfRats extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // When Wave of Rats dies, if it dealt combat damage to a player this turn, return it to the battlefield under its owner’s control. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new DiesSourceTriggeredAbility(new ReturnToBattlefieldUnderOwnerControlSourceEffect()), - WaveOfRatsDealtDamageToPlayerCondition.instance, - "When Wave of Rats dies, if it dealt combat damage to a player this turn, return it to the battlefield under its owner's control."), - new DamageDoneWatcher() - ); + this.addAbility(new DiesSourceTriggeredAbility(new ReturnToBattlefieldUnderOwnerControlSourceEffect().setText("return it to the battlefield under its owner's control")) + .withInterveningIf(WaveOfRatsDealtDamageToPlayerCondition.instance), new DamageDoneWatcher()); // Blitz {4}{B} (If you cast this spell for its blitz cost, it gains haste and “When this creature dies, draw a card.” Sacrifice it at the beginning of the next end step.) this.addAbility(new BlitzAbility(this, "{4}{B}")); @@ -70,4 +65,9 @@ enum WaveOfRatsDealtDamageToPlayerCondition implements Condition { } return watcher.damagedAPlayer(waveOfRats.getId(), waveOfRats.getZoneChangeCounter(game), game); } + + @Override + public String toString() { + return "it dealt combat damage to a player this turn"; + } } diff --git a/Mage.Sets/src/mage/cards/w/WavecrashTriton.java b/Mage.Sets/src/mage/cards/w/WavecrashTriton.java index 902c3bfb60d..20dde47ffdf 100644 --- a/Mage.Sets/src/mage/cards/w/WavecrashTriton.java +++ b/Mage.Sets/src/mage/cards/w/WavecrashTriton.java @@ -12,8 +12,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -30,7 +33,7 @@ public final class WavecrashTriton extends CardImpl { // Heroic - Whenever you cast a spell that targets Wavecrash Triton, tap target creature an opponent controls. That creature doesn't untap during its controller's next untap step. Ability ability = new HeroicAbility(new TapTargetEffect()); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("That creature")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WaylayingPirates.java b/Mage.Sets/src/mage/cards/w/WaylayingPirates.java index 5f8a6d9c807..52106b352f2 100644 --- a/Mage.Sets/src/mage/cards/w/WaylayingPirates.java +++ b/Mage.Sets/src/mage/cards/w/WaylayingPirates.java @@ -5,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.hint.ConditionHint; @@ -16,6 +15,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledArtifactPermanent; import mage.target.TargetPermanent; import java.util.UUID; @@ -25,8 +25,10 @@ import java.util.UUID; */ public final class WaylayingPirates extends CardImpl { - private static final Condition condition = new PermanentsOnTheBattlefieldCondition(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT); - private static final Hint hint = new ConditionHint(condition, "You control an artifact"); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledArtifactPermanent("you control an artifact") + ); + private static final Hint hint = new ConditionHint(condition); public WaylayingPirates(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); @@ -37,12 +39,8 @@ public final class WaylayingPirates extends CardImpl { this.toughness = new MageInt(3); // When Waylaying Pirates enters the battlefield, if you control an artifact, tap target artifact or creature an opponent controls and put a stun counter on it. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new TapTargetEffect()), - condition, "When {this} enters, if you control an artifact, " + - "tap target artifact or creature an opponent controls and put a stun counter on it." - ); - ability.addEffect(new AddCountersTargetEffect(CounterType.STUN.createInstance())); + Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()).withInterveningIf(condition); + ability.addEffect(new AddCountersTargetEffect(CounterType.STUN.createInstance()).setText("and put a stun counter on it")); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_ARTIFACT_OR_CREATURE)); this.addAbility(ability.addHint(hint)); } diff --git a/Mage.Sets/src/mage/cards/w/WaytaTrainerProdigy.java b/Mage.Sets/src/mage/cards/w/WaytaTrainerProdigy.java index c7e7e20a89e..cf67c8fc49c 100644 --- a/Mage.Sets/src/mage/cards/w/WaytaTrainerProdigy.java +++ b/Mage.Sets/src/mage/cards/w/WaytaTrainerProdigy.java @@ -24,12 +24,15 @@ import mage.game.events.GameEvent; import mage.game.events.NumberOfTriggersEvent; import mage.game.permanent.Permanent; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import mage.util.CardUtil; import java.util.UUID; +import static mage.filter.StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2; + /** * @@ -60,7 +63,7 @@ public final class WaytaTrainerProdigy extends CardImpl { ability.addTarget(controlledTarget); Target secondTarget = - new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2).setTargetTag(2); + new TargetPermanent(FILTER_ANOTHER_CREATURE_TARGET_2).setTargetTag(2); ability.addTarget(secondTarget); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/w/WeatheredWayfarer.java b/Mage.Sets/src/mage/cards/w/WeatheredWayfarer.java index 5805aa12f84..571a4af7fd4 100644 --- a/Mage.Sets/src/mage/cards/w/WeatheredWayfarer.java +++ b/Mage.Sets/src/mage/cards/w/WeatheredWayfarer.java @@ -1,10 +1,9 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.OpponentControlsMoreCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -13,19 +12,20 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.filter.common.FilterLandCard; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class WeatheredWayfarer extends CardImpl { + private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS); + public WeatheredWayfarer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.NOMAD); this.subtype.add(SubType.CLERIC); @@ -35,10 +35,10 @@ public final class WeatheredWayfarer extends CardImpl { // {W}, {tap}: Search your library for a land card, reveal it, and put it into your hand. Then shuffle your library. Activate this ability only if an opponent controls more lands than you. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new SearchLibraryPutInHandEffect(new TargetCardInLibrary(new FilterLandCard()), true), - new ManaCostsImpl<>("{W}"), - new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS)); + new SearchLibraryPutInHandEffect( + new TargetCardInLibrary(StaticFilters.FILTER_CARD_LAND_A), true + ), new ManaCostsImpl<>("{W}"), condition + ); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WeatherseedTotem.java b/Mage.Sets/src/mage/cards/w/WeatherseedTotem.java index 7a7a03a5c22..e7cdf48fcd2 100644 --- a/Mage.Sets/src/mage/cards/w/WeatherseedTotem.java +++ b/Mage.Sets/src/mage/cards/w/WeatherseedTotem.java @@ -5,7 +5,6 @@ import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.keyword.TrampleAbility; @@ -43,11 +42,9 @@ public final class WeatherseedTotem extends CardImpl { ), new ManaCostsImpl<>("{2}{G}{G}{G}"))); // When Weatherseed Totem is put into a graveyard from the battlefield, if it was a creature, return this card to its owner's hand. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new ReturnSourceFromGraveyardToHandEffect()), - WeatherseedTotemCondition.instance, "When {this} is put into a graveyard from the battlefield, " - + "if it was a creature, return this card to its owner's hand" - )); + this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility( + new ReturnSourceFromGraveyardToHandEffect().setText("return this card to its owner's hand") + ).withInterveningIf(WeatherseedTotemCondition.instance)); } private WeatherseedTotem(final WeatherseedTotem card) { @@ -69,4 +66,9 @@ enum WeatherseedTotemCondition implements Condition { .getEffectValueFromAbility(source, "permanentWasCreature", Boolean.class) .orElse(false); } + + @Override + public String toString() { + return "it was a creature"; + } } diff --git a/Mage.Sets/src/mage/cards/w/WeaverOfLies.java b/Mage.Sets/src/mage/cards/w/WeaverOfLies.java index e52eacded1b..23d2e47dd66 100644 --- a/Mage.Sets/src/mage/cards/w/WeaverOfLies.java +++ b/Mage.Sets/src/mage/cards/w/WeaverOfLies.java @@ -1,11 +1,8 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.TurnedFaceUpSourceTriggeredAbility; -import mage.constants.SubType; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureAllEffect; @@ -14,6 +11,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicates; @@ -22,10 +20,11 @@ import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class WeaverOfLies extends CardImpl { @@ -49,7 +48,7 @@ public final class WeaverOfLies extends CardImpl { // When Weaver of Lies is turned face up, turn any number of target creatures with a morph ability other than Weaver of Lies face down. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new WeaverOfLiesEffect(), false, false); - ability.addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, false)); + ability.addTarget(new TargetPermanent(0, Integer.MAX_VALUE, filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WeaverOfLightning.java b/Mage.Sets/src/mage/cards/w/WeaverOfLightning.java index 6e9c4cc3ccd..fe7c2d46ba6 100644 --- a/Mage.Sets/src/mage/cards/w/WeaverOfLightning.java +++ b/Mage.Sets/src/mage/cards/w/WeaverOfLightning.java @@ -11,8 +11,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -30,7 +33,7 @@ public final class WeaverOfLightning extends CardImpl { this.addAbility(ReachAbility.getInstance()); // Whenever you cast an instant or sorcery spell, Weaver of Lightning deals 1 damage to target creature an opponent controls. Ability ability = new SpellCastControllerTriggeredAbility(new DamageTargetEffect(1), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WebstrikeElite.java b/Mage.Sets/src/mage/cards/w/WebstrikeElite.java index bc5997fa765..3a2995fc469 100644 --- a/Mage.Sets/src/mage/cards/w/WebstrikeElite.java +++ b/Mage.Sets/src/mage/cards/w/WebstrikeElite.java @@ -1,9 +1,10 @@ package mage.cards.w; import mage.MageInt; -import mage.abilities.common.ZoneChangeTriggeredAbility; +import mage.abilities.Ability; +import mage.abilities.common.CycleTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.dynamicvalue.common.EffectKeyValue; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.CyclingAbility; import mage.abilities.keyword.ReachAbility; @@ -12,14 +13,10 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterArtifactOrEnchantmentPermanent; -import mage.filter.predicate.mageobject.ManaValuePredicate; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.stack.StackObject; import mage.target.TargetPermanent; +import mage.target.targetadjustment.ManaValueTargetAdjuster; import java.util.UUID; @@ -28,6 +25,8 @@ import java.util.UUID; */ public final class WebstrikeElite extends CardImpl { + private static final FilterPermanent filter = new FilterArtifactOrEnchantmentPermanent("artifact or enchantment with mana value X"); + public WebstrikeElite(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{G}"); @@ -43,7 +42,10 @@ public final class WebstrikeElite extends CardImpl { this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{X}{G}{G}"))); // When you cycle this card, destroy up to one target artifact or enchantment with mana value X. - this.addAbility(new WebstrikeEliteTriggeredAbility()); + Ability ability = new CycleTriggeredAbility(new DestroyTargetEffect()); + ability.addTarget(new TargetPermanent(0, 1, filter)); + ability.setTargetAdjuster(new ManaValueTargetAdjuster(new EffectKeyValue("cycleXValue"), ComparisonType.EQUAL_TO)); + this.addAbility(ability); } private WebstrikeElite(final WebstrikeElite card) { @@ -55,47 +57,3 @@ public final class WebstrikeElite extends CardImpl { return new WebstrikeElite(this); } } - -class WebstrikeEliteTriggeredAbility extends ZoneChangeTriggeredAbility { - - WebstrikeEliteTriggeredAbility() { - super(Zone.ALL, new DestroyTargetEffect(), "", false); - } - - private WebstrikeEliteTriggeredAbility(final WebstrikeEliteTriggeredAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY; - } - - @Override - public WebstrikeEliteTriggeredAbility copy() { - return new WebstrikeEliteTriggeredAbility(this); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (!event.getSourceId().equals(this.getSourceId())) { - return false; - } - StackObject object = game.getStack().getStackObject(event.getSourceId()); - if (object == null || !(object.getStackAbility() instanceof CyclingAbility)) { - return false; - } - FilterPermanent filter = new FilterArtifactOrEnchantmentPermanent("artifact or enchantment with mana value X"); - filter.add(new ManaValuePredicate( - ComparisonType.EQUAL_TO, GetXValue.instance.calculate(game, object.getStackAbility(), null) - )); - this.getTargets().clear(); - this.addTarget(new TargetPermanent(0, 1, filter)); - return true; - } - - @Override - public String getRule() { - return "When you cycle this card, destroy up to one target artifact or enchantment with mana value X."; - } -} diff --git a/Mage.Sets/src/mage/cards/w/WebweaverChangeling.java b/Mage.Sets/src/mage/cards/w/WebweaverChangeling.java index e0fd5c9f4da..393acd48945 100644 --- a/Mage.Sets/src/mage/cards/w/WebweaverChangeling.java +++ b/Mage.Sets/src/mage/cards/w/WebweaverChangeling.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.keyword.ChangelingAbility; import mage.abilities.keyword.ReachAbility; @@ -22,7 +21,7 @@ import java.util.UUID; public final class WebweaverChangeling extends CardImpl { private static final Condition condition - = new CardsInControllerGraveyardCondition(3, StaticFilters.FILTER_CARD_CREATURE); + = new CardsInControllerGraveyardCondition(3, StaticFilters.FILTER_CARD_CREATURES); public WebweaverChangeling(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); @@ -38,11 +37,7 @@ public final class WebweaverChangeling extends CardImpl { this.addAbility(ReachAbility.getInstance()); // When Webweaver Changeling enters the battlefield, if there are three or more creature cards in your graveyard, you gain 5 life. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new GainLifeEffect(5)), condition, - "When {this} enters, if there are three or more " + - "creature cards in your graveyard, you gain 5 life." - )); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(5)).withInterveningIf(condition)); } private WebweaverChangeling(final WebweaverChangeling card) { diff --git a/Mage.Sets/src/mage/cards/w/WeddingRing.java b/Mage.Sets/src/mage/cards/w/WeddingRing.java index 08402474cca..e62812386e1 100644 --- a/Mage.Sets/src/mage/cards/w/WeddingRing.java +++ b/Mage.Sets/src/mage/cards/w/WeddingRing.java @@ -4,7 +4,6 @@ import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -35,11 +34,8 @@ public final class WeddingRing extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{W}{W}"); // When Wedding Ring enters the battlefield, if it was cast, target opponent creates a token that's a copy of it. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new WeddingRingEffect()), - CastFromEverywhereSourceCondition.instance, "When {this} enters, " + - "if it was cast, target opponent creates a token that's a copy of it." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new WeddingRingEffect()) + .withInterveningIf(CastFromEverywhereSourceCondition.instance); ability.addTarget(new TargetOpponent()); this.addAbility(ability); @@ -64,6 +60,7 @@ class WeddingRingEffect extends OneShotEffect { WeddingRingEffect() { super(Outcome.Benefit); + staticText = "target opponent creates a token that's a copy of it"; } private WeddingRingEffect(final WeddingRingEffect effect) { diff --git a/Mage.Sets/src/mage/cards/w/WeedPrunerPoplar.java b/Mage.Sets/src/mage/cards/w/WeedPrunerPoplar.java index 7e337a7ab21..afcad218844 100644 --- a/Mage.Sets/src/mage/cards/w/WeedPrunerPoplar.java +++ b/Mage.Sets/src/mage/cards/w/WeedPrunerPoplar.java @@ -13,6 +13,7 @@ import mage.constants.SubType; import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -36,7 +37,7 @@ public final class WeedPrunerPoplar extends CardImpl { // At the beginning of your upkeep, target creature other than Weed-Pruner Poplar gets -1/-1 until end of turn. Ability ability = new BeginningOfUpkeepTriggeredAbility(new BoostTargetEffect(-1, -1, Duration.EndOfTurn)); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WeightOfConscience.java b/Mage.Sets/src/mage/cards/w/WeightOfConscience.java index b7218100ba9..063c4dec9a6 100644 --- a/Mage.Sets/src/mage/cards/w/WeightOfConscience.java +++ b/Mage.Sets/src/mage/cards/w/WeightOfConscience.java @@ -14,6 +14,7 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicate; import mage.filter.predicate.mageobject.SharesCreatureTypePredicate; import mage.filter.predicate.permanent.TappedPredicate; @@ -21,7 +22,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.*; @@ -59,9 +60,9 @@ public final class WeightOfConscience extends CardImpl { } } -class WeightOfConscienceTarget extends TargetControlledCreaturePermanent { +class WeightOfConscienceTarget extends TargetControlledPermanent { - private static final FilterControlledCreaturePermanent filterUntapped = new FilterControlledCreaturePermanent("untapped creatures you control that share a creature type"); + private static final FilterControlledPermanent filterUntapped = new FilterControlledCreaturePermanent("untapped creatures you control that share a creature type"); static { filterUntapped.add(TappedPredicate.UNTAPPED); diff --git a/Mage.Sets/src/mage/cards/w/WelcomingVampire.java b/Mage.Sets/src/mage/cards/w/WelcomingVampire.java index 1b3ffd7a0c2..507783572ea 100644 --- a/Mage.Sets/src/mage/cards/w/WelcomingVampire.java +++ b/Mage.Sets/src/mage/cards/w/WelcomingVampire.java @@ -21,7 +21,7 @@ import java.util.UUID; */ public final class WelcomingVampire extends CardImpl { - private static final FilterPermanent filter = new FilterControlledCreaturePermanent("one or more other creatures with power 2 or less"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("one or more other creatures you control with power 2 or less"); static { filter.add(AnotherPredicate.instance); diff --git a/Mage.Sets/src/mage/cards/w/WellOfDiscovery.java b/Mage.Sets/src/mage/cards/w/WellOfDiscovery.java index 82c184366f2..68d0d68d94b 100644 --- a/Mage.Sets/src/mage/cards/w/WellOfDiscovery.java +++ b/Mage.Sets/src/mage/cards/w/WellOfDiscovery.java @@ -1,38 +1,37 @@ - package mage.cards.w; -import java.util.UUID; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledLandPermanent; import mage.filter.predicate.permanent.TappedPredicate; +import java.util.UUID; + /** - * * @author LoneFox */ public final class WellOfDiscovery extends CardImpl { - private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); + private static final FilterPermanent filter = new FilterControlledLandPermanent("you control no untapped lands"); static { filter.add(TappedPredicate.UNTAPPED); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0); + public WellOfDiscovery(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{6}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}"); // At the beginning of your end step, if you control no untapped lands, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new BeginningOfEndStepTriggeredAbility( - new DrawCardSourceControllerEffect(1)), - new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)), - "At the beginning of your end step, if you control no untapped lands, draw a card.")); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new DrawCardSourceControllerEffect(1)).withInterveningIf(condition)); } private WellOfDiscovery(final WellOfDiscovery card) { diff --git a/Mage.Sets/src/mage/cards/w/WellOfLife.java b/Mage.Sets/src/mage/cards/w/WellOfLife.java index 003a4b691d7..6d6a2043da0 100644 --- a/Mage.Sets/src/mage/cards/w/WellOfLife.java +++ b/Mage.Sets/src/mage/cards/w/WellOfLife.java @@ -1,37 +1,38 @@ package mage.cards.w; -import java.util.UUID; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledLandPermanent; import mage.filter.predicate.permanent.TappedPredicate; +import java.util.UUID; + /** - * * @author LoneFox */ public final class WellOfLife extends CardImpl { - private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); + private static final FilterPermanent filter = new FilterControlledLandPermanent("you control no untapped lands"); static { filter.add(TappedPredicate.UNTAPPED); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0); + public WellOfLife(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // At the beginning of your end step, if you control no untapped lands, you gain 2 life. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new BeginningOfEndStepTriggeredAbility( - new GainLifeEffect(2)), new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)), - "At the beginning of your end step, if you control no untapped lands, you gain 2 life.")); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new GainLifeEffect(2)).withInterveningIf(condition)); } private WellOfLife(final WellOfLife card) { diff --git a/Mage.Sets/src/mage/cards/w/WellgabberApothecary.java b/Mage.Sets/src/mage/cards/w/WellgabberApothecary.java index 82797bc6f4d..19bd97e88bd 100644 --- a/Mage.Sets/src/mage/cards/w/WellgabberApothecary.java +++ b/Mage.Sets/src/mage/cards/w/WellgabberApothecary.java @@ -15,6 +15,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class WellgabberApothecary extends CardImpl { // {1}{W} : Prevent all damage that would be dealt to target tapped Merfolk or Kithkin creatuer this turn SimpleActivatedAbility ability = new SimpleActivatedAbility(new PreventDamageToTargetEffect(Duration.EndOfTurn, Integer.MAX_VALUE), new ManaCostsImpl<>("{1}{W}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WerefoxBodyguard.java b/Mage.Sets/src/mage/cards/w/WerefoxBodyguard.java index b41bed744a6..d1d4ca8a24d 100644 --- a/Mage.Sets/src/mage/cards/w/WerefoxBodyguard.java +++ b/Mage.Sets/src/mage/cards/w/WerefoxBodyguard.java @@ -16,7 +16,7 @@ import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -46,7 +46,7 @@ public final class WerefoxBodyguard extends CardImpl { // When Werefox Bodyguard enters the battlefield, exile up to one other target non-Fox creature until Werefox Bodyguard leaves the battlefield. Ability ability = new EntersBattlefieldTriggeredAbility(new ExileUntilSourceLeavesEffect()); - ability.addTarget(new TargetCreaturePermanent(0, 1, filter, false)); + ability.addTarget(new TargetPermanent(0, 1, filter)); this.addAbility(ability); // {1}{W}, Sacrifice Werefox Bodyguard: You gain 2 life. diff --git a/Mage.Sets/src/mage/cards/w/WesternPaladin.java b/Mage.Sets/src/mage/cards/w/WesternPaladin.java index 1e814734d85..92a3545c42a 100644 --- a/Mage.Sets/src/mage/cards/w/WesternPaladin.java +++ b/Mage.Sets/src/mage/cards/w/WesternPaladin.java @@ -18,6 +18,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -41,7 +42,7 @@ public final class WesternPaladin extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(3); Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{B}{B}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WhaleboneGlider.java b/Mage.Sets/src/mage/cards/w/WhaleboneGlider.java index c5fec2a8dc1..03492dbb68b 100644 --- a/Mage.Sets/src/mage/cards/w/WhaleboneGlider.java +++ b/Mage.Sets/src/mage/cards/w/WhaleboneGlider.java @@ -15,6 +15,7 @@ import mage.constants.ComparisonType; import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -41,7 +42,7 @@ public final class WhaleboneGlider extends CardImpl { new GenericManaCost(2) ); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WhereAncientsTread.java b/Mage.Sets/src/mage/cards/w/WhereAncientsTread.java index e759b3d8b63..6d5644c4f9b 100644 --- a/Mage.Sets/src/mage/cards/w/WhereAncientsTread.java +++ b/Mage.Sets/src/mage/cards/w/WhereAncientsTread.java @@ -1,36 +1,39 @@ - package mage.cards.w; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author Plopman */ - public final class WhereAncientsTread extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature with power 5 or greater"); +public final class WhereAncientsTread extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("a creature you control with power 5 or greater"); + static { filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 4)); } public WhereAncientsTread(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{4}{R}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{R}"); // Whenever a creature with power 5 or greater you control enters, you may have Where Ancients Tread deal 5 damage to any target. - Ability ability = new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, new DamageTargetEffect(5).setText("you may have {this} deal 5 damage to any target"), filter, true); + Ability ability = new EntersBattlefieldAllTriggeredAbility( + new DamageTargetEffect(5) + .setText("you may have {this} deal 5 damage to any target"), + filter, true + ); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WhirlingDervish.java b/Mage.Sets/src/mage/cards/w/WhirlingDervish.java index 23e4d3c8769..cfff2e0e6dd 100644 --- a/Mage.Sets/src/mage/cards/w/WhirlingDervish.java +++ b/Mage.Sets/src/mage/cards/w/WhirlingDervish.java @@ -1,32 +1,27 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; -import mage.abilities.TriggeredAbility; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.condition.common.DealtDamageToAnOpponent; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.ProtectionAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.TargetController; import mage.counters.CounterType; -import mage.game.events.GameEvent; + +import java.util.UUID; /** - * * @author LevelX */ public final class WhirlingDervish extends CardImpl { - private static final String ruleText = "At the beginning of each end step, if {this} dealt damage to an opponent this turn, put a +1/+1 counter on it."; - public WhirlingDervish(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{G}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.MONK); @@ -36,9 +31,14 @@ public final class WhirlingDervish extends CardImpl { // Protection from black this.addAbility(ProtectionAbility.from(ObjectColor.BLACK)); + // At the beginning of each end step, if Whirling Dervish dealt damage to an opponent this turn, put a +1/+1 counter on it. - TriggeredAbility triggered = new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of each end step", true, new AddCountersSourceEffect(CounterType.P1P1.createInstance())); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(triggered, new DealtDamageToAnOpponent(), ruleText)); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.ANY, + new AddCountersSourceEffect(CounterType.P1P1.createInstance()) + .setText("put a +1/+1 counter on it"), + false, DealtDamageToAnOpponent.instance + )); } private WhirlingDervish(final WhirlingDervish card) { diff --git a/Mage.Sets/src/mage/cards/w/WhiskAway.java b/Mage.Sets/src/mage/cards/w/WhiskAway.java index aeda1bc88c6..93de2b9e7bb 100644 --- a/Mage.Sets/src/mage/cards/w/WhiskAway.java +++ b/Mage.Sets/src/mage/cards/w/WhiskAway.java @@ -11,6 +11,7 @@ import mage.filter.common.FilterAttackingOrBlockingCreature; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -26,7 +27,7 @@ public final class WhiskAway extends CardImpl { // Put target attacking or blocking creature on top of its owner's library. this.getSpellAbility().addEffect(new WhiskAwayEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private WhiskAway(final WhiskAway card) { diff --git a/Mage.Sets/src/mage/cards/w/WhispergearSneak.java b/Mage.Sets/src/mage/cards/w/WhispergearSneak.java index 2c4a5d11fe9..c6df85e9149 100644 --- a/Mage.Sets/src/mage/cards/w/WhispergearSneak.java +++ b/Mage.Sets/src/mage/cards/w/WhispergearSneak.java @@ -1,14 +1,15 @@ package mage.cards.w; -import java.util.UUID; import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.InfoEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.InfoEffect; + +import java.util.UUID; /** * @@ -26,10 +27,10 @@ public final class WhispergearSneak extends CardImpl { // TODO: Draft specific abilities not implemented // Draft Whispergear Sneak face up. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft Whispergear Sneak face up - not implemented."))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft {this} face up - not implemented."))); // During the draft, you may turn Whispergear Sneak face down. If you do, look at any unopened booster pack in the draft or any booster pack not being looked at by another player. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("During the draft, you may turn Whispergear Sneak face down. If you do, " + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("During the draft, you may turn {this} face down. If you do, " + "look at any unopened booster pack in the draft or any booster pack not being looked at by another player - not implemented."))); } diff --git a/Mage.Sets/src/mage/cards/w/WhiteGloveGourmand.java b/Mage.Sets/src/mage/cards/w/WhiteGloveGourmand.java index 8c8f068c4db..e8235d280eb 100644 --- a/Mage.Sets/src/mage/cards/w/WhiteGloveGourmand.java +++ b/Mage.Sets/src/mage/cards/w/WhiteGloveGourmand.java @@ -3,13 +3,12 @@ package mage.cards.w; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -42,11 +41,8 @@ public final class WhiteGloveGourmand extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new HumanSoldierToken(), 2))); // At the beginning of your end step, if another Human died under your control this turn, create a Food token. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility(new CreateTokenEffect(new FoodToken())), - WhiteGloveGourmandCondition.instance, - "At the beginning of your end step, if another Human died under your control this turn, create a Food token." - ).addHint(WhiteGloveGourmandCondition.hint), new WhiteGloveGourmandWatcher()); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new CreateTokenEffect(new FoodToken())) + .withInterveningIf(WhiteGloveGourmandCondition.instance).addHint(WhiteGloveGourmandCondition.hint), new WhiteGloveGourmandWatcher()); } private WhiteGloveGourmand(final WhiteGloveGourmand card) { diff --git a/Mage.Sets/src/mage/cards/w/WickedAkuba.java b/Mage.Sets/src/mage/cards/w/WickedAkuba.java index 32f48de14fa..a4cfc10ff45 100644 --- a/Mage.Sets/src/mage/cards/w/WickedAkuba.java +++ b/Mage.Sets/src/mage/cards/w/WickedAkuba.java @@ -1,7 +1,6 @@ package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -10,9 +9,8 @@ import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ColoredManaSymbol; -import mage.constants.Zone; +import mage.constants.SubType; import mage.filter.FilterPlayer; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; @@ -21,13 +19,15 @@ import mage.players.Player; import mage.target.TargetPlayer; import mage.watchers.common.PlayerDamagedBySourceWatcher; +import java.util.UUID; + /** * * @author North */ public final class WickedAkuba extends CardImpl { - private static final FilterPlayer filter = new FilterPlayer("player dealt damage by Wicked Akuba this turn"); + private static final FilterPlayer filter = new FilterPlayer("player dealt damage by {this} this turn"); static { filter.add(new WickedAkubaPredicate()); diff --git a/Mage.Sets/src/mage/cards/w/WickedPact.java b/Mage.Sets/src/mage/cards/w/WickedPact.java index 7af7624f848..c872ccf577c 100644 --- a/Mage.Sets/src/mage/cards/w/WickedPact.java +++ b/Mage.Sets/src/mage/cards/w/WickedPact.java @@ -1,26 +1,26 @@ package mage.cards.w; -import java.util.UUID; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author fireshoes */ public final class WickedPact extends CardImpl { public WickedPact(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{B}"); // Destroy two target nonblack creatures. You lose 5 life. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(2, 2, StaticFilters.FILTER_PERMANENT_CREATURES_NON_BLACK, false)); + this.getSpellAbility().addTarget(new TargetPermanent(2, StaticFilters.FILTER_PERMANENT_CREATURES_NON_BLACK)); this.getSpellAbility().addEffect(new LoseLifeSourceControllerEffect(5)); } diff --git a/Mage.Sets/src/mage/cards/w/WickedSlumber.java b/Mage.Sets/src/mage/cards/w/WickedSlumber.java index 3e94e9849f8..1e5a0940f8d 100644 --- a/Mage.Sets/src/mage/cards/w/WickedSlumber.java +++ b/Mage.Sets/src/mage/cards/w/WickedSlumber.java @@ -1,6 +1,5 @@ package mage.cards.w; -import mage.MageItem; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TapTargetEffect; @@ -12,8 +11,7 @@ import mage.constants.Outcome; import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -87,13 +85,7 @@ class WickedSlumberEffect extends OneShotEffect { return true; } FilterPermanent filter = new FilterCreaturePermanent(); - filter.add(Predicates.or( - permanents - .stream() - .map(MageItem::getId) - .map(PermanentIdPredicate::new) - .collect(Collectors.toList()) - )); + filter.add(new PermanentReferenceInCollectionPredicate(permanents, game)); for (int i = 0; i < 2; i++) { TargetPermanent target = new TargetPermanent(filter); target.withNotTarget(true); diff --git a/Mage.Sets/src/mage/cards/w/WickerfolkThresher.java b/Mage.Sets/src/mage/cards/w/WickerfolkThresher.java index c22f8d62ab0..a0f3e10816c 100644 --- a/Mage.Sets/src/mage/cards/w/WickerfolkThresher.java +++ b/Mage.Sets/src/mage/cards/w/WickerfolkThresher.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -29,12 +28,10 @@ public final class WickerfolkThresher extends CardImpl { this.toughness = new MageInt(4); // Delirium -- Whenever Wickerfolk Thresher attacks, if there are four or more card types among cards in your graveyard, look at the top card of your library. If it's a land card, you may put it onto the battlefield. If you don't put the card onto the battlefield, put it into your hand. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new WickerfolkThresherEffect()), - DeliriumCondition.instance, "Whenever {this} attacks, if there are four or more card types " + - "among cards in your graveyard, look at the top card of your library. If it's a land card, you may " + - "put it onto the battlefield. If you don't put the card onto the battlefield, put it into your hand." - ).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); + this.addAbility(new AttacksTriggeredAbility(new WickerfolkThresherEffect()) + .withInterveningIf(DeliriumCondition.instance) + .setAbilityWord(AbilityWord.DELIRIUM) + .addHint(CardTypesInGraveyardCount.YOU.getHint())); } private WickerfolkThresher(final WickerfolkThresher card) { @@ -51,6 +48,8 @@ class WickerfolkThresherEffect extends OneShotEffect { WickerfolkThresherEffect() { super(Outcome.Benefit); + staticText = "look at the top card of your library. If it's a land card, you may put it onto the battlefield. " + + "If you don't put the card onto the battlefield, put it into your hand"; } private WickerfolkThresherEffect(final WickerfolkThresherEffect effect) { diff --git a/Mage.Sets/src/mage/cards/w/WildInstincts.java b/Mage.Sets/src/mage/cards/w/WildInstincts.java index eef26a7ebbf..eb6a829f5f3 100644 --- a/Mage.Sets/src/mage/cards/w/WildInstincts.java +++ b/Mage.Sets/src/mage/cards/w/WildInstincts.java @@ -12,9 +12,12 @@ import mage.constants.Duration; import mage.constants.TargetController; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; + /** * * @author LevelX2 @@ -33,7 +36,7 @@ public final class WildInstincts extends CardImpl { "(Each deals damage equal to its power to the other.)"); getSpellAbility().addEffect(fightTargetsEffect); - getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + getSpellAbility().addTarget(new TargetPermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); } private WildInstincts(final WildInstincts card) { diff --git a/Mage.Sets/src/mage/cards/w/WildernessHypnotist.java b/Mage.Sets/src/mage/cards/w/WildernessHypnotist.java index 795dd643a1c..f3a367217e3 100644 --- a/Mage.Sets/src/mage/cards/w/WildernessHypnotist.java +++ b/Mage.Sets/src/mage/cards/w/WildernessHypnotist.java @@ -17,6 +17,7 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class WildernessHypnotist extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(3); Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(-2, 0, Duration.EndOfTurn), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WildwoodMentor.java b/Mage.Sets/src/mage/cards/w/WildwoodMentor.java index 283575f1e72..2c7461131db 100644 --- a/Mage.Sets/src/mage/cards/w/WildwoodMentor.java +++ b/Mage.Sets/src/mage/cards/w/WildwoodMentor.java @@ -18,6 +18,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.permanent.AttackingPredicate; import mage.filter.predicate.permanent.TokenPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -59,7 +60,7 @@ public final class WildwoodMentor extends CardImpl { .setText("another target attacking creature gets +X/+X until end of turn, where X is {this}'s power"), false ); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WildwoodTracker.java b/Mage.Sets/src/mage/cards/w/WildwoodTracker.java index 80efe9ee458..7f957d121c1 100644 --- a/Mage.Sets/src/mage/cards/w/WildwoodTracker.java +++ b/Mage.Sets/src/mage/cards/w/WildwoodTracker.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.AttacksOrBlocksTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -23,7 +22,7 @@ import java.util.UUID; */ public final class WildwoodTracker extends CardImpl { - private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("you control another non-Human creature"); static { filter.add(AnotherPredicate.instance); @@ -41,12 +40,9 @@ public final class WildwoodTracker extends CardImpl { this.toughness = new MageInt(1); // Whenever Wildwood Tracker attacks or blocks, if you control another non-Human creature, Wildwood Tracker gets +1/+1 until end of turn. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksOrBlocksTriggeredAbility( - new BoostSourceEffect(1, 1, Duration.EndOfTurn), false - ), condition, "Whenever {this} attacks or blocks, if you control another non-Human creature, " + - "{this} gets +1/+1 until end of turn." - )); + this.addAbility(new AttacksOrBlocksTriggeredAbility( + new BoostSourceEffect(1, 1, Duration.EndOfTurn), false + ).withInterveningIf(condition)); } private WildwoodTracker(final WildwoodTracker card) { diff --git a/Mage.Sets/src/mage/cards/w/WillOfTheAbzan.java b/Mage.Sets/src/mage/cards/w/WillOfTheAbzan.java index 3bbcf532696..02f94c7229b 100644 --- a/Mage.Sets/src/mage/cards/w/WillOfTheAbzan.java +++ b/Mage.Sets/src/mage/cards/w/WillOfTheAbzan.java @@ -43,7 +43,7 @@ public final class WillOfTheAbzan extends CardImpl { .setText("any number of target opponents each sacrifice a creature " + "with the greatest power among creatures that player controls")); this.getSpellAbility().addEffect(new LoseLifeTargetControllerEffect(3).setText("and lose 3 life")); - this.getSpellAbility().addTarget(new TargetOpponent(0, 1, false)); + this.getSpellAbility().addTarget(new TargetOpponent(0, Integer.MAX_VALUE, false)); // * Return target creature card from your graveyard to the battlefield. this.getSpellAbility().addMode(new Mode(new ReturnFromGraveyardToBattlefieldTargetEffect()) diff --git a/Mage.Sets/src/mage/cards/w/WillingTestSubject.java b/Mage.Sets/src/mage/cards/w/WillingTestSubject.java index 194197896d7..9a560536164 100644 --- a/Mage.Sets/src/mage/cards/w/WillingTestSubject.java +++ b/Mage.Sets/src/mage/cards/w/WillingTestSubject.java @@ -1,4 +1,3 @@ - package mage.cards.w; import mage.MageInt; @@ -58,8 +57,9 @@ public final class WillingTestSubject extends CardImpl { class WillingTestSubjectTriggeredAbility extends TriggeredAbilityImpl { - public WillingTestSubjectTriggeredAbility() { + WillingTestSubjectTriggeredAbility() { super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance())); + setTriggerPhrase("Whenever you roll a 4 or higher on a die, "); } private WillingTestSubjectTriggeredAbility(final WillingTestSubjectTriggeredAbility ability) { @@ -83,8 +83,4 @@ class WillingTestSubjectTriggeredAbility extends TriggeredAbilityImpl { return this.isControlledBy(event.getTargetId()) && drEvent.getResult() >= 4; } - @Override - public String getRule() { - return "Whenever you roll a 4 or higher on a die, put a +1/+1 counter on {this}"; - } } diff --git a/Mage.Sets/src/mage/cards/w/WillowSatyr.java b/Mage.Sets/src/mage/cards/w/WillowSatyr.java index 21cfb6aff04..f77829df12c 100644 --- a/Mage.Sets/src/mage/cards/w/WillowSatyr.java +++ b/Mage.Sets/src/mage/cards/w/WillowSatyr.java @@ -15,6 +15,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.SuperType; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -44,7 +45,7 @@ public final class WillowSatyr extends CardImpl { new GainControlTargetEffect(Duration.WhileControlled), SourceTappedCondition.TAPPED, "Gain control of target legendary creature for as long as you control {this} and {this} remains tapped" ), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WindswiftSlice.java b/Mage.Sets/src/mage/cards/w/WindswiftSlice.java index bb74bc96156..0c9751e1c7a 100644 --- a/Mage.Sets/src/mage/cards/w/WindswiftSlice.java +++ b/Mage.Sets/src/mage/cards/w/WindswiftSlice.java @@ -12,9 +12,12 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.ElfWarriorToken; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * * @author bwsinger @@ -28,7 +31,7 @@ public final class WindswiftSlice extends CardImpl { // Target creature you control deals damage equal to its power to target creature you don't control. Create a number of 1/1 green Elf Warrior creature tokens equal to the amount of excess damage dealt this way. this.getSpellAbility().addEffect(new WindswiftSliceEffect()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); } private WindswiftSlice(final WindswiftSlice card) { diff --git a/Mage.Sets/src/mage/cards/w/WingPuncture.java b/Mage.Sets/src/mage/cards/w/WingPuncture.java index 8019f2b76ea..33c8f39bdcd 100644 --- a/Mage.Sets/src/mage/cards/w/WingPuncture.java +++ b/Mage.Sets/src/mage/cards/w/WingPuncture.java @@ -14,6 +14,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; @@ -34,7 +35,7 @@ public final class WingPuncture extends CardImpl { // Target creature you control deals damage equal to its power to target creature with flying. this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new WingPunctureEffect()); } diff --git a/Mage.Sets/src/mage/cards/w/WingSnare.java b/Mage.Sets/src/mage/cards/w/WingSnare.java index 2318052779d..f041ce1f5ea 100644 --- a/Mage.Sets/src/mage/cards/w/WingSnare.java +++ b/Mage.Sets/src/mage/cards/w/WingSnare.java @@ -9,6 +9,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class WingSnare extends CardImpl { // Destroy target creature with flying. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); } private WingSnare(final WingSnare card) { diff --git a/Mage.Sets/src/mage/cards/w/WingmantleChaplain.java b/Mage.Sets/src/mage/cards/w/WingmantleChaplain.java index e12168835d7..d41032733df 100644 --- a/Mage.Sets/src/mage/cards/w/WingmantleChaplain.java +++ b/Mage.Sets/src/mage/cards/w/WingmantleChaplain.java @@ -2,7 +2,7 @@ package mage.cards.w; import mage.MageInt; import mage.MageObject; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; @@ -14,7 +14,6 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicate; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.filter.predicate.mageobject.AnotherPredicate; @@ -30,7 +29,7 @@ public final class WingmantleChaplain extends CardImpl { private static final FilterPermanent filter = new FilterControlledCreaturePermanent("creature with defender you control"); private static final FilterPermanent filter2 - = new FilterCreaturePermanent("another creature with defender"); + = new FilterControlledCreaturePermanent("another creature you control with defender"); private static final Predicate predicate = new AbilityPredicate(DefenderAbility.class); @@ -57,7 +56,7 @@ public final class WingmantleChaplain extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new BirdToken(), xValue))); // Whenever another creature with defender you control enters, create a 1/1 white Bird creature token with flying. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new CreateTokenEffect(new BirdToken()), filter2)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility(new CreateTokenEffect(new BirdToken()), filter2)); } private WingmantleChaplain(final WingmantleChaplain card) { diff --git a/Mage.Sets/src/mage/cards/w/WingmateRoc.java b/Mage.Sets/src/mage/cards/w/WingmateRoc.java index c3ca3257cf9..5061a0f33e3 100644 --- a/Mage.Sets/src/mage/cards/w/WingmateRoc.java +++ b/Mage.Sets/src/mage/cards/w/WingmateRoc.java @@ -4,9 +4,8 @@ import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RaidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.AttackingCreatureCount; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.hint.common.RaidHint; @@ -26,6 +25,8 @@ import java.util.UUID; */ public final class WingmateRoc extends CardImpl { + private static final DynamicValue xValue = new AttackingCreatureCount(); + public WingmateRoc(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); this.subtype.add(SubType.BIRD); @@ -37,16 +38,11 @@ public final class WingmateRoc extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Raid — When Wingmate Roc enters the battlefield, if you attacked this turn, create a 3/4 white Bird creature token with flying. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new WingmateRocToken())), RaidCondition.instance, - "When {this} enters, if you attacked this turn, create a 3/4 white Bird creature token with flying.") - .setAbilityWord(AbilityWord.RAID) - .addHint(RaidHint.instance), - new PlayerAttackedWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new WingmateRocToken())) + .withInterveningIf(RaidCondition.instance).setAbilityWord(AbilityWord.RAID).addHint(RaidHint.instance), new PlayerAttackedWatcher()); // Whenever Wingmate Roc attacks, you gain 1 life for each attacking creature. - Effect effect = new GainLifeEffect(new AttackingCreatureCount()); - effect.setText("you gain 1 life for each attacking creature"); - this.addAbility(new AttacksTriggeredAbility(effect, false)); + this.addAbility(new AttacksTriggeredAbility(new GainLifeEffect(xValue).setText("you gain 1 life for each attacking creature"))); } private WingmateRoc(final WingmateRoc card) { diff --git a/Mage.Sets/src/mage/cards/w/WishclawTalisman.java b/Mage.Sets/src/mage/cards/w/WishclawTalisman.java index 9b714024a9e..67496fc1887 100644 --- a/Mage.Sets/src/mage/cards/w/WishclawTalisman.java +++ b/Mage.Sets/src/mage/cards/w/WishclawTalisman.java @@ -8,18 +8,15 @@ import mage.abilities.costs.common.RemoveCountersSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; -import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.players.Player; @@ -46,11 +43,12 @@ public final class WishclawTalisman extends CardImpl { // {1}, {T}, Remove a wish counter from Wishclaw Talisman: Search your library for a card, put it into your hand, then shuffle your library. An opponent gains control of Wishclaw Talisman. Activate this ability only during your turn. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new WishclawTalismanEffect(), new GenericManaCost(1), MyTurnCondition.instance + new SearchLibraryPutInHandEffect(new TargetCardInLibrary(), false), + new GenericManaCost(1), MyTurnCondition.instance ); + ability.addEffect(new WishclawTalismanEffect()); ability.addCost(new TapSourceCost()); ability.addCost(new RemoveCountersSourceCost(CounterType.WISH.createInstance())); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); } @@ -66,12 +64,9 @@ public final class WishclawTalisman extends CardImpl { class WishclawTalismanEffect extends OneShotEffect { - private static final Effect effect = new SearchLibraryPutInHandEffect(new TargetCardInLibrary(), false); - WishclawTalismanEffect() { super(Outcome.Benefit); - staticText = "Search your library for a card, put it into your hand, then shuffle. " + - "An opponent gains control of {this}"; + staticText = "An opponent gains control of {this}"; } private WishclawTalismanEffect(final WishclawTalismanEffect effect) { @@ -85,7 +80,6 @@ class WishclawTalismanEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - effect.apply(game, source); Player player = game.getPlayer(source.getControllerId()); if (player == null) { return false; diff --git a/Mage.Sets/src/mage/cards/w/WispdrinkerVampire.java b/Mage.Sets/src/mage/cards/w/WispdrinkerVampire.java index 9194e34f0d9..4db6f2a0248 100644 --- a/Mage.Sets/src/mage/cards/w/WispdrinkerVampire.java +++ b/Mage.Sets/src/mage/cards/w/WispdrinkerVampire.java @@ -2,7 +2,7 @@ package mage.cards.w; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.GainLifeEffect; @@ -19,7 +19,6 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.PowerPredicate; @@ -31,7 +30,7 @@ import java.util.UUID; public final class WispdrinkerVampire extends CardImpl { private static final FilterPermanent filter - = new FilterCreaturePermanent("another creature with power 2 or less"); + = new FilterControlledCreaturePermanent("another creature you control with power 2 or less"); private static final FilterPermanent filter2 = new FilterControlledCreaturePermanent(); static { @@ -52,7 +51,7 @@ public final class WispdrinkerVampire extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever another creature with power 2 or less you control enters, each opponent loses 1 life and you gain 1 life. - Ability ability = new EntersBattlefieldControlledTriggeredAbility(new LoseLifeOpponentsEffect(1), filter); + Ability ability = new EntersBattlefieldAllTriggeredAbility(new LoseLifeOpponentsEffect(1), filter); ability.addEffect(new GainLifeEffect(1).concatBy("and")); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/w/WispweaverAngel.java b/Mage.Sets/src/mage/cards/w/WispweaverAngel.java index 5a6cb31661f..02a0c380183 100644 --- a/Mage.Sets/src/mage/cards/w/WispweaverAngel.java +++ b/Mage.Sets/src/mage/cards/w/WispweaverAngel.java @@ -10,7 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -30,7 +30,7 @@ public final class WispweaverAngel extends CardImpl { // When Wispweaver Angel enters the battlefield, you may exile another target creature you control, then return that card to the battlefield under its owner's control. Ability ability = new EntersBattlefieldTriggeredAbility(new ExileThenReturnTargetEffect(false, true), true); - ability.addTarget(new TargetControlledCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WitchHunter.java b/Mage.Sets/src/mage/cards/w/WitchHunter.java index 6bf1516ecf8..c8b97743108 100644 --- a/Mage.Sets/src/mage/cards/w/WitchHunter.java +++ b/Mage.Sets/src/mage/cards/w/WitchHunter.java @@ -1,7 +1,5 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -13,13 +11,12 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.StaticFilters; -import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; import mage.target.common.TargetPlayerOrPlaneswalker; +import java.util.UUID; + /** - * * @author fireshoes */ public final class WitchHunter extends CardImpl { @@ -39,8 +36,7 @@ public final class WitchHunter extends CardImpl { // {1}{W}{W}, {tap}: Return target creature an opponent controls to its owner's hand. Ability returnAbility = new SimpleActivatedAbility(new ReturnToHandTargetEffect(), new ManaCostsImpl<>("{1}{W}{W}")); returnAbility.addCost(new TapSourceCost()); - TargetCreaturePermanent target = new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE); - returnAbility.addTarget(target); + returnAbility.addTarget(new TargetOpponentsCreaturePermanent()); this.addAbility(returnAbility); } diff --git a/Mage.Sets/src/mage/cards/w/WitchOfTheMoors.java b/Mage.Sets/src/mage/cards/w/WitchOfTheMoors.java index 60bac2d662e..12aabc07124 100644 --- a/Mage.Sets/src/mage/cards/w/WitchOfTheMoors.java +++ b/Mage.Sets/src/mage/cards/w/WitchOfTheMoors.java @@ -2,14 +2,13 @@ package mage.cards.w; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.YouGainedLifeCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.ControllerGainedLifeCount; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.effects.common.SacrificeOpponentsEffect; import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -40,15 +39,10 @@ public final class WitchOfTheMoors extends CardImpl { // At the beginning of your end step, if you gained life this turn, each opponent sacrifices a // creature and you return up to one target creature card from your graveyard to your hand. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility(new SacrificeOpponentsEffect( - StaticFilters.FILTER_PERMANENT_A_CREATURE - )), - condition, "At the beginning of your end step, if you gained life this turn, " - + "each opponent sacrifices a creature and you return up to one target creature card " - + "from your graveyard to your hand." - ); - ability.addEffect(new ReturnFromGraveyardToHandTargetEffect()); + Ability ability = new BeginningOfEndStepTriggeredAbility( + new SacrificeOpponentsEffect(StaticFilters.FILTER_PERMANENT_A_CREATURE) + ).withInterveningIf(condition); + ability.addEffect(new ReturnFromGraveyardToHandTargetEffect().concatBy("and you")); ability.addTarget(new TargetCardInYourGraveyard( 0, 1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD )); diff --git a/Mage.Sets/src/mage/cards/w/Withdraw.java b/Mage.Sets/src/mage/cards/w/Withdraw.java index ca0d10c4a53..01666de77d1 100644 --- a/Mage.Sets/src/mage/cards/w/Withdraw.java +++ b/Mage.Sets/src/mage/cards/w/Withdraw.java @@ -16,6 +16,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; import mage.util.ManaUtil; @@ -32,13 +33,13 @@ public final class Withdraw extends CardImpl { // Return target creature to its owner's hand. Then return another target creature to its owner's hand unless its controller pays {1}. this.getSpellAbility().addEffect(new WithdrawEffect()); - Target target = new TargetCreaturePermanent(new FilterCreaturePermanent("creature to return unconditionally")); + Target target = new TargetPermanent(new FilterCreaturePermanent("creature to return unconditionally")); target.setTargetTag(1); this.getSpellAbility().addTarget(target); FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature to return unless {1} is paid"); filter.add(new AnotherTargetPredicate(2)); - target = new TargetCreaturePermanent(filter); + target = new TargetPermanent(filter); target.setTargetTag(2); this.getSpellAbility().addTarget(target); } diff --git a/Mage.Sets/src/mage/cards/w/WithengarUnbound.java b/Mage.Sets/src/mage/cards/w/WithengarUnbound.java index dfc2c30b8de..032eae161b0 100644 --- a/Mage.Sets/src/mage/cards/w/WithengarUnbound.java +++ b/Mage.Sets/src/mage/cards/w/WithengarUnbound.java @@ -1,7 +1,6 @@ package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.common.counter.AddCountersSourceEffect; @@ -18,6 +17,8 @@ import mage.counters.CounterType; import mage.game.Game; import mage.game.events.GameEvent; +import java.util.UUID; + /** * * @author BetaSteward @@ -81,6 +82,6 @@ class WithengarUnboundTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever a player loses the game, put thirteen +1/+1 counters on Withengar Unbound."; + return "Whenever a player loses the game, put thirteen +1/+1 counters on {this}."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/w/WitheringWisps.java b/Mage.Sets/src/mage/cards/w/WitheringWisps.java index ec0ef84406a..9373b77c089 100644 --- a/Mage.Sets/src/mage/cards/w/WitheringWisps.java +++ b/Mage.Sets/src/mage/cards/w/WitheringWisps.java @@ -1,40 +1,37 @@ - package mage.cards.w; -import java.util.UUID; import mage.abilities.ActivatedAbilityImpl; -import mage.abilities.TriggeredAbility; -import mage.abilities.common.OnEventTriggeredAbility; -import mage.abilities.condition.common.CreatureCountCondition; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageEverythingEffect; import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.TargetController; -import mage.constants.SuperType; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; +import mage.constants.*; import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; + +import java.util.UUID; /** - * * @author L_J */ public final class WitheringWisps extends CardImpl { - private static final String ruleText = "At the beginning of the end step, if no creatures are on the battlefield, sacrifice {this}."; + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterCreaturePermanent("no creatures are on the battlefield"), + ComparisonType.EQUAL_TO, 0, false + ); public WitheringWisps(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{B}"); // At the beginning of the end step, if no creatures are on the battlefield, sacrifice Withering Wisps. - TriggeredAbility triggered = new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new SacrificeSourceEffect()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(triggered, new CreatureCountCondition(0, TargetController.ANY), ruleText)); + this.addAbility(new BeginningOfEndStepTriggeredAbility(TargetController.NEXT, new SacrificeSourceEffect(), false, condition)); // {B}: Withering Wisps deals 1 damage to each creature and each player. Activate this ability no more times each turn than the number of snow Swamps you control. this.addAbility(new WitheringWispsActivatedAbility()); @@ -52,17 +49,15 @@ public final class WitheringWisps extends CardImpl { class WitheringWispsActivatedAbility extends ActivatedAbilityImpl { - private static final FilterPermanent filter = new FilterPermanent("snow Swamps you control"); + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.SWAMP, "snow Swamps you control"); static { filter.add(SuperType.SNOW.getPredicate()); - filter.add(SubType.SWAMP.getPredicate()); - filter.add(TargetController.YOU.getControllerPredicate()); } @Override public int getMaxActivationsPerTurn(Game game) { - return game.getBattlefield().getAllActivePermanents(filter, game).size(); + return game.getBattlefield().getActivePermanents(filter, getControllerId(), this, game).size(); } public WitheringWispsActivatedAbility() { @@ -76,7 +71,7 @@ class WitheringWispsActivatedAbility extends ActivatedAbilityImpl { @Override public String getRule() { - return super.getRule() + " Activate this ability no more times each turn than the number of snow Swamps you control."; + return super.getRule() + " Activate no more times each turn than the number of snow Swamps you control."; } @Override diff --git a/Mage.Sets/src/mage/cards/w/WolfStrike.java b/Mage.Sets/src/mage/cards/w/WolfStrike.java index 6a7e7288350..552c59514e2 100644 --- a/Mage.Sets/src/mage/cards/w/WolfStrike.java +++ b/Mage.Sets/src/mage/cards/w/WolfStrike.java @@ -13,9 +13,12 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.filter.StaticFilters; import mage.game.Game; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; + /** * * @author weirddan455 @@ -28,7 +31,7 @@ public final class WolfStrike extends CardImpl { // Target creature you control gets +2/+0 until end of turn if it's night. // Then it deals damage equal to its power to target creature you don't control. this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); this.getSpellAbility().addEffect(new WolfStikeEffect()); this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect("it").concatBy("Then")); } diff --git a/Mage.Sets/src/mage/cards/w/WolfhuntersQuiver.java b/Mage.Sets/src/mage/cards/w/WolfhuntersQuiver.java index 192954a6937..aa094c3e46a 100644 --- a/Mage.Sets/src/mage/cards/w/WolfhuntersQuiver.java +++ b/Mage.Sets/src/mage/cards/w/WolfhuntersQuiver.java @@ -14,6 +14,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetAnyTarget; import mage.target.common.TargetCreaturePermanent; @@ -42,7 +43,7 @@ public final class WolfhuntersQuiver extends CardImpl { // and "{T}: This creature deals 3 damage to target Werewolf creature." abilityToGain = new SimpleActivatedAbility(new DamageTargetEffect(3), new TapSourceCost()); - abilityToGain.addTarget(new TargetCreaturePermanent(filter)); + abilityToGain.addTarget(new TargetPermanent(filter)); effect = new GainAbilityAttachedEffect(abilityToGain, AttachmentType.EQUIPMENT); effect.setText("and \"{T}: This creature deals 3 damage to target Werewolf creature.\""); ability.addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/w/WolfwillowHaven.java b/Mage.Sets/src/mage/cards/w/WolfwillowHaven.java index 532db353ad8..b36ba498e75 100644 --- a/Mage.Sets/src/mage/cards/w/WolfwillowHaven.java +++ b/Mage.Sets/src/mage/cards/w/WolfwillowHaven.java @@ -9,12 +9,14 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.mana.AddManaToManaPoolTargetControllerEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.abilities.keyword.EnchantAbility; import mage.abilities.mana.EnchantedTappedTriggeredManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.game.permanent.token.WolfToken; import mage.target.TargetPermanent; import mage.target.common.TargetLandPermanent; @@ -45,11 +47,9 @@ public final class WolfwillowHaven extends CardImpl { // {4}{G}, Sacrifice Wolfwillow Haven: Create a 2/2 green Wolf creature token. Activate this ability only during your turn. ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new CreateTokenEffect(new WolfToken()), - new ManaCostsImpl<>("{4}{G}"), MyTurnCondition.instance + new CreateTokenEffect(new WolfToken()), new ManaCostsImpl<>("{4}{G}"), MyTurnCondition.instance ); ability.addCost(new SacrificeSourceCost()); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WoodcallerAutomaton.java b/Mage.Sets/src/mage/cards/w/WoodcallerAutomaton.java index c8ab4ac80ad..300c6a2c8d8 100644 --- a/Mage.Sets/src/mage/cards/w/WoodcallerAutomaton.java +++ b/Mage.Sets/src/mage/cards/w/WoodcallerAutomaton.java @@ -1,14 +1,15 @@ package mage.cards.w; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerValue; +import mage.abilities.dynamicvalue.common.SourcePermanentToughnessValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; +import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.PrototypeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -18,12 +19,9 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.game.permanent.token.custom.CreatureToken; import mage.target.TargetPermanent; -import java.util.Objects; -import java.util.Optional; import java.util.UUID; /** @@ -42,12 +40,8 @@ public final class WoodcallerAutomaton extends CardImpl { this.addAbility(new PrototypeAbility(this, "{2}{G}{G}", 3, 3)); // When Woodcaller Automaton enters the battlefield, if you cast it, untap target land you control. It becomes a Treefolk creature with haste and base power and toughness equal to Woodcaller Automaton's power and toughness. It's still a land. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new UntapTargetEffect()), - CastFromEverywhereSourceCondition.instance, "When {this} enters, " + - "if you cast it, untap target land you control. It becomes a Treefolk creature with haste " + - "and base power and toughness equal to {this}'s power and toughness. It's still a land." - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new UntapTargetEffect()) + .withInterveningIf(CastFromEverywhereSourceCondition.instance); ability.addEffect(new WoodcallerAutomatonEffect()); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND)); this.addAbility(ability); @@ -67,6 +61,7 @@ class WoodcallerAutomatonEffect extends OneShotEffect { WoodcallerAutomatonEffect() { super(Outcome.Benefit); + staticText = "It becomes a Treefolk creature with haste and base power and toughness equal to {this}'s power and toughness. It's still a land"; } private WoodcallerAutomatonEffect(final WoodcallerAutomatonEffect effect) { @@ -80,19 +75,10 @@ class WoodcallerAutomatonEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Optional optionalPermanent = Optional - .ofNullable(source.getSourcePermanentOrLKI(game)) - .filter(Objects::nonNull); - int power = optionalPermanent - .map(MageObject::getPower) - .map(MageInt::getValue) - .orElse(0); - int toughness = optionalPermanent - .map(MageObject::getToughness) - .map(MageInt::getValue) - .orElse(0); + int power = SourcePermanentPowerValue.ALLOW_NEGATIVE.calculate(game, source, this); + int toughness = SourcePermanentToughnessValue.instance.calculate(game, source, this); game.addEffect(new BecomesCreatureTargetEffect( - new CreatureToken(power, toughness, "", SubType.TREEFOLK), + new CreatureToken(power, toughness, "", SubType.TREEFOLK).withAbility(HasteAbility.getInstance()), false, true, Duration.Custom ), source); return true; diff --git a/Mage.Sets/src/mage/cards/w/WoodlandSleuth.java b/Mage.Sets/src/mage/cards/w/WoodlandSleuth.java index abc9d5e1e6f..e181039a0b8 100644 --- a/Mage.Sets/src/mage/cards/w/WoodlandSleuth.java +++ b/Mage.Sets/src/mage/cards/w/WoodlandSleuth.java @@ -1,14 +1,13 @@ package mage.cards.w; import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.MorbidCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardAtRandomEffect; import mage.abilities.hint.common.MorbidHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; @@ -17,13 +16,10 @@ import mage.filter.StaticFilters; import java.util.UUID; /** - * * @author North */ public final class WoodlandSleuth extends CardImpl { - private static final String staticText = "Morbid — When {this} enters, if a creature died this turn, return a creature card at random from your graveyard to your hand."; - public WoodlandSleuth(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); this.subtype.add(SubType.HUMAN); @@ -34,9 +30,9 @@ public final class WoodlandSleuth extends CardImpl { this.toughness = new MageInt(3); // Morbid — When Woodland Sleuth enters the battlefield, if a creature died this turn, return a creature card at random from your graveyard to your hand. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility( - new ReturnFromGraveyardAtRandomEffect(StaticFilters.FILTER_CARD_CREATURE, Zone.HAND)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, MorbidCondition.instance, staticText).addHint(MorbidHint.instance)); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new ReturnFromGraveyardAtRandomEffect(StaticFilters.FILTER_CARD_CREATURE, Zone.HAND) + ).withInterveningIf(MorbidCondition.instance).setAbilityWord(AbilityWord.MORBID).addHint(MorbidHint.instance)); } private WoodlandSleuth(final WoodlandSleuth card) { diff --git a/Mage.Sets/src/mage/cards/w/WookieeRaidleader.java b/Mage.Sets/src/mage/cards/w/WookieeRaidleader.java index 55e00ec7391..d783d02f98b 100644 --- a/Mage.Sets/src/mage/cards/w/WookieeRaidleader.java +++ b/Mage.Sets/src/mage/cards/w/WookieeRaidleader.java @@ -13,8 +13,11 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Duration; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_ANOTHER_TARGET_CREATURE; + /** * * @author Styxo @@ -30,7 +33,7 @@ public final class WookieeRaidleader extends CardImpl { // Whenever Wookiee Raidleader attacks, antoher target creature gains trample until end of turn Ability ability = new AttacksTriggeredAbility(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn), false); - ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + ability.addTarget(new TargetPermanent(FILTER_ANOTHER_TARGET_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WowzerTheAspirational.java b/Mage.Sets/src/mage/cards/w/WowzerTheAspirational.java index 55cfdf03022..59d23c16e76 100644 --- a/Mage.Sets/src/mage/cards/w/WowzerTheAspirational.java +++ b/Mage.Sets/src/mage/cards/w/WowzerTheAspirational.java @@ -5,13 +5,10 @@ import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.CompoundCondition; import mage.abilities.condition.Condition; -import mage.abilities.condition.IntCompareCondition; import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.condition.common.HaveInitiativeCondition; import mage.abilities.condition.common.MonarchIsSourceControllerCondition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.dynamicvalue.common.CountersControllerCount; import mage.abilities.effects.common.WinGameSourceControllerEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; @@ -21,13 +18,14 @@ import mage.abilities.hint.common.MonarchHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ComparisonType; import mage.constants.SubType; import mage.constants.SuperType; import mage.counters.CounterType; import mage.filter.common.FilterControlledPermanent; +import mage.game.Controllable; import mage.game.Game; +import java.util.Optional; import java.util.UUID; /** @@ -35,7 +33,7 @@ import java.util.UUID; */ public class WowzerTheAspirational extends CardImpl { - private static final Condition energyCondition = new WowzerTheAspirationalCondition(); + private static final Condition energyCondition = WowzerTheAspirationalCondition.instance; private static final Condition bloodCondition = new PermanentsOnTheBattlefieldCondition(new FilterControlledPermanent(SubType.BLOOD)); private static final Condition clueCondition @@ -50,6 +48,8 @@ public class WowzerTheAspirational extends CardImpl { = new PermanentsOnTheBattlefieldCondition(new FilterControlledPermanent(SubType.TREASURE)); private static final Condition winCondition = new CompoundCondition( + "you have an {E}, control a Blood, a Clue, a Food, a Map, a Powerstone, and a Treasure, " + + "are the monarch, and have the city's blessing and the initiative", energyCondition, bloodCondition, clueCondition, @@ -59,7 +59,8 @@ public class WowzerTheAspirational extends CardImpl { treasureCondition, MonarchIsSourceControllerCondition.instance, CitysBlessingCondition.instance, - HaveInitiativeCondition.instance); + HaveInitiativeCondition.instance + ); private static final Hint energyHint = new ConditionHint(energyCondition, "You have an {E}"); private static final Hint bloodHint = new ConditionHint(bloodCondition, "You control a Blood"); @@ -83,13 +84,9 @@ public class WowzerTheAspirational extends CardImpl { // Whenever Wowzer, the Aspirational attacks, // if you have an {E}, control a Blood, a Clue, a Food, a Map, a Powerstone, and a Treasure, // are the monarch, and have the city's blessing and the initiative, you win the game. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new WinGameSourceControllerEffect()), - winCondition, - "Whenever {this} attacks, " + - "if you have an {E}, control a Blood, a Clue, a Food, a Map, a Powerstone, and a Treasure, " + - "are the monarch, and have the city's blessing and the initiative, you win the game." - ).addHint(energyHint) + this.addAbility(new AttacksTriggeredAbility(new WinGameSourceControllerEffect()) + .withInterveningIf(winCondition) + .addHint(energyHint) .addHint(bloodHint) .addHint(clueHint) .addHint(foodHint) @@ -111,14 +108,16 @@ public class WowzerTheAspirational extends CardImpl { } } -class WowzerTheAspirationalCondition extends IntCompareCondition { - - WowzerTheAspirationalCondition() { - super(ComparisonType.MORE_THAN, 0); - } +enum WowzerTheAspirationalCondition implements Condition { + instance; @Override - protected int getInputValue(Game game, Ability source) { - return new CountersControllerCount(CounterType.ENERGY).calculate(game, source, null); + public boolean apply(Game game, Ability source) { + return Optional + .of(source) + .map(Controllable::getControllerId) + .map(game::getPlayer) + .filter(player -> player.getCountersCount(CounterType.ENERGY) > 0) + .isPresent(); } } diff --git a/Mage.Sets/src/mage/cards/w/Wrangle.java b/Mage.Sets/src/mage/cards/w/Wrangle.java index ec9db18fbfa..e3503135c8c 100644 --- a/Mage.Sets/src/mage/cards/w/Wrangle.java +++ b/Mage.Sets/src/mage/cards/w/Wrangle.java @@ -14,6 +14,7 @@ import mage.constants.ComparisonType; import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -32,7 +33,7 @@ public final class Wrangle extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); // Gain control of target creature with power 4 or less until end of turn. Untap that creature. It gains haste until end of turn. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfTurn)); Effect effect = new UntapTargetEffect(); effect.setText("Untap that creature"); diff --git a/Mage.Sets/src/mage/cards/w/WretchedCamel.java b/Mage.Sets/src/mage/cards/w/WretchedCamel.java index 1a865b57a42..d7e59681720 100644 --- a/Mage.Sets/src/mage/cards/w/WretchedCamel.java +++ b/Mage.Sets/src/mage/cards/w/WretchedCamel.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.condition.common.DesertControlledOrGraveyardCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -28,11 +27,7 @@ public final class WretchedCamel extends CardImpl { this.toughness = new MageInt(1); // When Wretched Camel dies, if you control a Desert or there is a Desert card in your graveyard, target player discards a card. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new DiesSourceTriggeredAbility(new DiscardTargetEffect(1)), - DesertControlledOrGraveyardCondition.instance, "When {this} dies, " + - "if you control a Desert or there is a Desert card in your graveyard, target player discards a card." - ); + Ability ability = new DiesSourceTriggeredAbility(new DiscardTargetEffect(1)).withInterveningIf(DesertControlledOrGraveyardCondition.instance); ability.addTarget(new TargetPlayer()); this.addAbility(ability.addHint(DesertControlledOrGraveyardCondition.getHint())); } diff --git a/Mage.Sets/src/mage/cards/w/WritOfPassage.java b/Mage.Sets/src/mage/cards/w/WritOfPassage.java index 7787b1c3bc0..c2053b11018 100644 --- a/Mage.Sets/src/mage/cards/w/WritOfPassage.java +++ b/Mage.Sets/src/mage/cards/w/WritOfPassage.java @@ -2,10 +2,9 @@ package mage.cards.w; import mage.abilities.Ability; import mage.abilities.common.AttacksAttachedTriggeredAbility; -import mage.abilities.condition.common.AttachedToMatchesFilterCondition; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceMatchesFilterCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; import mage.abilities.keyword.EnchantAbility; @@ -16,8 +15,6 @@ import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; @@ -28,6 +25,16 @@ import java.util.UUID; */ public final class WritOfPassage extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent("its power is 2 or less"); + private static final FilterPermanent filter2 = new FilterCreaturePermanent("creature with power 2 or less"); + + static { + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); + filter2.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); + } + + private static final Condition condition = new SourceMatchesFilterCondition(filter); + public WritOfPassage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); @@ -37,22 +44,18 @@ public final class WritOfPassage extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget)); // Whenever enchanted creature attacks, if its power is 2 or less, it's unblockable this turn. - FilterPermanent filter = new FilterPermanent("if enchanted creature's power is 2 or less"); - filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); - ability = new ConditionalInterveningIfTriggeredAbility(new AttacksAttachedTriggeredAbility( - new WritOfPassageAttachedEffect(AttachmentType.AURA), AttachmentType.AURA, false), - new AttachedToMatchesFilterCondition(filter), "Whenever enchanted creature attacks, if its power is 2 or less, it can't be blocked this turn."); - this.addAbility(ability); + this.addAbility(new AttacksAttachedTriggeredAbility( + new CantBeBlockedTargetEffect().setText("it can't be blocked this turn"), + AttachmentType.AURA, false, SetTargetPointer.PERMANENT + ).withInterveningIf(condition)); + // Forecast - {1}{U}, Reveal Writ of Passage from your hand: Target creature with power 2 or less is unblockable this turn. - ForecastAbility ability2 = new ForecastAbility(new CantBeBlockedTargetEffect(), new ManaCostsImpl<>("{1}{U}")); - FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creature with power 2 or less"); - filter2.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); - ability2.addTarget(new TargetCreaturePermanent(filter2)); - this.addAbility(ability2); + Ability ability = new ForecastAbility(new CantBeBlockedTargetEffect(), new ManaCostsImpl<>("{1}{U}")); + ability.addTarget(new TargetPermanent(filter2)); + this.addAbility(ability); } private WritOfPassage(final WritOfPassage card) { @@ -64,31 +67,3 @@ public final class WritOfPassage extends CardImpl { return new WritOfPassage(this); } } - -class WritOfPassageAttachedEffect extends RestrictionEffect { - - WritOfPassageAttachedEffect(AttachmentType attachmentType) { - super(Duration.EndOfTurn); - this.staticText = attachmentType.verb() + " creature can't be blocked"; - } - - private WritOfPassageAttachedEffect(final WritOfPassageAttachedEffect effect) { - super(effect); - } - - @Override - public WritOfPassageAttachedEffect copy() { - return new WritOfPassageAttachedEffect(this); - } - - @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { - return false; - } - - @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - Permanent attachment = game.getPermanent(source.getSourceId()); - return attachment != null && attachment.isAttachedTo(permanent.getId()); - } -} diff --git a/Mage.Sets/src/mage/cards/w/WuLongbowman.java b/Mage.Sets/src/mage/cards/w/WuLongbowman.java index 1f808131064..45addd2fd47 100644 --- a/Mage.Sets/src/mage/cards/w/WuLongbowman.java +++ b/Mage.Sets/src/mage/cards/w/WuLongbowman.java @@ -1,7 +1,5 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -12,17 +10,17 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author fireshoes */ public final class WuLongbowman extends CardImpl { public WuLongbowman(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); this.subtype.add(SubType.ARCHER); @@ -30,8 +28,9 @@ public final class WuLongbowman extends CardImpl { this.toughness = new MageInt(1); // {tap}: Wu Longbowman deals 1 damage to any target. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new DamageTargetEffect(1), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DamageTargetEffect(1), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance + ); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WumpusAberration.java b/Mage.Sets/src/mage/cards/w/WumpusAberration.java index 43cd3f14568..342c1580104 100644 --- a/Mage.Sets/src/mage/cards/w/WumpusAberration.java +++ b/Mage.Sets/src/mage/cards/w/WumpusAberration.java @@ -1,28 +1,30 @@ package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.ManaWasSpentCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CastSourceTriggeredAbility; import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect; -import mage.constants.SubType; import mage.abilities.keyword.DevoidAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.filter.StaticFilters; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author DominionSpy */ public final class WumpusAberration extends CardImpl { + private static final Condition condition = new InvertCondition(ManaWasSpentCondition.COLORLESS, "{C} wasn't spent to cast it"); + public WumpusAberration(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); @@ -35,13 +37,9 @@ public final class WumpusAberration extends CardImpl { this.addAbility(new DevoidAbility(this.color)); // When you cast this spell, if {C} wasn't spent to cast it, target opponent may put a creature card from their hand onto the battlefield. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new CastSourceTriggeredAbility( - new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_CREATURE, true)), - new InvertCondition(ManaWasSpentCondition.COLORLESS), - "When you cast this spell, if {C} wasn't spent to cast it, " + - "target opponent may put a creature card from their hand onto the battlefield." - ); + Ability ability = new CastSourceTriggeredAbility(new PutCardFromHandOntoBattlefieldEffect( + StaticFilters.FILTER_CARD_CREATURE, true + ).setText("target opponent may put a creature card from their hand onto the battlefield")).withInterveningIf(condition); ability.addTarget(new TargetOpponent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/w/WurmwallSweeper.java b/Mage.Sets/src/mage/cards/w/WurmwallSweeper.java new file mode 100644 index 00000000000..ebcce0554cf --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WurmwallSweeper.java @@ -0,0 +1,47 @@ +package mage.cards.w; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.StationAbility; +import mage.abilities.keyword.StationLevelAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WurmwallSweeper extends CardImpl { + + public WurmwallSweeper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + this.subtype.add(SubType.SPACECRAFT); + + // When this Spacecraft enters, surveil 2. + this.addAbility(new EntersBattlefieldTriggeredAbility(new SurveilEffect(2))); + + // Station + this.addAbility(new StationAbility()); + + // STATION 4+ + // Flying + // 2/2 + this.addAbility(new StationLevelAbility(4) + .withLevelAbility(FlyingAbility.getInstance()) + .withPT(2, 2)); + } + + private WurmwallSweeper(final WurmwallSweeper card) { + super(card); + } + + @Override + public WurmwallSweeper copy() { + return new WurmwallSweeper(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WurmweaverCoil.java b/Mage.Sets/src/mage/cards/w/WurmweaverCoil.java index 0b005173f1c..9fdb0c32ae8 100644 --- a/Mage.Sets/src/mage/cards/w/WurmweaverCoil.java +++ b/Mage.Sets/src/mage/cards/w/WurmweaverCoil.java @@ -41,7 +41,7 @@ public final class WurmweaverCoil extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{4}{G}{G}"); this.subtype.add(SubType.AURA); - TargetPermanent auraTarget = new TargetCreaturePermanent(filter); + TargetPermanent auraTarget = new TargetPermanent(filter); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Benefit)); Ability ability = new EnchantAbility(auraTarget); diff --git a/Mage.Sets/src/mage/cards/x/XerexStrobeKnight.java b/Mage.Sets/src/mage/cards/x/XerexStrobeKnight.java index c97b78a4f0b..1139273654d 100644 --- a/Mage.Sets/src/mage/cards/x/XerexStrobeKnight.java +++ b/Mage.Sets/src/mage/cards/x/XerexStrobeKnight.java @@ -12,7 +12,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.token.KnightWhiteBlueToken; import mage.watchers.common.CastSpellLastTurnWatcher; @@ -40,7 +39,7 @@ public final class XerexStrobeKnight extends CardImpl { // {T}: Create a 2/2 white and blue Knight creature token with vigilance. Activate only if you've cast two or more spells this turn. this.addAbility(new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new CreateTokenEffect(new KnightWhiteBlueToken()), + new CreateTokenEffect(new KnightWhiteBlueToken()), new TapSourceCost(), XerexStrobeKnightCondition.instance )); } @@ -70,4 +69,4 @@ enum XerexStrobeKnightCondition implements Condition { public String toString() { return "you've cast two or more spells this turn"; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/x/XiahouDunTheOneEyed.java b/Mage.Sets/src/mage/cards/x/XiahouDunTheOneEyed.java index 960f837c52b..2d2c89ba9cb 100644 --- a/Mage.Sets/src/mage/cards/x/XiahouDunTheOneEyed.java +++ b/Mage.Sets/src/mage/cards/x/XiahouDunTheOneEyed.java @@ -44,7 +44,7 @@ public final class XiahouDunTheOneEyed extends CardImpl { this.addAbility(HorsemanshipAbility.getInstance()); // Sacrifice Xiahou Dun, the One-Eyed: Return target black card from your graveyard to your hand. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, + Ability ability = new ActivateIfConditionActivatedAbility( new ReturnFromGraveyardToHandTargetEffect(), new SacrificeSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/x/XunYuWeiAdvisor.java b/Mage.Sets/src/mage/cards/x/XunYuWeiAdvisor.java index 62ac471e703..6f705ae3957 100644 --- a/Mage.Sets/src/mage/cards/x/XunYuWeiAdvisor.java +++ b/Mage.Sets/src/mage/cards/x/XunYuWeiAdvisor.java @@ -1,7 +1,5 @@ - package mage.cards.x; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -12,19 +10,18 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Duration; import mage.constants.SuperType; -import mage.constants.Zone; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class XunYuWeiAdvisor extends CardImpl { public XunYuWeiAdvisor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ADVISOR); @@ -32,8 +29,10 @@ public final class XunYuWeiAdvisor extends CardImpl { this.toughness = new MageInt(1); // {tap}: Target creature you control gets +2/+0 until end of turn. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new BoostTargetEffect(2, 0, Duration.EndOfTurn), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new BoostTargetEffect(2, 0), new TapSourceCost(), + MyTurnBeforeAttackersDeclaredCondition.instance + ); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/y/YasovaDragonclaw.java b/Mage.Sets/src/mage/cards/y/YasovaDragonclaw.java index 165c9c2c20e..9b7e5f83e20 100644 --- a/Mage.Sets/src/mage/cards/y/YasovaDragonclaw.java +++ b/Mage.Sets/src/mage/cards/y/YasovaDragonclaw.java @@ -1,10 +1,8 @@ package mage.cards.y; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DoIfCostPaid; @@ -13,19 +11,18 @@ import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.SuperType; -import mage.constants.TargetController; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** * @@ -33,7 +30,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class YasovaDragonclaw extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls with power less than Yasova Dragonclaw's power"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls with power less than {this}'s power"); static { filter.add(new YasovaDragonclawPowerLessThanSourcePredicate()); @@ -57,7 +54,7 @@ public final class YasovaDragonclaw extends CardImpl { effect.addEffect(effect2); effect.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn, ", and it gains haste until end of turn")); Ability ability = new BeginningOfCombatTriggeredAbility(effect); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } @@ -81,6 +78,6 @@ class YasovaDragonclawPowerLessThanSourcePredicate implements ObjectSourcePlayer @Override public String toString() { - return "power less than Yasova Dragonclaw's power"; + return "power less than {this}'s power"; } } diff --git a/Mage.Sets/src/mage/cards/y/YavimayaIconoclast.java b/Mage.Sets/src/mage/cards/y/YavimayaIconoclast.java index 8b2d2c09950..5ff6c7e99c3 100644 --- a/Mage.Sets/src/mage/cards/y/YavimayaIconoclast.java +++ b/Mage.Sets/src/mage/cards/y/YavimayaIconoclast.java @@ -1,10 +1,9 @@ package mage.cards.y; import mage.MageInt; -import mage.abilities.TriggeredAbility; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.HasteAbility; @@ -37,10 +36,13 @@ public final class YavimayaIconoclast extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // When Yavimaya Iconoclast enters the battlefield, if it was kicked, it gets +1/+1 and gains haste until end of turn. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn)); - ability.addEffect(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.EndOfTurn)); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.ONCE, - "When {this} enters, if it was kicked, it gets +1/+1 and gains haste until end of turn.")); + Ability ability = new EntersBattlefieldTriggeredAbility(new BoostSourceEffect( + 1, 1, Duration.EndOfTurn + ).setText("it gets +1/+1")).withInterveningIf(KickedCondition.ONCE); + ability.addEffect(new GainAbilitySourceEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains haste until end of turn")); + this.addAbility(ability); } private YavimayaIconoclast(final YavimayaIconoclast card) { diff --git a/Mage.Sets/src/mage/cards/y/YawgmothsVileOffering.java b/Mage.Sets/src/mage/cards/y/YawgmothsVileOffering.java index e8851a48ccd..bd619465ade 100644 --- a/Mage.Sets/src/mage/cards/y/YawgmothsVileOffering.java +++ b/Mage.Sets/src/mage/cards/y/YawgmothsVileOffering.java @@ -11,7 +11,6 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SuperType; import mage.constants.Zone; -import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; import mage.filter.common.FilterPermanentCard; import mage.filter.predicate.Predicates; import mage.game.Game; @@ -47,7 +46,7 @@ public final class YawgmothsVileOffering extends CardImpl { // Destroy up to one target creature or planeswalker. Exile Yawgmoth's Vile Offering. this.getSpellAbility().addEffect(new YawgmothsVileOfferingEffect()); this.getSpellAbility().addTarget(new TargetCardInGraveyard(0, 1, cardFilter)); - this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker(0, 1, new FilterCreatureOrPlaneswalkerPermanent(), false)); + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker(0, 1)); this.getSpellAbility().addEffect(new ExileSpellEffect()); } diff --git a/Mage.Sets/src/mage/cards/y/YesManPersonalSecuritron.java b/Mage.Sets/src/mage/cards/y/YesManPersonalSecuritron.java index 0db344a9708..c2a3593240f 100644 --- a/Mage.Sets/src/mage/cards/y/YesManPersonalSecuritron.java +++ b/Mage.Sets/src/mage/cards/y/YesManPersonalSecuritron.java @@ -1,6 +1,5 @@ package mage.cards.y; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -14,10 +13,11 @@ import mage.abilities.effects.common.CreateTokenTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.TargetPlayerGainControlSourceEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.abilities.hint.common.MyTurnHint; -import mage.constants.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; @@ -25,29 +25,31 @@ import mage.game.permanent.token.SoldierToken; import mage.target.common.TargetOpponent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author Grath */ public final class YesManPersonalSecuritron extends CardImpl { public YesManPersonalSecuritron(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{W}"); - + this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.ROBOT); this.power = new MageInt(2); this.toughness = new MageInt(2); // {T}: Target opponent gains control of Yes Man, Personal Securitron. When they do, you draw two cards and put a quest counter on Yes Man. Activate only during your turn. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new YesManPersonalSecuritronControlEffect(), new TapSourceCost(), MyTurnCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new YesManPersonalSecuritronControlEffect(), + new TapSourceCost(), MyTurnCondition.instance + ); ability.addTarget(new TargetOpponent()); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); // Wild Card -- When Yes Man leaves the battlefield, its owner creates a tapped 1/1 white Soldier creature token for each quest counter on it. - this.addAbility(new LeavesBattlefieldTriggeredAbility(new YesManPersonalSecuritronLeavesEffect(), false)); + this.addAbility(new LeavesBattlefieldTriggeredAbility(new YesManPersonalSecuritronLeavesEffect()).withFlavorWord("Wild Card")); } private YesManPersonalSecuritron(final YesManPersonalSecuritron card) { @@ -61,6 +63,7 @@ public final class YesManPersonalSecuritron extends CardImpl { } class YesManPersonalSecuritronControlEffect extends TargetPlayerGainControlSourceEffect { + YesManPersonalSecuritronControlEffect() { super(); this.staticText = "Target opponent gains control of {this}. When they do, you draw two cards and put a quest counter on Yes Man."; @@ -91,6 +94,7 @@ class YesManPersonalSecuritronControlEffect extends TargetPlayerGainControlSourc } class YesManPersonalSecuritronLeavesEffect extends CreateTokenTargetEffect { + YesManPersonalSecuritronLeavesEffect() { super(new SoldierToken(), new CountersSourceCount(CounterType.QUEST), true); this.staticText = "its owner creates a tapped 1/1 white Soldier creature token for each quest counter on it."; @@ -114,4 +118,4 @@ class YesManPersonalSecuritronLeavesEffect extends CreateTokenTargetEffect { this.setTargetPointer(new FixedTarget(yesman.getOwnerId())); return super.apply(game, source); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/y/YomijiWhoBarsTheWay.java b/Mage.Sets/src/mage/cards/y/YomijiWhoBarsTheWay.java index b53b439c8ed..46872a1216f 100644 --- a/Mage.Sets/src/mage/cards/y/YomijiWhoBarsTheWay.java +++ b/Mage.Sets/src/mage/cards/y/YomijiWhoBarsTheWay.java @@ -1,7 +1,6 @@ package mage.cards.y; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.PutIntoGraveFromBattlefieldAllTriggeredAbility; import mage.abilities.effects.Effect; @@ -14,14 +13,21 @@ import mage.constants.SuperType; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class YomijiWhoBarsTheWay extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent("a legendary permanent other than {this}"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(SuperType.LEGENDARY.getPredicate()); + } public YomijiWhoBarsTheWay(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}{W}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.SPIRIT); @@ -29,11 +35,7 @@ public final class YomijiWhoBarsTheWay extends CardImpl { this.toughness = new MageInt(4); // Whenever a legendary permanent other than Yomiji, Who Bars the Way is put into a graveyard from the battlefield, return that card to its owner's hand. - FilterPermanent filter = new FilterPermanent("a legendary permanent other than " + getName()); - filter.add(AnotherPredicate.instance); - filter.add(SuperType.LEGENDARY.getPredicate()); - Effect effect = new ReturnToHandTargetEffect(); - effect.setText("return that card to its owner's hand"); + Effect effect = new ReturnToHandTargetEffect().setText("return that card to its owner's hand"); this.addAbility(new PutIntoGraveFromBattlefieldAllTriggeredAbility(effect, false, filter, true)); } diff --git a/Mage.Sets/src/mage/cards/y/YshtolaNightsBlessed.java b/Mage.Sets/src/mage/cards/y/YshtolaNightsBlessed.java index d3e1214ef55..835f8223562 100644 --- a/Mage.Sets/src/mage/cards/y/YshtolaNightsBlessed.java +++ b/Mage.Sets/src/mage/cards/y/YshtolaNightsBlessed.java @@ -1,28 +1,28 @@ package mage.cards.y; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.hint.ConditionHint; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.constants.*; +import mage.abilities.hint.Hint; import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.*; import mage.filter.FilterSpell; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.watchers.common.PlayerLostLifeWatcher; +import java.util.UUID; + /** - * * @author inuenc */ public final class YshtolaNightsBlessed extends CardImpl { @@ -36,7 +36,7 @@ public final class YshtolaNightsBlessed extends CardImpl { public YshtolaNightsBlessed(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}{B}"); - + this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.CAT); this.subtype.add(SubType.WARLOCK); @@ -47,22 +47,16 @@ public final class YshtolaNightsBlessed extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // At the beginning of each end step, if a player lost 4 or more life this turn, you draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfEndStepTriggeredAbility( - TargetController.ANY, - new DrawCardSourceControllerEffect(1), - false - ), YshtolaNightsBlessedCondition.instance, "At the beginning of each end step, " + - "if a player lost 4 or more life this turn, you draw a card." - ).addHint(new ConditionHint(YshtolaNightsBlessedCondition.instance, "A player lost 4 or more life this turn"))); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.ANY, new DrawCardSourceControllerEffect(1, true), + false, YshtolaNightsBlessedCondition.instance + ).addHint(YshtolaNightsBlessedCondition.getHint())); // Whenever you cast a noncreature spell with mana value 3 or greater, Y'shtola deals 2 damage to each opponent and you gain 2 life. Ability ability = new SpellCastControllerTriggeredAbility( - new DamagePlayersEffect( - 2, TargetController.OPPONENT, "Y'shtola"), - filter, false + new DamagePlayersEffect(2, TargetController.OPPONENT), filter, false ); - ability.addEffect(new GainLifeEffect(2).setText("and you gain 2 life")); + ability.addEffect(new GainLifeEffect(2).concatBy("and")); this.addAbility(ability); } @@ -78,6 +72,11 @@ public final class YshtolaNightsBlessed extends CardImpl { enum YshtolaNightsBlessedCondition implements Condition { instance; + private static final Hint hint = new ConditionHint(instance); + + public static Hint getHint() { + return hint; + } @Override public boolean apply(Game game, Ability source) { @@ -85,10 +84,16 @@ enum YshtolaNightsBlessedCondition implements Condition { if (watcher == null) { return false; } - return game + return watcher != null + && game .getState() .getPlayersInRange(source.getControllerId(), game) .stream() - .anyMatch(uuid -> watcher.getLifeLost(uuid) > 3); + .anyMatch(uuid -> watcher.getLifeLost(uuid) >= 4); + } + + @Override + public String toString() { + return "a player lost 4 or more life this turn"; } } diff --git a/Mage.Sets/src/mage/cards/z/ZacamaPrimalCalamity.java b/Mage.Sets/src/mage/cards/z/ZacamaPrimalCalamity.java index c5ffe9fe2a6..7f60af05f18 100644 --- a/Mage.Sets/src/mage/cards/z/ZacamaPrimalCalamity.java +++ b/Mage.Sets/src/mage/cards/z/ZacamaPrimalCalamity.java @@ -1,14 +1,11 @@ - package mage.cards.z; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.GainLifeEffect; @@ -21,13 +18,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ZacamaPrimalCalamity extends CardImpl { @@ -51,10 +48,8 @@ public final class ZacamaPrimalCalamity extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // When Zacama, Primal Calamity enters the battlefield, if you cast it, untap all lands you control. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new UntapAllLandsControllerEffect(), false), - CastFromEverywhereSourceCondition.instance, - "When {this} enters, if you cast it, untap all lands you control.")); + this.addAbility(new EntersBattlefieldTriggeredAbility(new UntapAllLandsControllerEffect()) + .withInterveningIf(CastFromEverywhereSourceCondition.instance)); // {2}{R}: Zacama deals 3 damage to target creature. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(3), new ManaCostsImpl<>("{2}{R}")); diff --git a/Mage.Sets/src/mage/cards/z/ZackFair.java b/Mage.Sets/src/mage/cards/z/ZackFair.java index 96ee7515874..af99fd6f41c 100644 --- a/Mage.Sets/src/mage/cards/z/ZackFair.java +++ b/Mage.Sets/src/mage/cards/z/ZackFair.java @@ -20,8 +20,7 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.counters.CounterType; import mage.filter.FilterPermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate; import mage.game.Controllable; import mage.game.Game; import mage.game.permanent.Permanent; @@ -117,13 +116,7 @@ class ZackFairEffect extends OneShotEffect { FilterPermanent filter = new FilterPermanent( SubType.EQUIPMENT, "Equipment to attach to " + creature.getIdName() ); - filter.add(Predicates.or( - permanents - .stream() - .map(MageItem::getId) - .map(PermanentIdPredicate::new) - .collect(Collectors.toList()) - )); + filter.add(new PermanentReferenceInCollectionPredicate(permanents, game)); TargetPermanent target = new TargetPermanent(filter); target.withNotTarget(true); Optional.ofNullable(source) diff --git a/Mage.Sets/src/mage/cards/z/ZaskSkitteringSwarmlord.java b/Mage.Sets/src/mage/cards/z/ZaskSkitteringSwarmlord.java index 856abc25f6e..92206d080d9 100644 --- a/Mage.Sets/src/mage/cards/z/ZaskSkitteringSwarmlord.java +++ b/Mage.Sets/src/mage/cards/z/ZaskSkitteringSwarmlord.java @@ -18,6 +18,7 @@ import mage.filter.FilterCard; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -65,7 +66,7 @@ public final class ZaskSkitteringSwarmlord extends CardImpl { ); ability2.addEffect(new GainAbilityTargetEffect(DeathtouchAbility.getInstance(), Duration.EndOfTurn) .setText(" and gains deathtouch until end of turn")); - ability2.addTarget(new TargetCreaturePermanent(filter3)); + ability2.addTarget(new TargetPermanent(filter3)); this.addAbility(ability2); } diff --git a/Mage.Sets/src/mage/cards/z/ZealotsEnDal.java b/Mage.Sets/src/mage/cards/z/ZealotsEnDal.java index 714cc57e277..8da0251b702 100644 --- a/Mage.Sets/src/mage/cards/z/ZealotsEnDal.java +++ b/Mage.Sets/src/mage/cards/z/ZealotsEnDal.java @@ -1,35 +1,38 @@ package mage.cards.z; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; -import mage.constants.SubType; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class ZealotsEnDal extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent(); + private static final FilterPermanent filter = new FilterControlledPermanent("all nonland permanents you control are white"); static { filter.add(Predicates.not(new ColorPredicate(ObjectColor.WHITE))); filter.add(Predicates.not(CardType.LAND.getPredicate())); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0); + public ZealotsEnDal(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); @@ -39,11 +42,7 @@ public final class ZealotsEnDal extends CardImpl { this.toughness = new MageInt(4); // At the beginning of your upkeep, if all nonland permanents you control are white, you gain 1 life. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(new GainLifeEffect(1)), - new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)), - "At the beginning of your upkeep, if all nonland permanents you control are white, you gain 1 life." - )); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new GainLifeEffect(1)).withInterveningIf(condition)); } private ZealotsEnDal(final ZealotsEnDal card) { diff --git a/Mage.Sets/src/mage/cards/z/ZeganaUtopianSpeaker.java b/Mage.Sets/src/mage/cards/z/ZeganaUtopianSpeaker.java index 220c79c1331..c29b1afdb59 100644 --- a/Mage.Sets/src/mage/cards/z/ZeganaUtopianSpeaker.java +++ b/Mage.Sets/src/mage/cards/z/ZeganaUtopianSpeaker.java @@ -3,16 +3,23 @@ package mage.cards.z; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.keyword.AdaptAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; import java.util.UUID; @@ -21,6 +28,15 @@ import java.util.UUID; */ public final class ZeganaUtopianSpeaker extends CardImpl { + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("you control another creature with a +1/+1 counter on it"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(CounterType.P1P1.getPredicate()); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + public ZeganaUtopianSpeaker(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); @@ -31,26 +47,16 @@ public final class ZeganaUtopianSpeaker extends CardImpl { this.toughness = new MageInt(4); // When Zegana, Utopian Speaker enters the battlefield, if you control another creature with a +1/+1 counter on it, draw a card. - this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility( - new DrawCardSourceControllerEffect(1), false - ), new PermanentsOnTheBattlefieldCondition(StaticFilters.FILTER_OTHER_CONTROLLED_CREATURE_P1P1), - "When {this} enters, " + - "if you control another creature " + - "with a +1/+1 counter on it, draw a card." - ) - ); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)).withInterveningIf(condition)); // {4}{G}{U}: Adapt 4. this.addAbility(new AdaptAbility(4, "{4}{G}{U}")); // Each creature you control with a +1/+1 counter on it has trample. - this.addAbility(new SimpleStaticAbility( - new GainAbilityAllEffect( - TrampleAbility.getInstance(), Duration.WhileOnBattlefield, - StaticFilters.FILTER_EACH_CONTROLLED_CREATURE_P1P1) - ) - ); + this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( + TrampleAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_EACH_CONTROLLED_CREATURE_P1P1 + ))); } private ZeganaUtopianSpeaker(final ZeganaUtopianSpeaker card) { diff --git a/Mage.Sets/src/mage/cards/z/ZephyrSentinel.java b/Mage.Sets/src/mage/cards/z/ZephyrSentinel.java index d0d6d54b835..bec1a7bba71 100644 --- a/Mage.Sets/src/mage/cards/z/ZephyrSentinel.java +++ b/Mage.Sets/src/mage/cards/z/ZephyrSentinel.java @@ -17,8 +17,9 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; +import java.util.Optional; import java.util.UUID; /** @@ -42,7 +43,7 @@ public final class ZephyrSentinel extends CardImpl { // When Zephyr Sentinel enters the battlefield, return up to one other target creature you control to its owner's hand. If it was a Soldier, put a +1/+1 counter on Zephyr Sentinel. Ability ability = new EntersBattlefieldTriggeredAbility(new ZephyrSentinelEffect()); - ability.addTarget(new TargetControlledCreaturePermanent(0, 1, StaticFilters.FILTER_OTHER_CONTROLLED_CREATURE, false)); + ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_OTHER_CONTROLLED_CREATURE)); this.addAbility(ability); } @@ -74,21 +75,16 @@ class ZephyrSentinelEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent targetPermanent = game.getPermanent(source.getFirstTarget()); - if (targetPermanent == null) { - return false; - } Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { + Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (controller == null || targetPermanent == null) { return false; } boolean soldier = targetPermanent.hasSubtype(SubType.SOLDIER, game); controller.moveCards(targetPermanent, Zone.HAND, source, game); if (soldier) { - Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); - if (sourcePermanent != null) { - sourcePermanent.addCounters(CounterType.P1P1.createInstance(), source, game); - } + Optional.ofNullable(source.getSourcePermanentIfItStillExists(game)) + .ifPresent(permanent -> permanent.addCounters(CounterType.P1P1.createInstance(), source, game)); } return true; } diff --git a/Mage.Sets/src/mage/cards/z/ZhalfirinCommander.java b/Mage.Sets/src/mage/cards/z/ZhalfirinCommander.java index 516b3c24a85..e22f33026ba 100644 --- a/Mage.Sets/src/mage/cards/z/ZhalfirinCommander.java +++ b/Mage.Sets/src/mage/cards/z/ZhalfirinCommander.java @@ -15,6 +15,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -40,7 +41,7 @@ public final class ZhalfirinCommander extends CardImpl { this.addAbility(new FlankingAbility()); // {1}{W}{W}: Target Knight creature gets +1/+1 until end of turn. Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(1, 1, Duration.EndOfTurn), new ManaCostsImpl<>("{1}{W}{W}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/z/ZhalfirinDecoy.java b/Mage.Sets/src/mage/cards/z/ZhalfirinDecoy.java index 9b7aa396539..eb088f1ec36 100644 --- a/Mage.Sets/src/mage/cards/z/ZhalfirinDecoy.java +++ b/Mage.Sets/src/mage/cards/z/ZhalfirinDecoy.java @@ -10,7 +10,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; import mage.watchers.common.CreatureEnteredControllerWatcher; @@ -32,8 +31,7 @@ public final class ZhalfirinDecoy extends CardImpl { // {T}: Tap target creature. Activate this ability only if you had a creature enter the battlefield under your control this turn. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new TapTargetEffect(), - new TapSourceCost(), ZhalfirinDecoyCondition.instance + new TapTargetEffect(), new TapSourceCost(), ZhalfirinDecoyCondition.instance ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability, new CreatureEnteredControllerWatcher()); diff --git a/Mage.Sets/src/mage/cards/z/ZhugeJinWuStrategist.java b/Mage.Sets/src/mage/cards/z/ZhugeJinWuStrategist.java index ef546c171d6..e3ba7d435a0 100644 --- a/Mage.Sets/src/mage/cards/z/ZhugeJinWuStrategist.java +++ b/Mage.Sets/src/mage/cards/z/ZhugeJinWuStrategist.java @@ -1,7 +1,5 @@ - package mage.cards.z; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -10,17 +8,21 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class ZhugeJinWuStrategist extends CardImpl { public ZhugeJinWuStrategist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN, SubType.ADVISOR); @@ -28,8 +30,10 @@ public final class ZhugeJinWuStrategist extends CardImpl { this.toughness = new MageInt(1); // {tap}: Target creature can't be blocked this turn. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new CantBeBlockedTargetEffect(Duration.EndOfTurn), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new CantBeBlockedTargetEffect(Duration.EndOfTurn), new TapSourceCost(), + MyTurnBeforeAttackersDeclaredCondition.instance + ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/z/ZimoneParadoxSculptor.java b/Mage.Sets/src/mage/cards/z/ZimoneParadoxSculptor.java index 5f5ce39c441..2f5c267e606 100644 --- a/Mage.Sets/src/mage/cards/z/ZimoneParadoxSculptor.java +++ b/Mage.Sets/src/mage/cards/z/ZimoneParadoxSculptor.java @@ -17,30 +17,24 @@ import mage.constants.SuperType; import mage.counters.Counter; import mage.counters.CounterType; import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.Target; import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; /** - * * @author ciaccona007 */ public final class ZimoneParadoxSculptor extends CardImpl { - private static final FilterControlledCreaturePermanent filterCreature = new FilterControlledCreaturePermanent(); - private static final FilterPermanent filterArtifactOrCreature = new FilterControlledPermanent(); + private static final FilterPermanent filter = new FilterControlledPermanent("up to two artifacts and/or creatures you control"); static { - filterCreature.setMessage("up to two creatures you control"); - filterArtifactOrCreature.setMessage("up to two artifacts and/or creatures you control"); - filterArtifactOrCreature.add(Predicates.or( + filter.add(Predicates.or( CardType.ARTIFACT.getPredicate(), CardType.CREATURE.getPredicate() )); @@ -48,7 +42,7 @@ public final class ZimoneParadoxSculptor extends CardImpl { public ZimoneParadoxSculptor(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); - + this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); @@ -57,19 +51,15 @@ public final class ZimoneParadoxSculptor extends CardImpl { // At the beginning of combat on your turn, put a +1/+1 counter on each of up to two target creatures you control. Ability triggeredAbility = new BeginningOfCombatTriggeredAbility( - new AddCountersTargetEffect( - CounterType.P1P1.createInstance() - ).setText("put a +1/+1 counter on each of up to two target creatures you control") - ); - triggeredAbility.addTarget( - new TargetControlledCreaturePermanent(0, 2, filterCreature, false) + new AddCountersTargetEffect(CounterType.P1P1.createInstance()) ); + triggeredAbility.addTarget(new TargetControlledCreaturePermanent(0, 2)); this.addAbility(triggeredAbility); // {G}{U}, {T}: Double the number of each kind of counter on up to two target creatures and/or artifacts you control. Ability ability = new SimpleActivatedAbility(new ZimoneParadoxSculptorEffect(), new ManaCostsImpl<>("{G}{U}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetPermanent(0, 2, filterArtifactOrCreature)); + ability.addTarget(new TargetPermanent(0, 2, filter)); this.addAbility(ability); } @@ -102,20 +92,16 @@ class ZimoneParadoxSculptorEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - boolean didOne = false; - - for (Target target : source.getTargets()) { - for (UUID targetID : target.getTargets()) { - Permanent permanent = game.getPermanent(targetID); - if (permanent != null) { - for (Counter counter : permanent.getCounters(game).values()) { - Counter newCounter = new Counter(counter.getName(), counter.getCount()); - permanent.addCounters(newCounter, source.getControllerId(), source, game); - didOne = true; - } - } + for (UUID targetId : getTargetPointer().getTargets(game, source)) { + Permanent permanent = game.getPermanent(targetId); + if (permanent == null) { + continue; + } + for (Counter counter : permanent.getCounters(game).values()) { + Counter newCounter = new Counter(counter.getName(), counter.getCount()); + permanent.addCounters(newCounter, source.getControllerId(), source, game); } } - return didOne; + return true; } } diff --git a/Mage.Sets/src/mage/cards/z/ZndrspltsJudgment.java b/Mage.Sets/src/mage/cards/z/ZndrspltsJudgment.java index 7d894bfaee6..0ae82739bea 100644 --- a/Mage.Sets/src/mage/cards/z/ZndrspltsJudgment.java +++ b/Mage.Sets/src/mage/cards/z/ZndrspltsJudgment.java @@ -1,7 +1,5 @@ - package mage.cards.z; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -16,11 +14,12 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class ZndrspltsJudgment extends CardImpl { @@ -72,7 +71,8 @@ class ZndrspltsJudgmentEffect extends OneShotEffect { } FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); filter.add(new ControllerIdPredicate(player.getId())); - TargetCreaturePermanent target = new TargetCreaturePermanent(1, 1, filter, true); + TargetPermanent target = new TargetPermanent(filter); + target.withNotTarget(true); if (!player.choose(Outcome.Copy, target, source, game)) { continue; } @@ -83,7 +83,8 @@ class ZndrspltsJudgmentEffect extends OneShotEffect { for (Player player : choice.getFoes()) { FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); filter.add(new ControllerIdPredicate(player.getId())); - TargetCreaturePermanent target = new TargetCreaturePermanent(1, 1, filter, true); + TargetPermanent target = new TargetPermanent(filter); + target.withNotTarget(true); if (!player.choose(Outcome.ReturnToHand, target, source, game)) { continue; } diff --git a/Mage.Sets/src/mage/cards/z/ZoZuThePunisher.java b/Mage.Sets/src/mage/cards/z/ZoZuThePunisher.java index bd57de814ad..1e66dfdc67e 100644 --- a/Mage.Sets/src/mage/cards/z/ZoZuThePunisher.java +++ b/Mage.Sets/src/mage/cards/z/ZoZuThePunisher.java @@ -1,7 +1,6 @@ package mage.cards.z; -import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; @@ -18,6 +17,8 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** * * @author LevelX @@ -82,6 +83,6 @@ class ZoZuThePunisherAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever a land enters the battlefield, Zo-Zu the Punisher deals 2 damage to that land's controller."; + return "Whenever a land enters the battlefield, {this} deals 2 damage to that land's controller."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/z/ZombieAssassin.java b/Mage.Sets/src/mage/cards/z/ZombieAssassin.java index d5ef339caf1..4fea3ce2bf8 100644 --- a/Mage.Sets/src/mage/cards/z/ZombieAssassin.java +++ b/Mage.Sets/src/mage/cards/z/ZombieAssassin.java @@ -15,9 +15,12 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.StaticFilters; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCreaturePermanent; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK; + /** * * @author cbt33 @@ -33,7 +36,7 @@ public final class ZombieAssassin extends CardImpl { // {tap}, Exile two cards from your graveyard and Zombie Assassin: Destroy target nonblack creature. It can't be regenerated. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(true), new TapSourceCost()); - Target target = new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK); + Target target = new TargetPermanent(FILTER_PERMANENT_CREATURE_NON_BLACK); ability.addTarget(target); ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(2,2,StaticFilters.FILTER_CARDS_FROM_YOUR_GRAVEYARD))); ability.addCost(new ExileSourceCost()); diff --git a/Mage.Sets/src/mage/cards/z/ZuranEnchanter.java b/Mage.Sets/src/mage/cards/z/ZuranEnchanter.java index e9dccf2d273..c63633158a5 100644 --- a/Mage.Sets/src/mage/cards/z/ZuranEnchanter.java +++ b/Mage.Sets/src/mage/cards/z/ZuranEnchanter.java @@ -7,12 +7,10 @@ import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.discard.DiscardTargetEffect; -import mage.abilities.hint.common.MyTurnHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.target.TargetPlayer; import java.util.UUID; @@ -29,10 +27,11 @@ public final class ZuranEnchanter extends CardImpl { this.toughness = new MageInt(1); // {2}{B}, {T}: Target player discards a card. Activate this ability only during your turn. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new DiscardTargetEffect(1), new ManaCostsImpl<>("{2}{B}"), MyTurnCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + new DiscardTargetEffect(1), new ManaCostsImpl<>("{2}{B}"), MyTurnCondition.instance + ); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetPlayer()); - ability.addHint(MyTurnHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/AvatarTheLastAirbender.java b/Mage.Sets/src/mage/sets/AvatarTheLastAirbender.java new file mode 100644 index 00000000000..4cfe962a30a --- /dev/null +++ b/Mage.Sets/src/mage/sets/AvatarTheLastAirbender.java @@ -0,0 +1,23 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.SetType; + +/** + * @author TheElk801 + */ +public final class AvatarTheLastAirbender extends ExpansionSet { + + private static final AvatarTheLastAirbender instance = new AvatarTheLastAirbender(); + + public static AvatarTheLastAirbender getInstance() { + return instance; + } + + private AvatarTheLastAirbender() { + super("Avatar: The Last Airbender", "TLA", ExpansionSet.buildDate(2025, 11, 21), SetType.EXPANSION); + this.blockName = "Avatar: The Last Airbender"; // for sorting in GUI + this.rotationSet = true; + this.hasBasicLands = false; // temporary + } +} diff --git a/Mage.Sets/src/mage/sets/BloomburrowCommander.java b/Mage.Sets/src/mage/sets/BloomburrowCommander.java index 854ec0853ea..cf26ee2d650 100644 --- a/Mage.Sets/src/mage/sets/BloomburrowCommander.java +++ b/Mage.Sets/src/mage/sets/BloomburrowCommander.java @@ -93,6 +93,7 @@ public final class BloomburrowCommander extends ExpansionSet { cards.add(new SetCardInfo("Devilish Valet", 195, Rarity.RARE, mage.cards.d.DevilishValet.class)); cards.add(new SetCardInfo("Domri, Anarch of Bolas", 98, Rarity.RARE, mage.cards.d.DomriAnarchOfBolas.class)); cards.add(new SetCardInfo("Dusk // Dawn", 138, Rarity.RARE, mage.cards.d.DuskDawn.class)); + cards.add(new SetCardInfo("Echoing Assault", 24, Rarity.RARE, mage.cards.e.EchoingAssault.class)); cards.add(new SetCardInfo("Elspeth, Sun's Champion", 97, Rarity.MYTHIC, mage.cards.e.ElspethSunsChampion.class)); cards.add(new SetCardInfo("End-Raze Forerunners", 214, Rarity.RARE, mage.cards.e.EndRazeForerunners.class)); cards.add(new SetCardInfo("Esika's Chariot", 215, Rarity.RARE, mage.cards.e.EsikasChariot.class)); diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 18abe25f7d0..481c8062516 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -142,6 +142,8 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Get Out", 60, Rarity.UNCOMMON, mage.cards.g.GetOut.class)); cards.add(new SetCardInfo("Ghost Vacuum", 248, Rarity.RARE, mage.cards.g.GhostVacuum.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ghost Vacuum", 326, Rarity.RARE, mage.cards.g.GhostVacuum.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ghostly Dancers", 13, Rarity.RARE, mage.cards.g.GhostlyDancers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ghostly Dancers", 302, Rarity.RARE, mage.cards.g.GhostlyDancers.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Give In to Violence", 101, Rarity.COMMON, mage.cards.g.GiveInToViolence.class)); cards.add(new SetCardInfo("Glimmer Seeker", 14, Rarity.UNCOMMON, mage.cards.g.GlimmerSeeker.class)); cards.add(new SetCardInfo("Glimmerburst", 62, Rarity.COMMON, mage.cards.g.Glimmerburst.class)); diff --git a/Mage.Sets/src/mage/sets/EdgeOfEternities.java b/Mage.Sets/src/mage/sets/EdgeOfEternities.java new file mode 100644 index 00000000000..2f65792fbee --- /dev/null +++ b/Mage.Sets/src/mage/sets/EdgeOfEternities.java @@ -0,0 +1,123 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +import java.util.Arrays; +import java.util.List; + +/** + * @author TheElk801 + */ +public final class EdgeOfEternities extends ExpansionSet { + + private static final List unfinished = Arrays.asList("Anticausal Vestige", "Astelli Reclaimer", "Bygone Colossus", "Eusocial Engineering", "Exalted Sunborn", "Haliya, Guided by Light", "Mechanozoa", "Nova Hellkite", "Quantum Riddler", "Red Tiger Mechan", "Starbreach Whale", "Starfield Shepherd", "Starfield Vocalist", "Timeline Culler", "Weftstalker Ardent"); + private static final EdgeOfEternities instance = new EdgeOfEternities(); + + public static EdgeOfEternities getInstance() { + return instance; + } + + private EdgeOfEternities() { + super("Edge of Eternities", "EOE", ExpansionSet.buildDate(2025, 8, 1), SetType.EXPANSION); + this.blockName = "Edge of Eternities"; // for sorting in GUI + this.rotationSet = true; + + cards.add(new SetCardInfo("Alpharael, Dreaming Acolyte", 212, Rarity.UNCOMMON, mage.cards.a.AlpharaelDreamingAcolyte.class)); + cards.add(new SetCardInfo("Anticausal Vestige", 1, Rarity.RARE, mage.cards.a.AnticausalVestige.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Anticausal Vestige", 317, Rarity.RARE, mage.cards.a.AnticausalVestige.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Anticausal Vestige", 357, Rarity.MYTHIC, mage.cards.a.AnticausalVestige.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Anticausal Vestige", 383, Rarity.RARE, mage.cards.a.AnticausalVestige.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Banishing Light", 6, Rarity.COMMON, mage.cards.b.BanishingLight.class)); + cards.add(new SetCardInfo("Biotech Specialist", 214, Rarity.RARE, mage.cards.b.BiotechSpecialist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Biotech Specialist", 347, Rarity.RARE, mage.cards.b.BiotechSpecialist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Breeding Pool", 251, Rarity.RARE, mage.cards.b.BreedingPool.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Breeding Pool", 278, Rarity.RARE, mage.cards.b.BreedingPool.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Breeding Pool", 373, Rarity.RARE, mage.cards.b.BreedingPool.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Bygone Colossus", 235, Rarity.UNCOMMON, mage.cards.b.BygoneColossus.class)); + cards.add(new SetCardInfo("Command Bridge", 252, Rarity.COMMON, mage.cards.c.CommandBridge.class)); + cards.add(new SetCardInfo("Decode Transmissions", 94, Rarity.COMMON, mage.cards.d.DecodeTransmissions.class)); + cards.add(new SetCardInfo("Embrace Oblivion", 98, Rarity.COMMON, mage.cards.e.EmbraceOblivion.class)); + cards.add(new SetCardInfo("Emergency Eject", 14, Rarity.UNCOMMON, mage.cards.e.EmergencyEject.class)); + cards.add(new SetCardInfo("Emissary Escort", 326, Rarity.RARE, mage.cards.e.EmissaryEscort.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Emissary Escort", 399, Rarity.RARE, mage.cards.e.EmissaryEscort.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Emissary Escort", 56, Rarity.RARE, mage.cards.e.EmissaryEscort.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Eusocial Engineering", 181, Rarity.UNCOMMON, mage.cards.e.EusocialEngineering.class)); + cards.add(new SetCardInfo("Exalted Sunborn", 15, Rarity.MYTHIC, mage.cards.e.ExaltedSunborn.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Exalted Sunborn", 318, Rarity.MYTHIC, mage.cards.e.ExaltedSunborn.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Exalted Sunborn", 358, Rarity.MYTHIC, mage.cards.e.ExaltedSunborn.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Exalted Sunborn", 384, Rarity.MYTHIC, mage.cards.e.ExaltedSunborn.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 266, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Forest", 275, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 276, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 371, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Galactic Wayfarer", 185, Rarity.COMMON, mage.cards.g.GalacticWayfarer.class)); + cards.add(new SetCardInfo("Godless Shrine", 254, Rarity.RARE, mage.cards.g.GodlessShrine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Godless Shrine", 280, Rarity.RARE, mage.cards.g.GodlessShrine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Godless Shrine", 375, Rarity.RARE, mage.cards.g.GodlessShrine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Harmonious Grovestrider", 189, Rarity.UNCOMMON, mage.cards.h.HarmoniousGrovestrider.class)); + cards.add(new SetCardInfo("Insatiable Skittermaw", 108, Rarity.COMMON, mage.cards.i.InsatiableSkittermaw.class)); + cards.add(new SetCardInfo("Island", 263, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Island", 269, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 270, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 368, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Mechanozoa", 66, Rarity.COMMON, mage.cards.m.Mechanozoa.class)); + cards.add(new SetCardInfo("Mountain", 265, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 273, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 274, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 370, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Nova Hellkite", 148, Rarity.RARE, mage.cards.n.NovaHellkite.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nova Hellkite", 309, Rarity.RARE, mage.cards.n.NovaHellkite.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ouroboroid", 201, Rarity.MYTHIC, mage.cards.o.Ouroboroid.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ouroboroid", 345, Rarity.MYTHIC, mage.cards.o.Ouroboroid.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 262, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Plains", 267, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 268, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 367, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Red Tiger Mechan", 154, Rarity.COMMON, mage.cards.r.RedTigerMechan.class)); + cards.add(new SetCardInfo("Sacred Foundry", 256, Rarity.RARE, mage.cards.s.SacredFoundry.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sacred Foundry", 282, Rarity.RARE, mage.cards.s.SacredFoundry.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sacred Foundry", 377, Rarity.RARE, mage.cards.s.SacredFoundry.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sami, Ship's Engineer", 225, Rarity.UNCOMMON, mage.cards.s.SamiShipsEngineer.class)); + cards.add(new SetCardInfo("Shattered Wings", 206, Rarity.COMMON, mage.cards.s.ShatteredWings.class)); + cards.add(new SetCardInfo("Singularity Rupture", 228, Rarity.RARE, mage.cards.s.SingularityRupture.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Singularity Rupture", 350, Rarity.RARE, mage.cards.s.SingularityRupture.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Singularity Rupture", 398, Rarity.RARE, mage.cards.s.SingularityRupture.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sothera, the Supervoid", 115, Rarity.MYTHIC, mage.cards.s.SotheraTheSupervoid.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sothera, the Supervoid", 360, Rarity.MYTHIC, mage.cards.s.SotheraTheSupervoid.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sothera, the Supervoid", 382, Rarity.MYTHIC, mage.cards.s.SotheraTheSupervoid.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sothera, the Supervoid", 386, Rarity.MYTHIC, mage.cards.s.SotheraTheSupervoid.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Starbreach Whale", 77, Rarity.COMMON, mage.cards.s.StarbreachWhale.class)); + cards.add(new SetCardInfo("Starfighter Pilot", 38, Rarity.COMMON, mage.cards.s.StarfighterPilot.class)); + cards.add(new SetCardInfo("Stomping Ground", 258, Rarity.RARE, mage.cards.s.StompingGround.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Stomping Ground", 283, Rarity.RARE, mage.cards.s.StompingGround.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Stomping Ground", 378, Rarity.RARE, mage.cards.s.StompingGround.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sunset Saboteur", 116, Rarity.RARE, mage.cards.s.SunsetSaboteur.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sunset Saboteur", 334, Rarity.RARE, mage.cards.s.SunsetSaboteur.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 264, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 271, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 272, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 369, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Tannuk, Memorial Ensign", 233, Rarity.UNCOMMON, mage.cards.t.TannukMemorialEnsign.class)); + cards.add(new SetCardInfo("Temporal Intervention", 120, Rarity.COMMON, mage.cards.t.TemporalIntervention.class)); + cards.add(new SetCardInfo("Tezzeret, Cruel Captain", 2, Rarity.MYTHIC, mage.cards.t.TezzeretCruelCaptain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tezzeret, Cruel Captain", 287, Rarity.MYTHIC, mage.cards.t.TezzeretCruelCaptain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Seriema", 323, Rarity.RARE, mage.cards.t.TheSeriema.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Seriema", 35, Rarity.RARE, mage.cards.t.TheSeriema.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Thrumming Hivepool", 247, Rarity.RARE, mage.cards.t.ThrummingHivepool.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Thrumming Hivepool", 356, Rarity.RARE, mage.cards.t.ThrummingHivepool.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tragic Trajectory", 122, Rarity.UNCOMMON, mage.cards.t.TragicTrajectory.class)); + cards.add(new SetCardInfo("Uthros, Titanic Godcore", 260, Rarity.MYTHIC, mage.cards.u.UthrosTitanicGodcore.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Uthros, Titanic Godcore", 285, Rarity.MYTHIC, mage.cards.u.UthrosTitanicGodcore.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Uthros, Titanic Godcore", 380, Rarity.MYTHIC, mage.cards.u.UthrosTitanicGodcore.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Virulent Silencer", 248, Rarity.UNCOMMON, mage.cards.v.VirulentSilencer.class)); + cards.add(new SetCardInfo("Voidforged Titan", 125, Rarity.UNCOMMON, mage.cards.v.VoidforgedTitan.class)); + cards.add(new SetCardInfo("Watery Grave", 261, Rarity.RARE, mage.cards.w.WateryGrave.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Watery Grave", 286, Rarity.RARE, mage.cards.w.WateryGrave.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Watery Grave", 381, Rarity.RARE, mage.cards.w.WateryGrave.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wurmwall Sweeper", 249, Rarity.COMMON, mage.cards.w.WurmwallSweeper.class)); + + cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName())); + } +} diff --git a/Mage.Sets/src/mage/sets/EdgeOfEternitiesCommander.java b/Mage.Sets/src/mage/sets/EdgeOfEternitiesCommander.java new file mode 100644 index 00000000000..4b361a8935a --- /dev/null +++ b/Mage.Sets/src/mage/sets/EdgeOfEternitiesCommander.java @@ -0,0 +1,25 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author TheElk801 + */ +public final class EdgeOfEternitiesCommander extends ExpansionSet { + + private static final EdgeOfEternitiesCommander instance = new EdgeOfEternitiesCommander(); + + public static EdgeOfEternitiesCommander getInstance() { + return instance; + } + + private EdgeOfEternitiesCommander() { + super("Edge of Eternities Commander", "EOC", ExpansionSet.buildDate(2025, 8, 1), SetType.SUPPLEMENTAL); + this.hasBasicLands = false; + + cards.add(new SetCardInfo("Kilo, Apogee Mind", 3, Rarity.MYTHIC, mage.cards.k.KiloApogeeMind.class)); + cards.add(new SetCardInfo("Szarel, Genesis Shepherd", 4, Rarity.MYTHIC, mage.cards.s.SzarelGenesisShepherd.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/Fallout.java b/Mage.Sets/src/mage/sets/Fallout.java index 0cf9a4160b3..e2e92d8770e 100644 --- a/Mage.Sets/src/mage/sets/Fallout.java +++ b/Mage.Sets/src/mage/sets/Fallout.java @@ -430,10 +430,10 @@ public final class Fallout extends ExpansionSet { cards.add(new SetCardInfo("Intelligence Bobblehead", 1061, Rarity.UNCOMMON, mage.cards.i.IntelligenceBobblehead.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Intelligence Bobblehead", 134, Rarity.UNCOMMON, mage.cards.i.IntelligenceBobblehead.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Intelligence Bobblehead", 662, Rarity.UNCOMMON, mage.cards.i.IntelligenceBobblehead.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("Inventory Management", 105, Rarity.RARE, mage.cards.i.InventoryManagement.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("Inventory Management", 342, Rarity.RARE, mage.cards.i.InventoryManagement.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("Inventory Management", 633, Rarity.RARE, mage.cards.i.InventoryManagement.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("Inventory Management", 870, Rarity.RARE, mage.cards.i.InventoryManagement.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Inventory Management", 105, Rarity.RARE, mage.cards.i.InventoryManagement.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Inventory Management", 342, Rarity.RARE, mage.cards.i.InventoryManagement.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Inventory Management", 633, Rarity.RARE, mage.cards.i.InventoryManagement.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Inventory Management", 870, Rarity.RARE, mage.cards.i.InventoryManagement.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Irrigated Farmland", 1027, Rarity.RARE, mage.cards.i.IrrigatedFarmland.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Irrigated Farmland", 268, Rarity.RARE, mage.cards.i.IrrigatedFarmland.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Irrigated Farmland", 499, Rarity.RARE, mage.cards.i.IrrigatedFarmland.class, NON_FULL_USE_VARIOUS)); @@ -571,10 +571,10 @@ public final class Fallout extends ExpansionSet { cards.add(new SetCardInfo("Mutational Advantage", 950, Rarity.RARE, mage.cards.m.MutationalAdvantage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Myriad Landscape", 274, Rarity.UNCOMMON, mage.cards.m.MyriadLandscape.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Myriad Landscape", 802, Rarity.UNCOMMON, mage.cards.m.MyriadLandscape.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("Mysterious Stranger", 334, Rarity.RARE, mage.cards.m.MysteriousStranger.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("Mysterious Stranger", 591, Rarity.RARE, mage.cards.m.MysteriousStranger.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("Mysterious Stranger", 63, Rarity.RARE, mage.cards.m.MysteriousStranger.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("Mysterious Stranger", 862, Rarity.RARE, mage.cards.m.MysteriousStranger.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mysterious Stranger", 334, Rarity.RARE, mage.cards.m.MysteriousStranger.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mysterious Stranger", 591, Rarity.RARE, mage.cards.m.MysteriousStranger.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mysterious Stranger", 63, Rarity.RARE, mage.cards.m.MysteriousStranger.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mysterious Stranger", 862, Rarity.RARE, mage.cards.m.MysteriousStranger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mystic Forge", 1012, Rarity.RARE, mage.cards.m.MysticForge.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mystic Forge", 236, Rarity.RARE, mage.cards.m.MysticForge.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mystic Forge", 484, Rarity.RARE, mage.cards.m.MysticForge.class, NON_FULL_USE_VARIOUS)); @@ -603,10 +603,10 @@ public final class Fallout extends ExpansionSet { cards.add(new SetCardInfo("Nuka-Cola Vending Machine", 358, Rarity.UNCOMMON, mage.cards.n.NukaColaVendingMachine.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nuka-Cola Vending Machine", 665, Rarity.UNCOMMON, mage.cards.n.NukaColaVendingMachine.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nuka-Cola Vending Machine", 886, Rarity.UNCOMMON, mage.cards.n.NukaColaVendingMachine.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("Nuka-Nuke Launcher", 138, Rarity.RARE, mage.cards.n.NukaNukeLauncher.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("Nuka-Nuke Launcher", 434, Rarity.RARE, mage.cards.n.NukaNukeLauncher.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("Nuka-Nuke Launcher", 666, Rarity.RARE, mage.cards.n.NukaNukeLauncher.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("Nuka-Nuke Launcher", 962, Rarity.RARE, mage.cards.n.NukaNukeLauncher.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nuka-Nuke Launcher", 138, Rarity.RARE, mage.cards.n.NukaNukeLauncher.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nuka-Nuke Launcher", 434, Rarity.RARE, mage.cards.n.NukaNukeLauncher.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nuka-Nuke Launcher", 666, Rarity.RARE, mage.cards.n.NukaNukeLauncher.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nuka-Nuke Launcher", 962, Rarity.RARE, mage.cards.n.NukaNukeLauncher.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("One with the Machine", 179, Rarity.RARE, mage.cards.o.OneWithTheMachine.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("One with the Machine", 462, Rarity.RARE, mage.cards.o.OneWithTheMachine.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("One with the Machine", 707, Rarity.RARE, mage.cards.o.OneWithTheMachine.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/MediaAndCollaborationPromos.java b/Mage.Sets/src/mage/sets/MediaAndCollaborationPromos.java index 6b0c9612c26..b655cb8f7fc 100644 --- a/Mage.Sets/src/mage/sets/MediaAndCollaborationPromos.java +++ b/Mage.Sets/src/mage/sets/MediaAndCollaborationPromos.java @@ -33,7 +33,7 @@ public class MediaAndCollaborationPromos extends ExpansionSet { cards.add(new SetCardInfo("Chandra's Outrage", "2010-3", Rarity.COMMON, mage.cards.c.ChandrasOutrage.class)); cards.add(new SetCardInfo("Chandra's Spitfire", "2010-4", Rarity.UNCOMMON, mage.cards.c.ChandrasSpitfire.class)); cards.add(new SetCardInfo("Counterspell", "2021-1", Rarity.RARE, mage.cards.c.Counterspell.class)); - cards.add(new SetCardInfo("Crop Rotation", "2020-7ww", Rarity.RARE, mage.cards.c.CropRotation.class)); + cards.add(new SetCardInfo("Crop Rotation", "2020-7", Rarity.RARE, mage.cards.c.CropRotation.class)); cards.add(new SetCardInfo("Culling the Weak", "2023-8", Rarity.RARE, mage.cards.c.CullingTheWeak.class)); cards.add(new SetCardInfo("Cunning Sparkmage", "2010-2", Rarity.UNCOMMON, mage.cards.c.CunningSparkmage.class)); cards.add(new SetCardInfo("Dark Ritual", "2020-4", Rarity.RARE, mage.cards.d.DarkRitual.class)); diff --git a/Mage.Sets/src/mage/sets/MurdersAtKarlovManorCommander.java b/Mage.Sets/src/mage/sets/MurdersAtKarlovManorCommander.java index b397fe215df..5054600618e 100644 --- a/Mage.Sets/src/mage/sets/MurdersAtKarlovManorCommander.java +++ b/Mage.Sets/src/mage/sets/MurdersAtKarlovManorCommander.java @@ -115,6 +115,7 @@ public final class MurdersAtKarlovManorCommander extends ExpansionSet { cards.add(new SetCardInfo("Finale of Revelation", 106, Rarity.MYTHIC, mage.cards.f.FinaleOfRevelation.class)); cards.add(new SetCardInfo("Follow the Bodies", 23, Rarity.RARE, mage.cards.f.FollowTheBodies.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Follow the Bodies", 333, Rarity.RARE, mage.cards.f.FollowTheBodies.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Foreboding Steamboat", 28, Rarity.RARE, mage.cards.f.ForebodingSteamboat.class)); cards.add(new SetCardInfo("Fortified Village", 262, Rarity.RARE, mage.cards.f.FortifiedVillage.class)); cards.add(new SetCardInfo("Frontier Warmonger", 154, Rarity.RARE, mage.cards.f.FrontierWarmonger.class)); cards.add(new SetCardInfo("Fumigate", 66, Rarity.RARE, mage.cards.f.Fumigate.class)); diff --git a/Mage.Sets/src/mage/sets/RavnicaClueEdition.java b/Mage.Sets/src/mage/sets/RavnicaClueEdition.java index 6111eb31787..b66b3f9823e 100644 --- a/Mage.Sets/src/mage/sets/RavnicaClueEdition.java +++ b/Mage.Sets/src/mage/sets/RavnicaClueEdition.java @@ -78,7 +78,7 @@ public final class RavnicaClueEdition extends ExpansionSet { cards.add(new SetCardInfo("Dimir Guildgate", 234, Rarity.COMMON, mage.cards.d.DimirGuildgate.class)); cards.add(new SetCardInfo("Dimir Guildmage", 186, Rarity.UNCOMMON, mage.cards.d.DimirGuildmage.class)); cards.add(new SetCardInfo("Dimir Signet", 221, Rarity.COMMON, mage.cards.d.DimirSignet.class)); - //cards.add(new SetCardInfo("Dimir Strandcatcher", 30, Rarity.RARE, mage.cards.d.DimirStrandcatcher.class)); + cards.add(new SetCardInfo("Dimir Strandcatcher", 30, Rarity.RARE, mage.cards.d.DimirStrandcatcher.class)); cards.add(new SetCardInfo("Dining Room", 15, Rarity.UNCOMMON, mage.cards.d.DiningRoom.class)); cards.add(new SetCardInfo("Direct Current", 132, Rarity.COMMON, mage.cards.d.DirectCurrent.class)); cards.add(new SetCardInfo("Discovery // Dispersal", 187, Rarity.UNCOMMON, mage.cards.d.DiscoveryDispersal.class)); @@ -195,7 +195,7 @@ public final class RavnicaClueEdition extends ExpansionSet { cards.add(new SetCardInfo("Plains", 255, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 256, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 257, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("Portal Manipulator", 40, Rarity.UNCOMMON, mage.cards.p.PortalManipulator.class)); + cards.add(new SetCardInfo("Portal Manipulator", 40, Rarity.UNCOMMON, mage.cards.p.PortalManipulator.class)); cards.add(new SetCardInfo("Predatory Impetus", 172, Rarity.COMMON, mage.cards.p.PredatoryImpetus.class)); cards.add(new SetCardInfo("Psychic Impetus", 92, Rarity.COMMON, mage.cards.p.PsychicImpetus.class)); cards.add(new SetCardInfo("Pyrewild Shaman", 144, Rarity.UNCOMMON, mage.cards.p.PyrewildShaman.class)); diff --git a/Mage.Sets/src/mage/sets/SecretLairDrop.java b/Mage.Sets/src/mage/sets/SecretLairDrop.java index 6e0085ed7b0..d8a6eb5b0f3 100644 --- a/Mage.Sets/src/mage/sets/SecretLairDrop.java +++ b/Mage.Sets/src/mage/sets/SecretLairDrop.java @@ -365,7 +365,7 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Blood Moon", 366, Rarity.RARE, mage.cards.b.BloodMoon.class)); cards.add(new SetCardInfo("Cut // Ribbons", 367, Rarity.RARE, mage.cards.c.CutRibbons.class)); cards.add(new SetCardInfo("Teferi's Puzzle Box", 368, Rarity.RARE, mage.cards.t.TeferisPuzzleBox.class)); - cards.add(new SetCardInfo("Generous Gift", 369, Rarity.RARE, mage.cards.g.GenerousGift.class)); + cards.add(new SetCardInfo("Generous Gift", 369, Rarity.RARE, mage.cards.g.GenerousGift.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Chain Lightning", 370, Rarity.RARE, mage.cards.c.ChainLightning.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kodama's Reach", 371, Rarity.RARE, mage.cards.k.KodamasReach.class)); cards.add(new SetCardInfo("Heirloom Blade", 372, Rarity.RARE, mage.cards.h.HeirloomBlade.class)); @@ -607,7 +607,7 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Eldrazi Monument", 603, Rarity.MYTHIC, mage.cards.e.EldraziMonument.class)); cards.add(new SetCardInfo("Ornithopter", 604, Rarity.RARE, mage.cards.o.Ornithopter.class)); cards.add(new SetCardInfo("Panharmonicon", 605, Rarity.RARE, mage.cards.p.Panharmonicon.class)); - cards.add(new SetCardInfo("Swiftfoot Boots", 606, Rarity.RARE, mage.cards.s.SwiftfootBoots.class)); + cards.add(new SetCardInfo("Swiftfoot Boots", 606, Rarity.RARE, mage.cards.s.SwiftfootBoots.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Rogue's Passage", 607, Rarity.RARE, mage.cards.r.RoguesPassage.class)); cards.add(new SetCardInfo("Darksteel Citadel", 608, Rarity.RARE, mage.cards.d.DarksteelCitadel.class)); cards.add(new SetCardInfo("Havengul Laboratory", 609, Rarity.RARE, mage.cards.h.HavengulLaboratory.class)); @@ -824,6 +824,7 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Norin the Wary", "827b", Rarity.RARE, mage.cards.n.NorinTheWary.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Keen Duelist", 828, Rarity.RARE, mage.cards.k.KeenDuelist.class)); cards.add(new SetCardInfo("Fatestitcher", 835, Rarity.RARE, mage.cards.f.Fatestitcher.class, RETRO_ART)); + cards.add(new SetCardInfo("Undead Alchemist", 836, Rarity.RARE, mage.cards.u.UndeadAlchemist.class, RETRO_ART)); cards.add(new SetCardInfo("Champion of the Perished", 837, Rarity.RARE, mage.cards.c.ChampionOfThePerished.class, RETRO_ART)); cards.add(new SetCardInfo("Corpse Connoisseur", 838, Rarity.RARE, mage.cards.c.CorpseConnoisseur.class, RETRO_ART)); cards.add(new SetCardInfo("Cryptbreaker", 839, Rarity.RARE, mage.cards.c.Cryptbreaker.class, RETRO_ART)); @@ -1957,7 +1958,7 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Dragonlord Ojutai", "1973b", Rarity.MYTHIC, mage.cards.d.DragonlordOjutai.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dragonlord Silumgar", 1974, Rarity.MYTHIC, mage.cards.d.DragonlordSilumgar.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dragonlord Silumgar", "1974b", Rarity.MYTHIC, mage.cards.d.DragonlordSilumgar.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Deadly Dispute", 1980, Rarity.RARE, mage.cards.d.DeadlyDispute.class)); + cards.add(new SetCardInfo("Deadly Dispute", 1980, Rarity.RARE, mage.cards.d.DeadlyDispute.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Murderous Rider", 1981, Rarity.RARE, mage.cards.m.MurderousRider.class)); cards.add(new SetCardInfo("Zulaport Cutthroat", 1982, Rarity.RARE, mage.cards.z.ZulaportCutthroat.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aggravated Assault", 1983, Rarity.RARE, mage.cards.a.AggravatedAssault.class, NON_FULL_USE_VARIOUS)); @@ -2017,13 +2018,38 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Swamp", 2078, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Mountain", 2079, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Forest", 2080, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Super State", 2081, Rarity.MYTHIC, mage.cards.s.SuperState.class)); + cards.add(new SetCardInfo("Knuckles the Echidna", 2082, Rarity.MYTHIC, mage.cards.k.KnucklesTheEchidna.class)); + cards.add(new SetCardInfo("Amy Rose", 2083, Rarity.MYTHIC, mage.cards.a.AmyRose.class)); + cards.add(new SetCardInfo("Dr. Eggman", 2084, Rarity.MYTHIC, mage.cards.d.DrEggman.class)); + cards.add(new SetCardInfo("Miles \"Tails\" Prower", 2085, Rarity.MYTHIC, mage.cards.m.MilesTailsPrower.class)); + cards.add(new SetCardInfo("Shadow the Hedgehog", 2086, Rarity.MYTHIC, mage.cards.s.ShadowTheHedgehog.class)); + cards.add(new SetCardInfo("Sonic the Hedgehog", 2087, Rarity.MYTHIC, mage.cards.s.SonicTheHedgehog.class)); + cards.add(new SetCardInfo("Generous Gift", 2088, Rarity.RARE, mage.cards.g.GenerousGift.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Open the Armory", 2089, Rarity.RARE, mage.cards.o.OpenTheArmory.class)); + cards.add(new SetCardInfo("Fabricate", 2090, Rarity.RARE, mage.cards.f.Fabricate.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Deadly Dispute", 2091, Rarity.RARE, mage.cards.d.DeadlyDispute.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Unexpected Windfall", 2092, Rarity.RARE, mage.cards.u.UnexpectedWindfall.class)); + cards.add(new SetCardInfo("Sol Ring", 2093, Rarity.RARE, mage.cards.s.SolRing.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Reaver Cleaver", 2095, Rarity.RARE, mage.cards.t.TheReaverCleaver.class)); + cards.add(new SetCardInfo("Swiftfoot Boots", 2096, Rarity.RARE, mage.cards.s.SwiftfootBoots.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Myr Battlesphere", 2097, Rarity.RARE, mage.cards.m.MyrBattlesphere.class)); + cards.add(new SetCardInfo("Hammer of Nazahn", 2098, Rarity.RARE, mage.cards.h.HammerOfNazahn.class)); + cards.add(new SetCardInfo("Lightning Greaves", 2099, Rarity.RARE, mage.cards.l.LightningGreaves.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Weatherlight", 2100, Rarity.MYTHIC, mage.cards.w.Weatherlight.class)); cards.add(new SetCardInfo("Feed the Swarm", 7001, Rarity.RARE, mage.cards.f.FeedTheSwarm.class)); cards.add(new SetCardInfo("Forge Anew", 7002, Rarity.RARE, mage.cards.f.ForgeAnew.class)); cards.add(new SetCardInfo("Silence", 7003, Rarity.RARE, mage.cards.s.Silence.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Solitude", 7004, Rarity.MYTHIC, mage.cards.s.Solitude.class)); + cards.add(new SetCardInfo("Subtlety", 7005, Rarity.MYTHIC, mage.cards.s.Subtlety.class)); + cards.add(new SetCardInfo("Grief", 7006, Rarity.MYTHIC, mage.cards.g.Grief.class)); + cards.add(new SetCardInfo("Fury", 7007, Rarity.MYTHIC, mage.cards.f.Fury.class)); + cards.add(new SetCardInfo("Endurance", 7008, Rarity.MYTHIC, mage.cards.e.Endurance.class)); cards.add(new SetCardInfo("Smothering Tithe", 7009, Rarity.RARE, mage.cards.s.SmotheringTithe.class)); cards.add(new SetCardInfo("Counterspell", 7010, Rarity.RARE, mage.cards.c.Counterspell.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dismember", 7011, Rarity.RARE, mage.cards.d.Dismember.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Command Tower", 7012, Rarity.RARE, mage.cards.c.CommandTower.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tibalt's Trickery", 7027, Rarity.RARE, mage.cards.t.TibaltsTrickery.class)); cards.add(new SetCardInfo("Minds Aglow", 7028, Rarity.RARE, mage.cards.m.MindsAglow.class)); cards.add(new SetCardInfo("Command Tower", 7029, Rarity.RARE, mage.cards.c.CommandTower.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Jace, the Mind Sculptor", 8001, Rarity.MYTHIC, mage.cards.j.JaceTheMindSculptor.class)); diff --git a/Mage.Sets/src/mage/sets/SecretLairShowdown.java b/Mage.Sets/src/mage/sets/SecretLairShowdown.java index 2d6802320d5..dfc3fecd8be 100644 --- a/Mage.Sets/src/mage/sets/SecretLairShowdown.java +++ b/Mage.Sets/src/mage/sets/SecretLairShowdown.java @@ -25,7 +25,6 @@ public class SecretLairShowdown extends ExpansionSet { cards.add(new SetCardInfo("Dark Ritual", 16, Rarity.RARE, mage.cards.d.DarkRitual.class)); cards.add(new SetCardInfo("Death's Shadow", 8, Rarity.RARE, mage.cards.d.DeathsShadow.class)); cards.add(new SetCardInfo("Dragonlord Silumgar", 9, Rarity.MYTHIC, mage.cards.d.DragonlordSilumgar.class)); - cards.add(new SetCardInfo("Echo of Death's Wail", 356, Rarity.RARE, mage.cards.e.EchoOfDeathsWail.class)); cards.add(new SetCardInfo("Eldritch Evolution", 5, Rarity.RARE, mage.cards.e.EldritchEvolution.class)); cards.add(new SetCardInfo("Explore", 12, Rarity.RARE, mage.cards.e.Explore.class)); cards.add(new SetCardInfo("Expressive Iteration", 13, Rarity.RARE, mage.cards.e.ExpressiveIteration.class)); @@ -60,7 +59,6 @@ public class SecretLairShowdown extends ExpansionSet { cards.add(new SetCardInfo("Supreme Verdict", 26, Rarity.RARE, mage.cards.s.SupremeVerdict.class)); cards.add(new SetCardInfo("Swamp", 33, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Swords to Plowshares", 20, Rarity.RARE, mage.cards.s.SwordsToPlowshares.class)); - cards.add(new SetCardInfo("Tribute to Horobi", 356, Rarity.RARE, mage.cards.t.TributeToHorobi.class)); cards.add(new SetCardInfo("Ugin, the Spirit Dragon", 6, Rarity.MYTHIC, mage.cards.u.UginTheSpiritDragon.class)); cards.add(new SetCardInfo("Unholy Heat", 4, Rarity.RARE, mage.cards.u.UnholyHeat.class)); cards.add(new SetCardInfo("Valakut, the Molten Pinnacle", 14, Rarity.RARE, mage.cards.v.ValakutTheMoltenPinnacle.class)); diff --git a/Mage.Sets/src/mage/sets/Warhammer40000Commander.java b/Mage.Sets/src/mage/sets/Warhammer40000Commander.java index c009b193fdd..2bb6b66df29 100644 --- a/Mage.Sets/src/mage/sets/Warhammer40000Commander.java +++ b/Mage.Sets/src/mage/sets/Warhammer40000Commander.java @@ -30,7 +30,6 @@ public final class Warhammer40000Commander extends ExpansionSet { cards.add(new SetCardInfo("Abundance", 210, Rarity.RARE, mage.cards.a.Abundance.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Acolyte Hybrid", "70*", Rarity.UNCOMMON, mage.cards.a.AcolyteHybrid.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Acolyte Hybrid", 70, Rarity.UNCOMMON, mage.cards.a.AcolyteHybrid.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Adaptive Automaton", 322, Rarity.RARE, mage.cards.a.AdaptiveAutomaton.class)); cards.add(new SetCardInfo("Aetherize", "191*", Rarity.UNCOMMON, mage.cards.a.Aetherize.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aetherize", 191, Rarity.UNCOMMON, mage.cards.a.Aetherize.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("And They Shall Know No Fear", "9*", Rarity.UNCOMMON, mage.cards.a.AndTheyShallKnowNoFear.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/LandTest.java b/Mage.Tests/src/frozen/org/mage/test/clientside/LandTest.java deleted file mode 100644 index 01ac0f9f94d..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/LandTest.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.mage.test.clientside; - -import org.junit.Test; -import org.mage.test.clientside.base.MageAPI; -import org.mage.test.clientside.bdd.and.And; -import org.mage.test.clientside.bdd.given.Given; -import org.mage.test.clientside.bdd.then.Then; -import org.mage.test.clientside.bdd.when.When; - -import static org.mage.test.clientside.base.MageAPI.Owner.*; - -public class LandTest extends MageAPI { - - @Test - public void testPlayingLandInMainPhase() throws Exception { - Given.I.have.a.card("Mountain"); - And.phase.is("Precombat Main", mine); - When.I.play("Mountain"); - Then.battlefield.has("Mountain"); - And.graveyards.empty(); - } -} diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/LandTestExtended.java b/Mage.Tests/src/frozen/org/mage/test/clientside/LandTestExtended.java deleted file mode 100644 index aeb8693ab56..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/LandTestExtended.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.mage.test.clientside; - -import mage.constants.Zone; -import org.junit.Test; -import org.mage.test.clientside.base.MageAPIExtended; - -import static org.mage.test.clientside.base.MageAPI.Owner.mine; - -public class LandTestExtended extends MageAPIExtended { - - @Test - public void testPlayingLandInMainPhase() throws Exception { - addCard("Mountain", Zone.HAND); - setPhase("Precombat Main", mine); - play("Mountain"); - assertBattlefield("Mountain"); - assertGraveyardsCount(0); - } -} diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/LightningHelixTest.java b/Mage.Tests/src/frozen/org/mage/test/clientside/LightningHelixTest.java deleted file mode 100644 index 01f034a06d0..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/LightningHelixTest.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.mage.test.clientside; - -import org.junit.Test; -import org.mage.test.clientside.base.MageAPI; - -public class LightningHelixTest extends MageAPI { - - @Test - public void testPlayTargetOpponent() throws Exception { - //Given.I.have.a.card("Lightning Helix"); - //And.battlefield.has("Mountain","Plains"); - //And.phase.is("Precombat Main", mine); - //And.phase.is("End of Turn", ai); - //And.lifes(20,20); - //When.I.play("Lightning Helix"); - //Then.my.life(23); - //And.ai.life(17); - //And.my.graveyard.has("Lightning Helix"); - //And.ai.graveyard.empty(); - //Then.graveyards.empty(); - } -} diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/base/Command.java b/Mage.Tests/src/frozen/org/mage/test/clientside/base/Command.java deleted file mode 100644 index 32728710a90..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/base/Command.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.mage.test.clientside.base; - -/** - * Command pattern. - * - * @author nantuko - */ -abstract public class Command { - abstract public void execute() throws Exception; -} diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/base/MageAPI.java b/Mage.Tests/src/frozen/org/mage/test/clientside/base/MageAPI.java deleted file mode 100644 index adbcd73db6c..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/base/MageAPI.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.mage.test.clientside.base; - -import org.junit.BeforeClass; -import org.mage.test.clientside.bdd.StepController; -import org.mage.test.clientside.bdd.StepState; - -/** - * Parent class for all Mage tests. - * Provides basic actions in mage game and assert functions to check game state. - */ -public class MageAPI { - - public enum Owner { - mine, - me, - ai - } - - @BeforeClass - public static void startServer() throws Exception { - MageBase.getInstance().start(); - } - - /** - * Defined step depending on input parameter. - * If step is UNKNOWN, then use previous remember step, otherwise remember it as current. - * - * Used for replacing "And." by "Given", "When", "Then" - * - * @param step - * @return - */ - public static StepState defineStep(StepState step) { - StepState current = step; - if (!step.equals(StepState.UNKNOWN)) { - StepController.currentState = step; - } else { - current = StepController.currentState; - } - return current; - } -} diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/base/MageAPIExtended.java b/Mage.Tests/src/frozen/org/mage/test/clientside/base/MageAPIExtended.java deleted file mode 100644 index 224777caab7..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/base/MageAPIExtended.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.mage.test.clientside.base; - -import mage.constants.Zone; -import org.mage.test.clientside.bdd.and.And; -import org.mage.test.clientside.bdd.given.Given; -import org.mage.test.clientside.bdd.then.Then; -import org.mage.test.clientside.bdd.when.When; - -import static org.mage.test.clientside.base.MageAPI.Owner.mine; - -/** - * Contains wrappers for bdd calls. - */ -public class MageAPIExtended extends MageAPI { - - public void addCard(String cardName, Zone zone) throws Exception { - Given.I.have.a.card("Mountain"); - } - - public void setPhase(String phase, Owner owner) throws Exception { - And.phase.is("Precombat Main", mine); - } - - public void play(String cardName) throws Exception { - When.I.play("Mountain"); - } - - public void assertBattlefield(String cardName) throws Exception { - Then.battlefield.has("Mountain"); - } - - public void assertGraveyardsCount(int count) throws Exception { - And.graveyards.empty(); - } -} diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/base/MageBase.java b/Mage.Tests/src/frozen/org/mage/test/clientside/base/MageBase.java deleted file mode 100644 index 5bd7fcc6e29..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/base/MageBase.java +++ /dev/null @@ -1,262 +0,0 @@ -package org.mage.test.clientside.base; - -import mage.constants.MultiplayerAttackOption; -import mage.constants.RangeOfInfluence; -import mage.game.match.MatchOptions; -import mage.interfaces.MageException; -import mage.interfaces.Server; -import mage.interfaces.ServerState; -import mage.interfaces.callback.CallbackClient; -import mage.interfaces.callback.CallbackClientDaemon; -import mage.interfaces.callback.ClientCallback; -import mage.server.Main; -import mage.sets.Sets; -import mage.util.Logging; - -import java.rmi.NotBoundException; -import java.rmi.RemoteException; -import java.rmi.registry.LocateRegistry; -import java.rmi.registry.Registry; -import java.util.Date; -import java.util.UUID; - -/** - * Base for starting Mage server. Controls interactions between MageAPI and Mage - * Server. - * - * @author nantuko - */ -public class MageBase { - - /** - * MageBase single instance - */ - private static MageBase instance = new MageBase(); - - /** - * Default logger - */ - private static Logger logger = Logging.getLogger(MageBase.class.getName()); - - public static MageBase getInstance() { - return instance; - } - - private static UUID sessionId; - public static Server server; - private static String userName; - private static ServerState serverState; - private static CallbackClientDaemon callbackDaemon; - private static UUID gameId; - private static UUID playerId; - private static CardView cardPlayed; - - private static GameView gameView; - private static String phaseToWait; - private static Object sync = new Object(); - private static Object syncStart = new Object(); - - public void start() throws Exception { - if (server == null) { - String[] args = new String[]{"-testMode=true"}; - Main.main(args); - connect("player", "localhost", 17171); - UUID roomId = server.getMainRoomId(); - - MatchOptions options = new MatchOptions("1", "Two Player Duel", false); - options.getPlayerTypes().add("Human"); - options.getPlayerTypes().add("Computer - default"); - options.setDeckType("Limited"); - options.setAttackOption(MultiplayerAttackOption.LEFT); - options.setRange(RangeOfInfluence.ALL); - options.setWinsNeeded(1); - TableView table = server.createTable(sessionId, roomId, options); - System.out.println("Cards in the deck: " + Sets.loadDeck("UW Control.dck").getCards().size()); - server.joinTable(sessionId, roomId, table.getTableId(), "Human", "Human", Sets.loadDeck("UW Control.dck")); - server.joinTable(sessionId, roomId, table.getTableId(), "Computer", "Computer - default", Sets.loadDeck("UW Control.dck")); - server.startMatch(sessionId, roomId, table.getTableId()); - - synchronized (syncStart) { - int waitTime = 7000; - Date prev = new Date(); - syncStart.wait(waitTime); - Date intermediate = new Date(); - if (intermediate.getTime() - prev.getTime() > waitTime - 500) { - throw new IllegalStateException("Couldn't start server"); - } - } - } - } - - public static void connect(String userName, String serverName, int port) { - try { - System.setSecurityManager(null); - Registry reg = LocateRegistry.getRegistry(serverName, port); - server = (Server) reg.lookup("mage-server"); - sessionId = server.registerClient(userName, UUID.randomUUID()); - CallbackClient client = new CallbackClient() { - @Override - public void processCallback(ClientCallback callback) { - logger.log(Level.INFO, "IN >> {0} - {1}", new Object[]{callback.getMessageId(), callback.getMethod()}); - try { - if (callback.getMethod().equals("startGame")) { - TableClientMessage data = (TableClientMessage) callback.getData(); - gameId = data.getGameId(); - playerId = data.getPlayerId(); - server.joinGame(gameId, sessionId); - } else if (callback.getMethod().equals("gameInit")) { - server.ack("gameInit", sessionId); - } else if (callback.getMethod().equals("gameAsk")) { - GameClientMessage message = (GameClientMessage) callback.getData(); - logger.log(Level.INFO, "ASK >> {0}", message.getMessage()); - if (message.getMessage().equals("Do you want to take a mulligan?")) { - server.sendPlayerBoolean(gameId, sessionId, false); - } - synchronized (syncStart) { - syncStart.notify(); - } - } else if (callback.getMethod().equals("gameTarget")) { - GameClientMessage message = (GameClientMessage) callback.getData(); - logger.log(Level.INFO, "TARGET >> {0} >> {1}", new Object[]{message.getMessage(), message.getTargets()}); - if (message.getMessage().equals("Select a starting player")) { - logger.log(Level.INFO, " Sending >> {0}", playerId); - server.sendPlayerUUID(gameId, sessionId, playerId); - } - } else if (callback.getMethod().equals("gameSelect")) { - GameClientMessage message = (GameClientMessage) callback.getData(); - logger.log(Level.INFO, "SELECT >> {0}", message.getMessage()); - if (phaseToWait == null) { - synchronized (sync) { - sync.wait(); - } - } - if (!message.getMessage().startsWith(phaseToWait)) { - server.sendPlayerBoolean(gameId, sessionId, false); - } else { - phaseToWait = null; - } - - /*if (!message.getMessage().startsWith("Precombat Main - play spells and sorceries.")) { - server.sendPlayerBoolean(gameId, sessionId, false); - } else { - if (cardPlayed == null) { - CardsView cards = message.getGameView().getHand(); - CardView landToPlay = null; - for (CardView card : cards.values()) { - //System.out.println(card.getName()); - if (card.getName().equals("Plains") || card.getName().equals("Island")) { - landToPlay = card; - } - } - if (landToPlay != null) { - logger.info("Playing " + landToPlay); - server.sendPlayerUUID(gameId, sessionId, landToPlay.getId()); - cardPlayed = landToPlay; - } else { - logger.warning("Couldn't find land to play"); - } - } else { - logger.info("Checking battlefield..."); - boolean foundPlayer = false; - boolean foundLand = false; - for (PlayerView player: message.getGameView().getPlayers()) { - if (player.getPlayerId().equals(playerId)) { - foundPlayer = true; - for (PermanentView permanent : player.getBattlefield().values()) { - if (permanent.getId().equals(cardPlayed.getId())) { - foundLand = true; - } - } - break; - } - } - logger.info(" found player: " + foundPlayer); - logger.info(" found land: " + foundLand); - System.exit(0); - } - - } */ - } - } catch (Exception e) { - logger.info(e.getMessage()); - } - } - }; - callbackDaemon = new CallbackClientDaemon(sessionId, client, server); - serverState = server.getServerState(); - } catch (MageException ex) { - logger.log(Level.SEVERE, null, ex); - } catch (RemoteException ex) { - logger.log(Level.SEVERE, "Unable connect to server - ", ex); - } catch (NotBoundException ex) { - logger.log(Level.SEVERE, "Unable connect to server - ", ex); - } - } - - public boolean giveme(String cardName) throws Exception { - return server.cheat(gameId, sessionId, playerId, cardName); - } - - public boolean checkIhave(String cardName) throws Exception { - if (cardName == null) { - return false; - } - gameView = server.getGameView(gameId, sessionId, playerId); - for (CardView card : gameView.getHand().values()) { - if (CardUtil.haveSameNames(card.getName(), cardName)) { - return true; - } - } - return false; - } - - public void goToPhase(String phase) { - phaseToWait = phase; - synchronized (sync) { - sync.notify(); - } - } - - public void playCard(String cardName) throws Exception { - gameView = server.getGameView(gameId, sessionId, playerId); - CardsView cards = gameView.getHand(); - CardView cardToPlay = null; - for (CardView card : cards.values()) { - if (CardUtil.haveSameNames(card.getName(), cardName)) { - cardToPlay = card; - } - } - if (cardToPlay == null) { - throw new IllegalArgumentException("Couldn't find " + cardName + " in the hand."); - } - if (cardToPlay != null) { - logger.info("Playing " + cardToPlay); - server.sendPlayerUUID(gameId, sessionId, cardToPlay.getId()); - cardPlayed = cardToPlay; - } - } - - public boolean checkBattlefield(String cardName) throws Exception { - gameView = server.getGameView(gameId, sessionId, playerId); - for (PlayerView player : gameView.getPlayers()) { - if (player.getPlayerId().equals(playerId)) { - for (PermanentView permanent : player.getBattlefield().values()) { - if (permanent.getName().equals(cardName)) { - return true; - } - } - } - } - return false; - } - - public boolean checkGraveyardsEmpty() throws Exception { - gameView = server.getGameView(gameId, sessionId, playerId); - for (PlayerView player : gameView.getPlayers()) { - if (player.getGraveyard().size() > 0) { - return false; - } - } - return true; - } -} diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/base/exception/CardNotFoundException.java b/Mage.Tests/src/frozen/org/mage/test/clientside/base/exception/CardNotFoundException.java deleted file mode 100644 index e123b5e1ad6..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/base/exception/CardNotFoundException.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.mage.test.clientside.base.exception; - -/** - * Thrown when server couldn't create card with given name. - * - * @author nantuko - */ -public class CardNotFoundException extends RuntimeException { - public CardNotFoundException(String s) { - super(s); - } -} diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/BDDTests.java b/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/BDDTests.java deleted file mode 100644 index ee3028f8207..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/BDDTests.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.mage.test.clientside.bdd; - -import org.junit.Test; -import org.mage.test.clientside.base.Command; -import org.mage.test.clientside.base.MageAPI; -import org.mage.test.clientside.base.exception.CardNotFoundException; -import org.mage.test.clientside.bdd.and.And; -import org.mage.test.clientside.bdd.given.Given; -import org.mage.test.clientside.bdd.then.Then; -import org.mage.test.clientside.bdd.when.When; - -import static org.mage.test.clientside.base.MageAPI.Owner.mine; - -/** - * Tests BDD classes. - */ -public class BDDTests extends MageAPI { - - @Test - public void testNonExistingCard() throws Exception { - Expect.expect(CardNotFoundException.class, new Command() { - @Override - public void execute() throws Exception { - Given.I.have.a.card("Super Puper Card"); - And.phase.is("Precombat Main", mine); - When.I.play("Super Puper Card"); - Then.battlefield.has("Mountain"); - And.graveyards.empty(); - } - }); - } -} diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/Expect.java b/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/Expect.java deleted file mode 100644 index 97e0ff0c8c9..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/Expect.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.mage.test.clientside.bdd; - -import org.junit.Assert; -import org.mage.test.clientside.base.Command; - -import static junit.framework.TestCase.*; - -/** - * Asserts expecting exception. - * - * @author nantuko - */ -public class Expect { - public static void expect(Class t, Command command) { - try { - command.execute(); - } catch (Throwable e) { - assertEquals(e.getClass().getName(), t.getName()) - return; - } - throw new AssertionError("Expected exception wasn't thrown: " + t.getName()); - } -} diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/StepController.java b/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/StepController.java deleted file mode 100644 index 36330e94a23..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/StepController.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.mage.test.clientside.bdd; - -/** - * Controls steps of bdd calls. - * Uses step for the same "And" calls depending on previous calls. - * So "And." can be either "Given." or "Then." depending on "Given" or "Then" was called previously. - * - * Example: - * - * Given.I.have.a.card("Island"); // remember step here - * And.battlefield.has("Plains"); // "And" replaced and Given.battlefield.has("Plains"); is called - * - * Then.graveyards.empty(); // remember step here - * And.battlefield.has("Plains"); // "And" replaced and Then.battlefield.has("Plains"); is called - * - */ -public class StepController { - public static StepState currentState = StepState.UNKNOWN; -} diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/StepState.java b/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/StepState.java deleted file mode 100644 index 327c4fd99cd..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/StepState.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.mage.test.clientside.bdd; - -public enum StepState { - GIVEN, - WHEN, - THEN, - UNKNOWN -} \ No newline at end of file diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/and/And.java b/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/and/And.java deleted file mode 100644 index 013d70444de..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/and/And.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.mage.test.clientside.bdd.and; - -import org.mage.test.clientside.bdd.StepState; -import org.mage.test.clientside.bdd.given.I; - -public class And { - public static Phase phase = new Phase(StepState.UNKNOWN); - public static Graveyards graveyards = new Graveyards(StepState.UNKNOWN); - public static I I = new I(StepState.UNKNOWN); -} diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/and/Graveyards.java b/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/and/Graveyards.java deleted file mode 100644 index 43fba7cf46b..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/and/Graveyards.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.mage.test.clientside.bdd.and; - -import org.junit.Assert; -import org.mage.test.clientside.base.MageAPI; -import org.mage.test.clientside.base.MageBase; -import org.mage.test.clientside.bdd.StepState; - -import static junit.framework.TestCase.*; - -public class Graveyards { - private StepState step; - public Graveyards(StepState step) { - this.step = step; - } - public boolean empty() throws Exception { - StepState current = MageAPI.defineStep(this.step); - if (current.equals(StepState.THEN)) { - boolean empty = MageBase.getInstance().checkGraveyardsEmpty(); - assertTrue(empty); - return empty; - } else { - throw new AssertionError("Not implemented for step="+current); - } - } -} diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/and/Phase.java b/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/and/Phase.java deleted file mode 100644 index 1cea712dcc5..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/and/Phase.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.mage.test.clientside.bdd.and; - -import org.mage.test.clientside.base.MageAPI; -import org.mage.test.clientside.base.MageBase; -import org.mage.test.clientside.bdd.StepState; - -import static org.mage.test.clientside.base.MageAPI.Owner.*; - -public class Phase { - private StepState step; - public Phase(StepState step) { - this.step = step; - } - public void is(String phase, MageAPI.Owner owner) throws Exception { - StepState current = MageAPI.defineStep(this.step); - if (current.equals(StepState.GIVEN)) { - if ("Precombat Main".equals(phase) && (owner.equals(mine) || owner.equals(me))) { - MageBase.getInstance().goToPhase("Precombat Main - play spells and sorceries."); - return; - } - System.err.println("waitForPhase not implemented for phase="+phase+", owner="+owner.name()); - throw new RuntimeException("Not implemented."); - } else { - throw new RuntimeException("Not implemented for step = " + current); - } - } -} diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/given/A.java b/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/given/A.java deleted file mode 100644 index a6b9865abe3..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/given/A.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.mage.test.clientside.bdd.given; - -import org.mage.test.clientside.base.MageAPI; -import org.mage.test.clientside.base.MageBase; -import org.mage.test.clientside.base.exception.CardNotFoundException; -import org.mage.test.clientside.bdd.StepState; - -public class A { - private StepState step; - public A(StepState step) { - this.step = step; - } - public void card(String cardName) throws Exception { - StepState current = MageAPI.defineStep(this.step); - if (current.equals(StepState.GIVEN)) { - if (!MageBase.getInstance().giveme(cardName)) { - throw new CardNotFoundException("Couldn't create card: " + cardName); - } - } else if (current.equals(StepState.THEN)) { - if (!MageBase.getInstance().checkIhave(cardName)) { - throw new CardNotFoundException("Couldn't find requested card in hand: " + cardName); - } - } - } -} diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/given/Given.java b/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/given/Given.java deleted file mode 100644 index 17763083c76..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/given/Given.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.mage.test.clientside.bdd.given; - -import org.mage.test.clientside.bdd.StepState; -import org.mage.test.clientside.bdd.and.Phase; - -public class Given { - public static I I = new I(StepState.GIVEN); - public static Phase phase = new Phase(StepState.GIVEN); -} diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/given/Have.java b/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/given/Have.java deleted file mode 100644 index b897e22a44f..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/given/Have.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.mage.test.clientside.bdd.given; - -import org.mage.test.clientside.bdd.StepState; - -public class Have { - public Have(StepState step) { - a = new A(step); - } - public A a; -} \ No newline at end of file diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/given/I.java b/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/given/I.java deleted file mode 100644 index e06c383c64a..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/given/I.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.mage.test.clientside.bdd.given; - -import org.mage.test.clientside.bdd.StepState; - -public class I { - public I(StepState step) { - have = new Have(step); - } - public Have have; -} \ No newline at end of file diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/then/Battlefield.java b/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/then/Battlefield.java deleted file mode 100644 index 4fb0fc6d3d5..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/then/Battlefield.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.mage.test.clientside.bdd.then; - -import org.mage.test.clientside.base.MageAPI; -import org.mage.test.clientside.base.MageBase; -import org.mage.test.clientside.bdd.StepState; - -public class Battlefield { - private StepState step; - public Battlefield(StepState step) { - this.step = step; - } - public boolean has(String cardName) throws Exception { - StepState current = MageAPI.defineStep(this.step); - if (current.equals(StepState.THEN)) { - return MageBase.getInstance().checkBattlefield(cardName); - } else { - throw new AssertionError("Not implemented for step="+current); - } - } -} diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/then/Then.java b/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/then/Then.java deleted file mode 100644 index 978cb7e1c11..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/then/Then.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.mage.test.clientside.bdd.then; - -import org.mage.test.clientside.bdd.StepState; -import org.mage.test.clientside.bdd.and.Graveyards; - -public class Then { - public static Battlefield battlefield = new Battlefield(StepState.THEN); - public static Graveyards graveyards = new Graveyards(StepState.THEN); -} diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/when/I.java b/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/when/I.java deleted file mode 100644 index fa15e96d3f0..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/when/I.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.mage.test.clientside.bdd.when; - -import org.mage.test.clientside.base.MageBase; - -public class I { - public void play(String cardName) throws Exception { - MageBase.getInstance().playCard(cardName); - } -} \ No newline at end of file diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/when/When.java b/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/when/When.java deleted file mode 100644 index 6133b8c9440..00000000000 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/bdd/when/When.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.mage.test.clientside.bdd.when; - -public class When { - public static I I = new I(); -} diff --git a/Mage.Tests/src/test/java/org/mage/test/AI/basic/PossibleTargetsSelectorAITest.java b/Mage.Tests/src/test/java/org/mage/test/AI/basic/PossibleTargetsSelectorAITest.java new file mode 100644 index 00000000000..2ac5a37f76c --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/AI/basic/PossibleTargetsSelectorAITest.java @@ -0,0 +1,149 @@ +package org.mage.test.AI.basic; + +import mage.MageItem; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.InfoEffect; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.player.ai.PossibleTargetsSelector; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetDiscard; +import mage.target.common.TargetPermanentOrPlayer; +import org.junit.Assert; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author JayDi85 + */ +public class PossibleTargetsSelectorAITest extends CardTestPlayerBase { + + @Test + public void test_SortByOutcome() { + addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1); // 2/2 + addCard(Zone.BATTLEFIELD, playerA, "Arbor Elf", 1); // 1/1 + addCard(Zone.BATTLEFIELD, playerA, "Spectral Bears", 1); // 3/3 + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); // land + addCard(Zone.BATTLEFIELD, playerA, "Gideon, Martial Paragon", 1); // planeswalker + // + addCard(Zone.BATTLEFIELD, playerB, "Forest", 1); // land + addCard(Zone.BATTLEFIELD, playerB, "Goblin Brigand", 1); // 2/2 + addCard(Zone.BATTLEFIELD, playerB, "Battering Sliver", 1); // 4/4 + + + runCode("check", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { + // most valuable (planeswalker -> player -> bigger -> smaller) + + // good effect + PossibleTargetsSelector selector = prepareAnyTargetSelector(Outcome.Benefit); + selector.findNewTargets(null); + assertTargets("good effect must return my most valuable and biggest as priority", selector.getGoodTargets(), Arrays.asList( + "Gideon, Martial Paragon", // pw + "PlayerA", // p + "Spectral Bears", // 3/3 + "Balduvian Bears", // 2/2 + "Arbor Elf", // 1/1 + "Forest" // l + )); + assertTargets("good effect must return opponent's lowest as optional", selector.getBadTargets(), Arrays.asList( + "Forest", // l + "Goblin Brigand", // 2/2 + "Battering Sliver", // 4/4 + "PlayerB" // p + )); + + // bad effect - must be inverted + selector = prepareAnyTargetSelector(Outcome.Detriment); + selector.findNewTargets(null); + assertTargets("bad effect must return opponent's most valuable and biggest as priority", selector.getGoodTargets(), Arrays.asList( + "PlayerB", // p + "Battering Sliver", // 4/4 + "Goblin Brigand", // 1/1 + "Forest" // l + )); + assertTargets("bad effect must return my lowest as optional", selector.getBadTargets(), Arrays.asList( + "Forest", // l + "Arbor Elf", // 1/1 + "Balduvian Bears", // 2/2 + "Spectral Bears", // 3/3 + "PlayerA", // p + "Gideon, Martial Paragon" // pw + )); + }); + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + } + + @Test + public void test_SortByPlayable() { + addCard(Zone.HAND, playerA, "Balduvian Bears", 1); // 2/2, {1}{G} + addCard(Zone.HAND, playerA, "Arbor Elf", 1); // 1/1, {G}, playable + addCard(Zone.HAND, playerA, "Spectral Bears", 1); // 3/3, {1}{G} + addCard(Zone.HAND, playerA, "Forest", 1); // land + addCard(Zone.HAND, playerA, "Gideon, Martial Paragon", 1); // planeswalker, {4}{W} + // + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + + runCode("check", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { + // discard logic (remove the biggest unplayable first, land at the end) + + PossibleTargetsSelector selector = prepareDiscardCardSelector(); + selector.findNewTargets(null); + assertTargets("discard must return biggest unplayable first", selector.getGoodTargets(), Arrays.asList( + "Gideon, Martial Paragon", // pw + "Spectral Bears", // 3/3 + "Balduvian Bears", // 2/2 + "Arbor Elf", // 1/1 - playable + "Forest" // l + )); + }); + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + } + + private PossibleTargetsSelector prepareAnyTargetSelector(Outcome outcome) { + Target target = new TargetPermanentOrPlayer(); + Ability fakeAbility = new SimpleStaticAbility(new InfoEffect("fake")); + return new PossibleTargetsSelector(outcome, target, playerA.getId(), fakeAbility, currentGame); + } + + private PossibleTargetsSelector prepareDiscardCardSelector() { + Target target = new TargetDiscard(playerA.getId()); + Ability fakeAbility = new SimpleStaticAbility(new InfoEffect("fake")); + // discard sorting do not use outcome + return new PossibleTargetsSelector(Outcome.Benefit, target, playerA.getId(), fakeAbility, currentGame); + } + + private void assertTargets(String info, List targets, List needTargets) { + List currentTargets = targets.stream() + .map(item -> { + if (item instanceof Player) { + return ((Player) item).getName(); + } else if (item instanceof MageObject) { + return ((MageObject) item).getName(); + } else { + return "unknown item"; + } + }) + .collect(Collectors.toList()); + String current = String.join("\n", currentTargets); + String need = String.join("\n", needTargets); + if (!current.equals(need)) { + Assert.fail(info + "\n\n" + + "NEED targets:\n" + need + "\n\n" + + "FOUND targets:\n" + current + "\n"); + } + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/AI/basic/SimulationStabilityAITest.java b/Mage.Tests/src/test/java/org/mage/test/AI/basic/SimulationStabilityAITest.java new file mode 100644 index 00000000000..d1aa17af189 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/AI/basic/SimulationStabilityAITest.java @@ -0,0 +1,237 @@ +package org.mage.test.AI.basic; + +import mage.abilities.Ability; +import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.game.Game; +import mage.player.ai.ComputerPlayer; +import mage.player.ai.ComputerPlayer7; +import mage.util.ThreadUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps; + +/** + * Tests for AI simulation stability (AI must process simulations with freezes or errors) + * + * @author JayDi85 + */ +public class SimulationStabilityAITest extends CardTestPlayerBaseWithAIHelps { + + @Before + public void prepare() { + // comment it to enable AI code debug + Assert.assertFalse("AI stability tests must be run under release config", ComputerPlayer.COMPUTER_DISABLE_TIMEOUT_IN_GAME_SIMULATIONS); + } + + @Test + public void test_GameFreeze_OnlyGoodAbilities() { + removeAllCardsFromLibrary(playerA); + + // possible combinations: from 1 to 3 abilities - all fine + addFreezeAbility("good 1", false); + addFreezeAbility("good 2", false); + addFreezeAbility("good 3", false); + + // AI must activate all +3 life + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20 + 3); + } + + @Test + public void test_GameFreeze_OnlyFreezeAbilities() { + removeAllCardsFromLibrary(playerA); + + // possible combinations: from 1 to 3 bad abilities - all bad + addFreezeAbility("freeze 1", true); + addFreezeAbility("freeze 2", true); + addFreezeAbility("freeze 3", true); + + // AI can't finish any simulation and do not choose to activate in real game + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + } + + @Test + @Ignore + // TODO: AI actions simulation do not support multithreading, so whole next action search + // will fail on any problem (enable after new simulation implement) + public void test_GameFreeze_GoodAndFreezeAbilities() { + removeAllCardsFromLibrary(playerA); + + // possible combinations: some good chains, some bad chains + addFreezeAbility("good 1", false); + addFreezeAbility("good 2", false); + addFreezeAbility("good 3", false); + addFreezeAbility("freeze 1", true); + + // AI must see and filter bad combinations with freeze ability in the chain + // so only 1 + 2 + 3 will give best score and will be chosen for real game + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20 + 3); + } + + @Test + public void test_GameError_OnlyGoodAbilities() { + removeAllCardsFromLibrary(playerA); + + // possible combinations: from 1 to 3 abilities - all fine + addErrorAbility("good 1", false); + addErrorAbility("good 2", false); + addErrorAbility("good 3", false); + + // AI must activate all +3 life + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20 + 3); + } + + @Test + public void test_GameError_OnlyErrorAbilities() { + removeAllCardsFromLibrary(playerA); + + // it's ok to have error logs in output + + // possible combinations: from 1 to 3 bad abilities - all bad + addErrorAbility("error 1", true); + addErrorAbility("error 2", true); + addErrorAbility("error 3", true); + + // AI can't finish any simulation and do not choose to activate in real game + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + } + + @Test + @Ignore + // TODO: AI actions simulation do not support multithreading, so whole next action search + // will fail on any problem (enable after new simulation implement) + public void test_GameError_GoodAndFreezeAbilities() { + removeAllCardsFromLibrary(playerA); + + // it's ok to have error logs in output + + // possible combinations: some good chains, some bad chains + addErrorAbility("good 1", false); + addErrorAbility("good 2", false); + addErrorAbility("good 3", false); + addErrorAbility("error 1", true); + + // AI must see and filter bad combinations with error ability in the chain + // so only 1 + 2 + 3 will give best score and will be chosen for real game + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20 + 3); + } + + private void addFreezeAbility(String name, boolean isFreeze) { + // change max think timeout to lower value, so test can work faster + ComputerPlayer7 aiPlayer = (ComputerPlayer7) playerA.getRealPlayer(); + aiPlayer.setMaxThinkTimeSecs(1); + + Effect effect; + if (isFreeze) { + effect = new GameFreezeEffect(); + } else { + effect = new GainLifeEffect(1); + } + effect.setText(name); + addCustomCardWithAbility(name, playerA, new LimitedTimesPerTurnActivatedAbility(effect, new ManaCostsImpl<>("{G}"))); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + } + + private void addErrorAbility(String name, boolean isError) { + // change error processing, so test can continue simulations after catch error - like a real game + playerA.setFastFailInTestMode(false); + + Effect effect; + if (isError) { + effect = new GameErrorEffect(); + } else { + effect = new GainLifeEffect(1); + } + effect.setText(name); + addCustomCardWithAbility(name, playerA, new LimitedTimesPerTurnActivatedAbility(effect, new ManaCostsImpl<>("{G}"))); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + } +} + +class GameFreezeEffect extends OneShotEffect { + + GameFreezeEffect() { + super(Outcome.Benefit); + } + + private GameFreezeEffect(final GameFreezeEffect effect) { + super(effect); + } + + public GameFreezeEffect copy() { + return new GameFreezeEffect(this); + } + + public boolean apply(Game game, Ability source) { + // freeze simulation, AI must close sim thread by timeout + System.out.println("apply freeze effect on " + game); // for debug only, show logs from any sim thread + while (true) { + ThreadUtils.sleep(1000); + } + } +} + +class GameErrorEffect extends OneShotEffect { + + GameErrorEffect() { + super(Outcome.Benefit); + } + + private GameErrorEffect(final GameErrorEffect effect) { + super(effect); + } + + public GameErrorEffect copy() { + return new GameErrorEffect(this); + } + + public boolean apply(Game game, Ability source) { + // error simulation, AI must close error thread, do not use rollback + System.out.println("apply error effect on " + game); // for debug only, show logs from any sim thread + throw new IllegalStateException("Test error"); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/AI/basic/TargetPriorityTest.java b/Mage.Tests/src/test/java/org/mage/test/AI/basic/TargetPriorityTest.java index 17dc5e580e3..753d4bbc9fe 100644 --- a/Mage.Tests/src/test/java/org/mage/test/AI/basic/TargetPriorityTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/AI/basic/TargetPriorityTest.java @@ -21,52 +21,81 @@ import org.mage.test.serverside.base.CardTestPlayerBaseAI; public class TargetPriorityTest extends CardTestPlayerBaseAI { // TODO: enable _target_ tests after computerPlayer.chooseTarget will be reworks like chooseTargetAmount + @Test - @Ignore - public void test_target_PriorityKillByBigPT() { + public void test_Target_PriorityDamageToGoodOpponent() { addCard(Zone.HAND, playerA, "Lightning Bolt"); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); // addCard(Zone.BATTLEFIELD, playerB, "Memnite", 3); // 1/1 addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 3); // 2/2 - addCard(Zone.BATTLEFIELD, playerB, "Ashcoat Bear", 3); // 2/2 with ability - addCard(Zone.BATTLEFIELD, playerB, "Golden Bear", 3); // 4/3 - addCard(Zone.BATTLEFIELD, playerB, "Battering Sliver", 3); // 4/4 with ability + addCard(Zone.BATTLEFIELD, playerA, "Ashcoat Bear", 3); // 2/2 with ability + // AI must make damage to opponent castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt"); + setStrictChooseMode(false); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertLife(playerA, 20); + assertLife(playerB, 20 - 3); + } + + @Test + public void test_Target_PriorityDamageToBadLowestCreature() { + addCard(Zone.HAND, playerA, "Lightning Bolt"); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + // + // You have shroud. + addCard(Zone.BATTLEFIELD, playerB, "Ivory Mask", 1); + // + addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 3); // 2/2 + addCard(Zone.BATTLEFIELD, playerA, "Memnite", 3); // 1/1 + addCard(Zone.BATTLEFIELD, playerA, "Ashcoat Bear", 3); // 2/2 with ability + + // AI can't target opponent so target own lowest creature + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt"); + + setStrictChooseMode(false); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Memnite", 3 - 1); + } + + @Test + public void test_Target_PriorityDamageToBiggestCreature() { + addCard(Zone.HAND, playerA, "Lightning Bolt"); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + // + // You have shroud. + addCard(Zone.BATTLEFIELD, playerA, "Ivory Mask", 1); + addCard(Zone.BATTLEFIELD, playerB, "Ivory Mask", 1); + // + addCard(Zone.BATTLEFIELD, playerB, "Memnite", 3); // 1/1 + addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 3); // 2/2 + addCard(Zone.BATTLEFIELD, playerB, "Ashcoat Bear", 3); // 2/2 with ability + addCard(Zone.BATTLEFIELD, playerB, "Golden Bear", 3); // 4/3 + //addCard(Zone.BATTLEFIELD, playerB, "Battering Sliver", 3); // 4/4 with ability TODO: add after AI will simulation simple choices too + + // AI must choose biggest creature to kill from opponent - 4/3 + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + showBattlefield("as", 1, PhaseStep.PRECOMBAT_MAIN, playerB); + + setStrictChooseMode(false); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); assertPermanentCount(playerB, "Memnite", 3); assertPermanentCount(playerB, "Balduvian Bears", 3); assertPermanentCount(playerB, "Ashcoat Bear", 3); assertPermanentCount(playerB, "Golden Bear", 3 - 1); - assertPermanentCount(playerB, "Battering Sliver", 3); - } - - @Test - @Ignore - public void test_target_PriorityByKillByLowPT() { - addCard(Zone.HAND, playerA, "Lightning Bolt"); - addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); - // - addCard(Zone.BATTLEFIELD, playerB, "Memnite", 3); // 1/1 - //addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 3); // 2/2 - //addCard(Zone.BATTLEFIELD, playerB, "Ashcoat Bear", 3); // 2/2 with ability - //addCard(Zone.BATTLEFIELD, playerB, "Golden Bear", 3); // 4/3 - addCard(Zone.BATTLEFIELD, playerB, "Battering Sliver", 3); // 4/4 with ability - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt"); - - setStopAt(1, PhaseStep.BEGIN_COMBAT); - execute(); - - assertPermanentCount(playerB, "Memnite", 3 - 1); - //assertPermanentCount(playerB, "Balduvian Bears", 3); - //assertPermanentCount(playerB, "Ashcoat Bear", 3); - //assertPermanentCount(playerB, "Golden Bear", 3); - assertPermanentCount(playerB, "Battering Sliver", 3); } @Test @@ -153,7 +182,7 @@ public class TargetPriorityTest extends CardTestPlayerBaseAI { // TARGET AMOUNT @Test - public void test_targetAmount_PriorityKillByBigPT() { + public void test_TargetAmount_PriorityKillByBigPT() { addCard(Zone.HAND, playerA, "Flames of the Firebrand"); // damage 3 addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); // @@ -176,7 +205,7 @@ public class TargetPriorityTest extends CardTestPlayerBaseAI { } @Test - public void test_targetAmount_PriorityByKillByLowPT() { + public void test_TargetAmount_PriorityByKillByLowPT() { addCard(Zone.HAND, playerA, "Flames of the Firebrand"); // damage 3 addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); // @@ -199,7 +228,7 @@ public class TargetPriorityTest extends CardTestPlayerBaseAI { } @Test - public void test_targetAmount_PriorityKillByExtraPoints() { + public void test_TargetAmount_PriorityKillByExtraPoints() { addCard(Zone.HAND, playerA, "Flames of the Firebrand"); // damage 3 addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); // @@ -222,7 +251,7 @@ public class TargetPriorityTest extends CardTestPlayerBaseAI { } @Test - public void test_targetAmount_NormalCase() { + public void test_TargetAmount_NormalCase() { Ability ability = new SimpleActivatedAbility(Zone.ALL, new DamageMultiEffect(), new ManaCostsImpl<>("{R}")); ability.addTarget(new TargetCreaturePermanentAmount(3, 0, 3)); addCustomCardWithAbility("damage 3", playerA, ability); @@ -247,7 +276,7 @@ public class TargetPriorityTest extends CardTestPlayerBaseAI { } @Test - public void test_targetAmount_BadCase() { + public void test_TargetAmount_BadCase() { // choose targets as enters battlefield (e.g. can't be canceled) SpellAbility spell = new SpellAbility(new ManaCostsImpl<>("{R}"), "damage 3", Zone.HAND); Ability ability = new EntersBattlefieldTriggeredAbility(new DamageMultiEffect()); @@ -263,14 +292,12 @@ public class TargetPriorityTest extends CardTestPlayerBaseAI { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "damage 3"); - // must damage x3 Balduvian Bears by -1 to keep alive - checkDamage("pt after", 1, PhaseStep.BEGIN_COMBAT, playerA, "Balduvian Bears", 1); - // showBattlefield("after", 1, PhaseStep.BEGIN_COMBAT, playerA); + // up to target is optional, so AI must choose nothing due only bad targets setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "damage 3", 1); - + assertLife(playerA, 20); + assertLife(playerB, 20); assertPermanentCount(playerA, "Memnite", 3); assertPermanentCount(playerA, "Balduvian Bears", 3); assertPermanentCount(playerA, "Ashcoat Bear", 3); @@ -280,7 +307,7 @@ public class TargetPriorityTest extends CardTestPlayerBaseAI { @Test @Ignore // do not enable it in production, only for devs - public void test_targetAmount_Performance() { + public void test_TargetAmount_Performance() { int cardsMultiplier = 3; Ability ability = new SimpleActivatedAbility(Zone.ALL, new DamageMultiEffect(), new ManaCostsImpl<>("{R}")); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CyclingTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CyclingTest.java index cbc4742c9a4..04696cceb3a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CyclingTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CyclingTest.java @@ -61,6 +61,24 @@ public class CyclingTest extends CardTestPlayerBase { assertPowerToughness(playerB, "Pillarfield Ox", 0, 2); } + /** + * Tests that X value is correctly read by the resulting triggered ability + */ + @Test + public void cycleSharkTyphoon() { + addCard(Zone.HAND, playerA, "Shark Typhoon", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 8); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cycling"); + setChoice(playerA, "X=6"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertGraveyardCount(playerA, "Shark Typhoon", 1); + assertPowerToughness(playerA, "Shark Token", 6, 6); + assertTappedCount("Island", true, 8); + } + /** * Cycle from graveyard or battlefield should not work. */ diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DayNightTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DayNightTest.java index 3ce078d3f4d..3a58e0dad27 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DayNightTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DayNightTest.java @@ -1,8 +1,10 @@ package org.mage.test.cards.abilities.keywords; +import mage.cards.Card; import mage.constants.PhaseStep; import mage.constants.Zone; import mage.game.permanent.Permanent; +import mage.util.CardUtil; import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; @@ -59,6 +61,41 @@ public class DayNightTest extends CardTestPlayerBase { assertRuffianSmasher(true); } + @Test + public void testCopy() { + // possible bug: stack overflow on copy + addCard(Zone.HAND, playerA, ruffian); + + runCode("copy", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { + Card card = currentGame.getCards().stream().filter(c -> c.getName().equals(ruffian)).findFirst().orElse(null); + Assert.assertNotNull(card); + Assert.assertNotNull(card.getSecondCardFace()); + + // original + Assert.assertNotNull(card.getSecondCardFace()); + // copy + Card copy = card.copy(); + Assert.assertNotNull(copy.getSecondCardFace()); + // deep copy + copy = CardUtil.deepCopyObject(card); + Assert.assertNotNull(copy.getSecondCardFace()); + + // copied + Card copied = game.copyCard(card, null, playerA.getId()); + Assert.assertNotNull(copied.getSecondCardFace()); + // copy + copy = copied.copy(); + Assert.assertNotNull(copy.getSecondCardFace()); + // deep copy + copy = CardUtil.deepCopyObject(copied); + Assert.assertNotNull(copy.getSecondCardFace()); + }); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + } + @Test public void testNightbound() { currentGame.setDaytime(false); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/WardTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/WardTest.java index 323d9b4cdd3..d34f5d2863c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/WardTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/WardTest.java @@ -1,5 +1,6 @@ package org.mage.test.cards.abilities.keywords; +import mage.abilities.keyword.FlyingAbility; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; @@ -80,4 +81,115 @@ public class WardTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Roaming Throne", 1); assertDamageReceived(playerB, "Roaming Throne", 0); } + + // Reported bug: #13523 - Ward not properly triggering when re-casting Aura + + private static final String creature = "Owlin Shieldmage"; // 3/3 Flying, Ward - Pay 3 life + private static final String aura = "Kenrith's Transformation"; // 1G enchanted creature loses all abilities and is 3/3 Elk (also draw card on ETB) + private static final String spell = "Beast Within"; // 2G destroy permanent, controller gets 3/3 Beast + private static final String regrowth = "Regrowth"; // 1G return target card from graveyard to hand + + @Test + public void wardRecastAuraNoPay() { + + addCard(Zone.BATTLEFIELD, playerB, creature); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 9); + addCard(Zone.HAND, playerA, aura); + addCard(Zone.HAND, playerA, spell); + addCard(Zone.HAND, playerA, regrowth); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, aura, creature); + setChoice(playerA, false); // don't pay for ward + + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, regrowth, aura); + + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, aura, creature); + setChoice(playerA, false); // don't pay for ward + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertGraveyardCount(playerA, aura, 1); + assertGraveyardCount(playerA, regrowth, 1); + assertGraveyardCount(playerA, 2); + assertHandCount(playerA, spell, 1); + assertHandCount(playerA, 1); + assertAbility(playerB, creature, FlyingAbility.getInstance(), true); + + } + + @Test + public void wardRecastAuraPaySecond() { + + addCard(Zone.BATTLEFIELD, playerB, creature); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 9); + addCard(Zone.HAND, playerA, aura); + addCard(Zone.HAND, playerA, spell); + addCard(Zone.HAND, playerA, regrowth); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, aura, creature); + setChoice(playerA, false); // don't pay for ward + + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, regrowth, aura); + + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, aura, creature); + setChoice(playerA, true); // pay ward + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 17); + assertGraveyardCount(playerA, aura, 0); + assertGraveyardCount(playerA, regrowth, 1); + assertGraveyardCount(playerA, 1); + assertHandCount(playerA, spell, 1); + assertHandCount(playerA, 2); // one draw from aura entering + assertAttachedTo(playerB, aura, creature, true); + assertAbility(playerB, creature, FlyingAbility.getInstance(), false); + + } + + @Test + public void wardRecastAuraPayBoth() { + + addCard(Zone.BATTLEFIELD, playerB, creature); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 9); + addCard(Zone.HAND, playerA, aura); + addCard(Zone.HAND, playerA, spell); + addCard(Zone.HAND, playerA, regrowth); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, aura, creature); + setChoice(playerA, true); // pay for ward + + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, spell, aura); // destroy aura + + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, regrowth, aura); + + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, aura, creature); + setChoice(playerA, true); // pay ward + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 14); + assertGraveyardCount(playerA, spell, 1); + assertGraveyardCount(playerA, regrowth, 1); + assertGraveyardCount(playerA, 2); + assertHandCount(playerA, 2); // two draws from aura entering + assertAttachedTo(playerB, aura, creature, true); + assertAbility(playerB, creature, FlyingAbility.getInstance(), false); + + } + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/OneShotNonTargetTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/OneShotNonTargetTest.java index 686b7ae7597..0475b151603 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/OneShotNonTargetTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/OneShotNonTargetTest.java @@ -74,4 +74,70 @@ public class OneShotNonTargetTest extends CardTestPlayerBase { assertPowerToughness(playerA, "Squire", 3, 4); assertPowerToughness(playerA, "Soldier Token", 2, 2); } + + @Test + public void MuseVesselTest() { + String muse = "Muse Vessel"; + addCard(Zone.HAND, playerA, muse); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 30); + addCard(Zone.BATTLEFIELD, playerA, "Vizier of Tumbling Sands", 2); + + addCard(Zone.HAND, playerA, "Squire"); + addCard(Zone.HAND, playerA, "Alpha Myr"); + addCard(Zone.HAND, playerA, "Void Snare"); + addCard(Zone.HAND, playerB, "Island"); + addCard(Zone.HAND, playerB, "Corridor Monitor"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, muse, true); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}, {T}: Target player", playerB); + setChoice(playerB, "Island"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Untap", muse); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}, {T}: Target player", playerB); + setChoice(playerB, "Corridor Monitor"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Untap", muse); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}, {T}: Target player", playerA); + setChoice(playerA, "Squire"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}: Choose"); + setChoice(playerA, "Island"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}: Choose"); + setChoice(playerA, "Squire"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Squire", true); + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Island"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Void Snare", muse, true); // Bounce the vessel to hand, check exile ID correctly managed + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, muse, true); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{1}: Choose"); // Should activate but no possible choices + + waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{3}, {T}: Target player", playerA); + setChoice(playerA, "Alpha Myr"); + waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{1}: Choose"); + setChoice(playerA, "Alpha Myr"); + checkPlayableAbility("Can cast on current turn", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Alpha Myr", true); + checkPlayableAbility("Can't cast on future turn", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Alpha Myr", false); + + activateAbility(3, PhaseStep.BEGIN_COMBAT, playerA, "{1}: Choose"); + setChoice(playerA, "Alpha Myr"); + castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Alpha Myr"); + + setStrictChooseMode(true); + setStopAt(3, PhaseStep.END_TURN); + execute(); + assertGraveyardCount(playerA, 1); // Void Snare + assertGraveyardCount(playerB, 0); + assertExileCount(playerA, 0); + assertExileCount(playerB, 1); // Corridor Monitor remains in exile + assertPermanentCount(playerA, "Island", 1); + assertPermanentCount(playerA, "Squire", 1); + assertPermanentCount(playerA, "Alpha Myr", 1); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/SearchNameExileTests.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/SearchNameExileTests.java index 71e83ef6543..3a0019ed703 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/SearchNameExileTests.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/SearchNameExileTests.java @@ -125,9 +125,9 @@ public class SearchNameExileTests extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Test of Talents", 1); addCard(Zone.BATTLEFIELD, playerA, "Island", 2); - addCard(Zone.GRAVEYARD, playerB, "Ready // Willing", 1); + addCard(Zone.GRAVEYARD, playerB, "Ready // Willing", 2); addCard(Zone.HAND, playerB, "Ready // Willing", 2); - addCard(Zone.LIBRARY, playerB, "Ready // Willing", 1); + addCard(Zone.LIBRARY, playerB, "Ready // Willing", 2); addCard(Zone.BATTLEFIELD, playerB, "Plains", 2); addCard(Zone.BATTLEFIELD, playerB, "Forest", 2); addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); @@ -137,7 +137,7 @@ public class SearchNameExileTests extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Test of Talents", "Ready // Willing", "Ready // Willing"); // TODO: a non strict cause a good AI choice test - make strict and duplicate as really AI test? - // in non strict mode AI must choose as much as possible in good "up to" target and half in bad target + // in non strict mode AI must choose as much as possible from grave/library due good exile effect/cost setStrictChooseMode(false); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -149,6 +149,6 @@ public class SearchNameExileTests extends CardTestPlayerBase { assertHandCount(playerB, "Ready // Willing", 0); assertHandCount(playerB, 1); //add 2, cast 1, last is exiled+redrawn - assertExileCount(playerB, "Ready // Willing", 4); + assertExileCount(playerB, "Ready // Willing", 6); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/ImpelledGiantTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/ImpelledGiantTest.java index 8a556458f3e..65858a16f46 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/ImpelledGiantTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/ImpelledGiantTest.java @@ -15,7 +15,7 @@ public class ImpelledGiantTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Impelled Giant"); // Creature 3/3 addCard(Zone.BATTLEFIELD, playerA, "Hurloon Minotaur"); // Creature 2/3 - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tap an untapped red creature you control other than Impelled Giant"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tap an untapped red creature you control other than"); setChoice(playerA, "Hurloon Minotaur"); setStopAt(1, PhaseStep.BEGIN_COMBAT); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/asthough/PlayTopCardFromLibraryTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/asthough/PlayTopCardFromLibraryTest.java index 126a34706ff..217d755e029 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/asthough/PlayTopCardFromLibraryTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/asthough/PlayTopCardFromLibraryTest.java @@ -2,13 +2,15 @@ package org.mage.test.cards.asthough; import mage.constants.PhaseStep; import mage.constants.Zone; +import mage.player.ai.ComputerPlayer7; +import org.junit.Ignore; import org.junit.Test; -import org.mage.test.serverside.base.CardTestPlayerBase; +import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps; /** * @author JayDi85 */ -public class PlayTopCardFromLibraryTest extends CardTestPlayerBase { +public class PlayTopCardFromLibraryTest extends CardTestPlayerBaseWithAIHelps { /* Bolas's Citadel @@ -218,4 +220,146 @@ public class PlayTopCardFromLibraryTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Balduvian Bears", 0); assertPermanentCount(playerA, "Balduvian Bears", 1); } + + @Test + public void test_EtaliPrimalStorm_NoCards_Manual() { + removeAllCardsFromLibrary(playerA); + removeAllCardsFromLibrary(playerB); + + // Whenever Etali, Primal Storm attacks, exile the top card of each player's library, + // then you may cast any number of nonland cards exiled this way without paying their mana costs. + addCard(Zone.BATTLEFIELD, playerA, "Etali, Primal Storm", 1); // 6/6 + // + addCard(Zone.LIBRARY, playerA, "Forest", 1); + addCard(Zone.LIBRARY, playerB, "Forest", 1); + + // nothing to free cast + attack(1, playerA, "Etali, Primal Storm"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerB, 20 - 6); + } + + @Test + public void test_EtaliPrimalStorm_NoCards_AI() { + removeAllCardsFromLibrary(playerA); + removeAllCardsFromLibrary(playerB); + + // Whenever Etali, Primal Storm attacks, exile the top card of each player's library, + // then you may cast any number of nonland cards exiled this way without paying their mana costs. + addCard(Zone.BATTLEFIELD, playerA, "Etali, Primal Storm", 1); // 6/6 + // + addCard(Zone.LIBRARY, playerA, "Forest", 1); + addCard(Zone.LIBRARY, playerB, "Forest", 1); + + // ai must attack and nothing to free cast + attack(1, playerA, "Etali, Primal Storm"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerB, 20 - 6); + } + + @Test + public void test_EtaliPrimalStorm_OneCard_Manual() { + removeAllCardsFromLibrary(playerA); + removeAllCardsFromLibrary(playerB); + + // Whenever Etali, Primal Storm attacks, exile the top card of each player's library, + // then you may cast any number of nonland cards exiled this way without paying their mana costs. + addCard(Zone.BATTLEFIELD, playerA, "Etali, Primal Storm", 1); // 6/6 + // + addCard(Zone.LIBRARY, playerA, "Lightning Bolt", 1); + addCard(Zone.LIBRARY, playerB, "Forest", 1); + + attack(1, playerA, "Etali, Primal Storm"); + setChoice(playerA, true); // use free cast + addTarget(playerA, playerB); // to damage + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerB, 20 - 6 - 3); + } + + @Test + public void test_EtaliPrimalStorm_OneCard_AI() { + removeAllCardsFromLibrary(playerA); + removeAllCardsFromLibrary(playerB); + + // Whenever Etali, Primal Storm attacks, exile the top card of each player's library, + // then you may cast any number of nonland cards exiled this way without paying their mana costs. + addCard(Zone.BATTLEFIELD, playerA, "Etali, Primal Storm", 1); // 6/6 + // + addCard(Zone.LIBRARY, playerA, "Lightning Bolt", 1); + addCard(Zone.LIBRARY, playerB, "Forest", 1); + + // ai must attack and free cast bolt to opponent's + aiPlayStep(1, PhaseStep.DECLARE_ATTACKERS, playerA); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerB, 20 - 6 - 3); + } + + @Test + public void test_EtaliPrimalStorm_MultipleCards_Manual() { + removeAllCardsFromLibrary(playerA); + removeAllCardsFromLibrary(playerB); + + // Whenever Etali, Primal Storm attacks, exile the top card of each player's library, + // then you may cast any number of nonland cards exiled this way without paying their mana costs. + addCard(Zone.BATTLEFIELD, playerA, "Etali, Primal Storm", 1); // 6/6 + // + addCard(Zone.LIBRARY, playerA, "Lightning Bolt", 1); // 3 damage + addCard(Zone.LIBRARY, playerB, "Cleansing Screech", 1); // 4 damage + + // choose cards one by one + attack(1, playerA, "Etali, Primal Storm"); + // first card + setChoice(playerA, "Cleansing Screech"); + setChoice(playerA, true); // use free + addTarget(playerA, playerB); + // last card (auto-chosen) + setChoice(playerA, true); // use free + addTarget(playerA, playerB); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerB, 20 - 6 - 4 - 3); + } + + @Test + public void test_EtaliPrimalStorm_MultipleCards_AI() { + removeAllCardsFromLibrary(playerA); + removeAllCardsFromLibrary(playerB); + + // Whenever Etali, Primal Storm attacks, exile the top card of each player's library, + // then you may cast any number of nonland cards exiled this way without paying their mana costs. + addCard(Zone.BATTLEFIELD, playerA, "Etali, Primal Storm", 1); // 6/6 + // + addCard(Zone.LIBRARY, playerA, "Lightning Bolt", 1); // 3 damage + addCard(Zone.LIBRARY, playerB, "Cleansing Screech", 1); // 4 damage + + // ai must attack and free cast two cards + // possible bug 1: game freeze due wrong dialog/selection logic + // possible bug 2: TargetCard can't find ALL zone + aiPlayStep(1, PhaseStep.DECLARE_ATTACKERS, playerA); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerB, 20 - 6 - 4 - 3); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControlTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControlTest.java index 5da74079cf0..9114099f95c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControlTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControlTest.java @@ -183,12 +183,13 @@ public class ExileAndReturnUnderYourControlTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Villainous Wealth", playerB); setChoice(playerA, "X=3"); + // first card setChoice(playerA, "Mox Emerald"); setChoice(playerA, "Yes"); - + // second card setChoice(playerA, "Mox Sapphire"); setChoice(playerA, "Yes"); - + // last card // Quicken is auto-chosen since it's the last of the 3 cards. Only need to say Yes to casting for free. setChoice(playerA, "Yes"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopyPermanentSpellTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopyPermanentSpellTest.java index edda38ee472..7c5caeba8ef 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopyPermanentSpellTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopyPermanentSpellTest.java @@ -63,20 +63,23 @@ public class CopyPermanentSpellTest extends CardTestPlayerBase { public void testAuraTokenRedirect() { makeTester(); addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); - addCard(Zone.BATTLEFIELD, playerB, "Centaur Courser"); - addCard(Zone.BATTLEFIELD, playerB, "Hill Giant"); + addCard(Zone.BATTLEFIELD, playerB, "Centaur Courser"); // 3/3 + addCard(Zone.BATTLEFIELD, playerB, "Serra Angel"); // 4/4 addCard(Zone.HAND, playerA, "Dead Weight"); - setChoice(playerA, true); + setChoice(playerA, true); // use new target castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Dead Weight", "Centaur Courser"); + // it's bad/unboost effect + // allow AI make a choice for new target of copied spell (it will be angel as a opponent's bigger creature for bad effect) + setStrictChooseMode(false); setStopAt(1, PhaseStep.END_TURN); execute(); assertPermanentCount(playerB, "Centaur Courser", 1); - assertPowerToughness(playerB, "Centaur Courser", 1, 1); - assertPermanentCount(playerB, "Hill Giant", 1); - assertPowerToughness(playerB, "Hill Giant", 1, 1); + assertPowerToughness(playerB, "Centaur Courser", 3 - 2, 3 - 2); + assertPermanentCount(playerB, "Serra Angel", 1); + assertPowerToughness(playerB, "Serra Angel", 4 - 2, 4 - 2); assertPermanentCount(playerA, "Dead Weight", 2); } @@ -152,23 +155,26 @@ public class CopyPermanentSpellTest extends CardTestPlayerBase { public void testBestowRedirect() { makeTester(); addCard(Zone.BATTLEFIELD, playerA, "Island", 5); - addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); - addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); // 2/2 + addCard(Zone.BATTLEFIELD, playerA, "Arbor Elf"); // 1/1 addCard(Zone.HAND, playerA, "Nimbus Naiad"); - setChoice(playerA, true); + setChoice(playerA, true); // change target castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nimbus Naiad using bestow", "Grizzly Bears"); + // it's good/boost effect + // allow AI make a choice for new target of copied spell (it will be bear as a bigger creature for good effect) + setStrictChooseMode(false); setStopAt(1, PhaseStep.END_TURN); execute(); assertPermanentCount(playerA, "Grizzly Bears", 1); - assertPowerToughness(playerA, "Grizzly Bears", 4, 4); + assertPowerToughness(playerA, "Grizzly Bears", 2 + 2 + 2, 2 + 2 + 2); assertAbility(playerA, "Grizzly Bears", FlyingAbility.getInstance(), true); - assertPermanentCount(playerA, "Silvercoat Lion", 1); - assertPowerToughness(playerA, "Silvercoat Lion", 4, 4); - assertAbility(playerA, "Silvercoat Lion", FlyingAbility.getInstance(), true); + assertPermanentCount(playerA, "Arbor Elf", 1); + assertPowerToughness(playerA, "Arbor Elf", 1, 1); + assertAbility(playerA, "Arbor Elf", FlyingAbility.getInstance(), false); assertPermanentCount(playerA, "Nimbus Naiad", 2); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/JaceTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/JaceTest.java index 811f814d21c..2007c6082d4 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/JaceTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/JaceTest.java @@ -67,7 +67,7 @@ public class JaceTest extends CardTestPlayerBase { setStopAt(3, PhaseStep.BEGIN_COMBAT); execute(); - assertGraveyardCount(playerA, "Pillarfield Ox", 1); + assertGraveyardCount(playerA, "Pillarfield Ox", 1); // must discard a creature and keep land card assertExileCount("Jace, Vryn's Prodigy", 0); assertPermanentCount(playerA, "Jace, Telepath Unbound", 1); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/VivienTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/VivienTest.java index 3b6f1720316..4650755a7dc 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/VivienTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/VivienTest.java @@ -14,19 +14,22 @@ import org.mage.test.serverside.base.CardTestPlayerBase; public class VivienTest extends CardTestPlayerBase { @Test - public void testVivienArkbowRangerAbility1NoTargets() { - setStrictChooseMode(true); + public void test_Distribute_NoTargets() { // +1: Distribute two +1/+1 counters among up to two target creatures. They gain trample until end of turn. // −3: Target creature you control deals damage equal to its power to target creature or planeswalker. // −5: You may choose a creature card you own from outside the game, reveal it, and put it into your hand. addCard(Zone.HAND, playerA, "Vivien, Arkbow Ranger"); // Planeswalker {1}{G}{G}{G} - starts with 4 Loyality counters addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); + // You can activate Vivien’s first ability without choosing any target creatures. The counters won’t be + // put on anything. This is a change from previous rules regarding distributing counters. + // (2019-07-12) + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Vivien, Arkbow Ranger", true); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Distribute"); addTargetAmount(playerA, TestPlayer.TARGET_SKIP); // stop choosing (not targets) - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Distribute"); - + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -36,8 +39,7 @@ public class VivienTest extends CardTestPlayerBase { } @Test - public void testVivienArkbowRangerAbilityOnePossibleTargetWithOne() { - setStrictChooseMode(true); + public void test_Distribute_OneTarget() { // +1: Distribute two +1/+1 counters among up to two target creatures. They gain trample until end of turn. // −3: Target creature you control deals damage equal to its power to target creature or planeswalker. // −5: You may choose a creature card you own from outside the game, reveal it, and put it into your hand. @@ -49,16 +51,16 @@ public class VivienTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Vivien, Arkbow Ranger", true); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Distribute"); - addTargetAmount(playerA, "Silvercoat Lion", 1); - addTargetAmount(playerA, TestPlayer.TARGET_SKIP); // stop choosing (one target) + addTargetAmount(playerA, "Silvercoat Lion", 2); + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); assertPermanentCount(playerA, "Vivien, Arkbow Ranger", 1); assertCounterCount("Vivien, Arkbow Ranger", CounterType.LOYALTY, 5); - assertPowerToughness(playerB, "Silvercoat Lion", 2 + 1, 2 + 1); + assertPowerToughness(playerB, "Silvercoat Lion", 2 + 2, 2 + 2); } @Test diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/afc/MantleOfTheAncientsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/afc/MantleOfTheAncientsTest.java new file mode 100644 index 00000000000..e425d65dc53 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/afc/MantleOfTheAncientsTest.java @@ -0,0 +1,70 @@ +package org.mage.test.cards.single.afc; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.player.TestPlayer; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * {@link mage.cards.m.MantleOfTheAncients Mantle of the Ancients} + * {3}{W}{W} + * Enchantment — Aura + * Enchant creature you control + * When this Aura enters, return any number of target Aura and/or Equipment cards from your graveyard to the battlefield attached to enchanted creature. + * Enchanted creature gets +1/+1 for each Aura and Equipment attached to it. + * + * @author notgreat + */ +public class MantleOfTheAncientsTest extends CardTestPlayerBase { + + /** + * Ensure that cards that can't be attached are not returned, and that cards that can be are correctly attached + */ + @Test + public void testCardReturnsCorrectAttachments() { + String creature = "Skylasher";// Protection from Blue, 2/2 Creature and +1/+1 from first Mantle + + addCard(Zone.HAND, playerA, "Mantle of the Ancients", 2); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 10); + addCard(Zone.BATTLEFIELD, playerA, creature); + addCard(Zone.BATTLEFIELD, playerA, "Grim Guardian"); // Counts number of enchantments entering + + addCard(Zone.GRAVEYARD, playerA, "Konda's Banner"); // No attach, Not legendary, but is returned + addCard(Zone.GRAVEYARD, playerA, "O-Naginata"); // Yes attach, Pow >= 3 + + addCard(Zone.GRAVEYARD, playerA, "Aether Tunnel"); // No attach, Pro Blue, then Yes attach on 2nd try + addCard(Zone.GRAVEYARD, playerA, "Reprobation"); // Yes attach, Enchant Creature and removes Pro Blue ability + addCard(Zone.GRAVEYARD, playerA, "Indestructibility"); // Yes attach, Enchant Permanent + addCard(Zone.GRAVEYARD, playerA, "Abundant Growth"); // No attach, Enchant Land + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mantle of the Ancients", creature); + setChoice(playerA, "Constellation"); //Stack trigger, Mantle + Grim + addTarget(playerA, "Konda's Banner^O-Naginata^Aether Tunnel^Reprobation^Indestructibility^Abundant Growth"); + setChoice(playerA, "Constellation"); //Stack trigger, Grim x2 + checkPermanentCount("Gate Smasher not returned", 1, PhaseStep.BEGIN_COMBAT, playerA, "Gate Smasher",0); + checkPermanentCount("Aether Tunnel not returned", 1, PhaseStep.BEGIN_COMBAT, playerA, "Aether Tunnel",0); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Mantle of the Ancients", creature); + setChoice(playerA, "Constellation"); //Stack trigger, Mantle -> Grim + addTarget(playerA, "Gate Smasher^Aether Tunnel"); + addTarget(playerA, TestPlayer.TARGET_SKIP); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertAttachedTo(playerA, "Konda's Banner", creature, false); + assertPermanentCount(playerA, "Konda's Banner", 1); + assertAttachedTo(playerA, "O-Naginata", creature, true); + + assertAttachedTo(playerA, "Aether Tunnel", creature, true); + assertAttachedTo(playerA, "Reprobation", creature, true); + assertAttachedTo(playerA, "Indestructibility", creature, true); + assertPermanentCount(playerA, "Abundant Growth", 0); + + assertPermanentCount(playerA, "Mantle of the Ancients", 2); + assertPowerToughness(playerA, creature, 16, 13); // base 0/1, 6 attachments so +12/+12, O-Naginata plus Aether Tunnel +4/+0 + assertLife(playerB, 15); // Mantle, Reprobation, Indestructibility + Mantle, Aether Tunnel + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/blb/AlaniaDivergentStormTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/blb/AlaniaDivergentStormTest.java index eb1bb871feb..094831ef36e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/blb/AlaniaDivergentStormTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/blb/AlaniaDivergentStormTest.java @@ -33,8 +33,8 @@ public class AlaniaDivergentStormTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, alania, true); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Coruscation Mage", true); setChoice(playerA, "No"); // Offspring? + addTarget(playerA, playerB); // Who draws? setChoice(playerA, "Yes"); // Copy spell? - setChoice(playerA, "PlayerB"); // Who draws? setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); @@ -61,8 +61,8 @@ public class AlaniaDivergentStormTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, alania, true); castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Stormcatch Mentor", true); + addTarget(playerA, playerB); // Who draws? setChoice(playerA, "Yes"); // Copy spell? - setChoice(playerA, "PlayerB"); // Who draws? castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Coruscation Mage", true); setChoice(playerA, "No"); // Offspring? @@ -93,16 +93,16 @@ public class AlaniaDivergentStormTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, alania, true); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Frolicking Familiar", true); + addTarget(playerA, playerB); // Who draws? setChoice(playerA, "Yes"); // Copy spell? - setChoice(playerA, "PlayerB"); // Who draws? castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Coruscation Mage", true); setChoice(playerA, "No"); // Offspring? castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Blow Off Steam", true); setChoice(playerA, "Whenever you cast an instant", 2); // Add Frolicking Familiar triggers first setChoice(playerA, "Whenever you cast a noncreature"); // Add Coruscation Mage trigger // Alania's trigger will add last + addTarget(playerA, playerB); // Who draws? setChoice(playerA, "Yes"); // Copy spell? - setChoice(playerA, "PlayerB"); // Who draws? addTarget(playerA, playerB); setChoice(playerA, "No"); // Change target? @@ -137,8 +137,8 @@ public class AlaniaDivergentStormTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, alania, true); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Acrobatic Leap", true); + addTarget(playerA, playerB); // Who draws? setChoice(playerA, "Yes"); // Copy spell? - setChoice(playerA, "PlayerB"); // Who draws? addTarget(playerA, alania); // Target creature setChoice(playerA, "No"); // Change target? castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ancestral Recall", true); @@ -170,8 +170,8 @@ public class AlaniaDivergentStormTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, alania, true); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gift of the Fae", true); + addTarget(playerA, playerB); // Who draws? setChoice(playerA, "Yes"); // Copy spell? - setChoice(playerA, "PlayerB"); // Who draws? addTarget(playerA, alania); // Target creature setChoice(playerA, "No"); // Change target? castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Maximize Velocity", true); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/SoulSeizerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/SoulSeizerTest.java index 1b904c4f136..7219846c3c3 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/SoulSeizerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/SoulSeizerTest.java @@ -19,7 +19,11 @@ public class SoulSeizerTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Craw Wurm"); attack(1, playerA, "Soul Seizer"); + addTarget(playerA, "Craw Wurm"); + setChoice(playerA, true); + setStopAt(1, PhaseStep.END_COMBAT); + setStrictChooseMode(true); execute(); assertLife(playerA, 20); @@ -38,8 +42,13 @@ public class SoulSeizerTest extends CardTestPlayerBase { attack(1, playerA, "Soul Seizer"); + addTarget(playerA, "Craw Wurm"); + setChoice(playerA, true); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Clear", "Ghastly Haunting"); + setStopAt(2, PhaseStep.BEGIN_COMBAT); + setStrictChooseMode(true); execute(); assertLife(playerA, 20); @@ -59,7 +68,11 @@ public class SoulSeizerTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Battlegrowth", "Soul Seizer"); attack(1, playerA, "Soul Seizer"); + addTarget(playerA, "Craw Wurm"); + setChoice(playerA, true); + setStopAt(1, PhaseStep.END_COMBAT); + setStrictChooseMode(true); execute(); assertLife(playerA, 20); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dmc/TillerEngineTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dmc/TillerEngineTest.java index c58c16977b6..e76708cdfa7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/dmc/TillerEngineTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dmc/TillerEngineTest.java @@ -25,7 +25,7 @@ public class TillerEngineTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, land); playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, land); - setChoice(playerA, "Whenever a land enters"); // order triggers + setChoice(playerA, "Whenever a land you control enters"); // order triggers setModeChoice(playerA, "1"); setStrictChooseMode(true); @@ -45,7 +45,7 @@ public class TillerEngineTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, land); playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, land); - setChoice(playerA, "Whenever a land enters"); // order triggers + setChoice(playerA, "Whenever a land you control enters"); // order triggers setModeChoice(playerA, "2"); addTarget(playerA, centaur); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dsc/SoaringLightbringerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dsc/SoaringLightbringerTest.java new file mode 100644 index 00000000000..e7639577d15 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dsc/SoaringLightbringerTest.java @@ -0,0 +1,86 @@ +package org.mage.test.cards.single.dsc; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestCommander4Players; + +/** + * @author notgreat + */ +public class SoaringLightbringerTest extends CardTestCommander4Players { + + @Test + public void test_AttacksDoubled() { + addCard(Zone.BATTLEFIELD, playerA, "Soaring Lightbringer"); + addCard(Zone.BATTLEFIELD, playerA, "Memnite"); + + attack(1, playerA, "Soaring Lightbringer", playerB); + attack(1, playerA, "Memnite", playerB); + + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_COMBAT); + execute(); + + assertTappedCount("Glimmer Token", true, 1); + assertLife(playerB, 20 - 4 - 1 - 1); + } + + @Test + public void test_AttacksTwo() { + addCard(Zone.BATTLEFIELD, playerA, "Soaring Lightbringer"); + addCard(Zone.BATTLEFIELD, playerA, "Memnite"); + + attack(1, playerA, "Soaring Lightbringer", playerB); + attack(1, playerA, "Memnite", playerD); + + setChoice(playerA, "Whenever"); // Order triggers + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_COMBAT); + execute(); + + assertTappedCount("Glimmer Token", true, 2); + assertLife(playerB, 20 - 4 - 1); + assertLife(playerD, 20 - 1 - 1); + } + + @Test + public void test_AttacksPlaneswalker() { + addCard(Zone.BATTLEFIELD, playerD, "Soaring Lightbringer"); + addCard(Zone.BATTLEFIELD, playerD, "Memnite"); + addCard(Zone.HAND, playerA, "Nissa Revane"); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nissa Revane"); + attack(2, playerD, "Memnite", "Nissa Revane"); + + setStrictChooseMode(true); + setStopAt(2, PhaseStep.END_COMBAT); + execute(); + + assertPermanentCount(playerD, "Glimmer Token", 0); + assertCounterCount("Nissa Revane", CounterType.LOYALTY, 1); + } + + @Test + public void test_AttacksEnters() { + addCard(Zone.BATTLEFIELD, playerA, "Soaring Lightbringer"); + addCard(Zone.BATTLEFIELD, playerA, "Falconer Adept"); + + attack(1, playerA, "Falconer Adept", playerB); + setChoice(playerA, "Whenever"); // Order triggers + addTarget(playerA, playerC); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_COMBAT); + execute(); + + assertTappedCount("Glimmer Token", true, 1); + assertTappedCount("Bird Token", true, 1); + assertLife(playerB, 20 - 2 - 1); + assertLife(playerC, 20 - 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/grn/BeamsplitterMageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/grn/BeamsplitterMageTest.java index 80cfef86fb3..32ad4d316e8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/grn/BeamsplitterMageTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/grn/BeamsplitterMageTest.java @@ -9,11 +9,25 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * @author TheElk801 */ public class BeamsplitterMageTest extends CardTestPlayerBase { + /** + * 2/2 + *

+ * Whenever you cast an instant or sorcery spell that targets only Beamsplitter Mage, + * if you control one or more creatures that spell could target, choose one of those + * creatures. Copy that spell. The copy targets the chosen creature. + */ private static final String bsm = "Beamsplitter Mage"; + + /** + * Target creature gets +1/+1 until end of turn. + * Target creature gets +1/+1 until end of turn. + * Target creature gets +1/+1 until end of turn. + */ + private static final String seeds = "Seeds of Strength"; + private static final String lion = "Silvercoat Lion"; private static final String duelist = "Deft Duelist"; private static final String bolt = "Lightning Bolt"; - private static final String seeds = "Seeds of Strength"; @Test public void testLightningBolt() { @@ -24,7 +38,9 @@ public class BeamsplitterMageTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, bolt); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bolt, bsm); + setChoice(playerA, lion); // target for copied bolt + setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); execute(); @@ -45,12 +61,18 @@ public class BeamsplitterMageTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, bsm); addCard(Zone.HAND, playerA, seeds); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, seeds, bsm); + // put x3 targets to bsm and copy it to lion + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, seeds); + addTarget(playerA, bsm); + addTarget(playerA, bsm); + addTarget(playerA, bsm); + setChoice(playerA, lion); + setStrictChooseMode(true); setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); execute(); - assertPowerToughness(playerA, bsm, 5, 5); - assertPowerToughness(playerA, lion, 5, 5); + assertPowerToughness(playerA, bsm, 2 + 3, 2 + 3); + assertPowerToughness(playerA, lion, 2 + 3, 2 + 3); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/isd/HomicidalBruteTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/isd/HomicidalBruteTest.java index 165999433bb..0bfb2decd72 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/isd/HomicidalBruteTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/isd/HomicidalBruteTest.java @@ -84,4 +84,34 @@ public class HomicidalBruteTest extends CardTestPlayerBase { assertTapped("Homicidal Brute", true); } + @Test + public void testCardBlinkNotTransform() { + addCard(Zone.BATTLEFIELD, playerA, "Civilized Scholar"); + addCard(Zone.HAND, playerA, "Sejiri Merfolk"); + addCard(Zone.HAND, playerA, "Moonmist"); // transform all + addCard(Zone.HAND, playerA, "Cloudshift"); // blink + addCard(Zone.BATTLEFIELD, playerA, "Savannah", 3); + + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Draw a card, then discard a card."); + setChoice(playerA, "Sejiri Merfolk"); // discard creature + + attack(3, playerA, "Homicidal Brute", playerB); + castSpell(3, PhaseStep.COMBAT_DAMAGE, playerA, "Cloudshift", "Homicidal Brute"); + castSpell(3, PhaseStep.END_COMBAT, playerA, "Moonmist"); + + checkPermanentTapped("after transform", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Homicidal Brute", false, 1); + + setStrictChooseMode(true); + setStopAt(4, PhaseStep.UPKEEP); + execute(); + + assertGraveyardCount(playerA, "Cloudshift", 1); + assertGraveyardCount(playerA, "Moonmist", 1); + assertLife(playerA, 20); + assertLife(playerB, 15); + assertPermanentCount(playerA, "Civilized Scholar", 1); + assertPermanentCount(playerA, "Homicidal Brute", 0); + assertTapped("Civilized Scholar", true); + } + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/lci/BarracksOfTheThousandTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/lci/BarracksOfTheThousandTest.java index e8f4545b1e4..c9838655cbe 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/lci/BarracksOfTheThousandTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/lci/BarracksOfTheThousandTest.java @@ -56,23 +56,29 @@ public class BarracksOfTheThousandTest extends CardTestPlayerBase { } @Test - public void trigger_onlyonce_doublemana() { + public void trigger_onceTwice_doublemana() { setStrictChooseMode(true); - addCard(Zone.BATTLEFIELD, playerB, "Heartbeat of Spring"); + addCard(Zone.BATTLEFIELD, playerA, "Mana Reflection"); addCard(Zone.HAND, playerA, "Armored Warhorse"); + addCard(Zone.HAND, playerA, "Savannah Lions", 2); initToTransform(); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Armored Warhorse"); + checkPermanentCount("One Gnome Soldier Token", 1, PhaseStep.BEGIN_COMBAT, playerA, "Gnome Soldier Token", 1); - setStopAt(1, PhaseStep.BEGIN_COMBAT); + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Savannah Lions"); + waitStackResolved(3, PhaseStep.PRECOMBAT_MAIN); + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Savannah Lions"); + + setStopAt(3, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "Gnome Soldier Token", 1); + assertPermanentCount(playerA, "Gnome Soldier Token", 3); assertPermanentCount(playerA, "Armored Warhorse", 1); + assertPermanentCount(playerA, "Savannah Lions", 2); } - @Test public void noTrigger_NotPaidWithBarrack() { setStrictChooseMode(true); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/lci/TheMyriadPoolsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/lci/TheMyriadPoolsTest.java new file mode 100644 index 00000000000..573ee3a2d44 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/lci/TheMyriadPoolsTest.java @@ -0,0 +1,27 @@ +package org.mage.test.cards.single.lci; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class TheMyriadPoolsTest extends CardTestPlayerBase { + + @Test + public void castCopiesCorrectly() { + addCard(Zone.BATTLEFIELD, playerA, "The Myriad Pools"); + addCard(Zone.BATTLEFIELD, playerA, "Memnite"); + addCard(Zone.HAND, playerA, "Flying Men"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Flying Men"); + addTarget(playerA, "Memnite"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + setStrictChooseMode(true); + execute(); + + assertPermanentCount(playerA, "The Myriad Pools", 1); + assertPermanentCount(playerA, "Memnite", 0); + assertPermanentCount(playerA, "Flying Men", 2); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/otc/BladegriffPrototypeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/otc/BladegriffPrototypeTest.java new file mode 100644 index 00000000000..df140741b84 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/otc/BladegriffPrototypeTest.java @@ -0,0 +1,41 @@ +package org.mage.test.cards.single.otc; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class BladegriffPrototypeTest extends CardTestPlayerBase { + private static final String griff = "Bladegriff Prototype"; + + @Test + public void test_CanTargetOwn() { + setStrictChooseMode(true); + + addCard(Zone.BATTLEFIELD, playerB, "Squire"); + addCard(Zone.BATTLEFIELD, playerA, griff); + + attack(1, playerA, griff); + addTarget(playerB, "Squire"); + + setStopAt(1, PhaseStep.END_COMBAT); + execute(); + + assertGraveyardCount(playerB, "Squire", 1); + } + + @Test(expected=AssertionError.class) + public void test_CantTargetYours() { + setStrictChooseMode(true); + + addCard(Zone.BATTLEFIELD, playerB, "Squire"); + addCard(Zone.BATTLEFIELD, playerA, griff); + + attack(1, playerA, griff); + addTarget(playerB, griff); + + setStopAt(1, PhaseStep.END_COMBAT); + execute(); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/tdm/TaigamMasterOpportunistTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/tdm/TaigamMasterOpportunistTest.java index 9cda471dcce..dd0358703b5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/tdm/TaigamMasterOpportunistTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/tdm/TaigamMasterOpportunistTest.java @@ -20,6 +20,7 @@ public class TaigamMasterOpportunistTest extends CardTestPlayerBase { setStrictChooseMode(true); addCard(Zone.BATTLEFIELD, playerA, TAIGAM); + addCard(Zone.BATTLEFIELD, playerA, "Yawgmoth's Bargain"); // Can shuffle to the top of the library, prevent drawing it addCard(Zone.HAND, playerA, ORNITHOPTER); addCard(Zone.HAND, playerA, TWINMAW); addCard(Zone.BATTLEFIELD, playerA, "Plateau", 6); @@ -102,4 +103,4 @@ public class TaigamMasterOpportunistTest extends CardTestPlayerBase { } -} \ No newline at end of file +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/unf/CometStellarPupTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/unf/CometStellarPupTest.java index 5cca732151f..faa662bf787 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/unf/CometStellarPupTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/unf/CometStellarPupTest.java @@ -27,11 +27,7 @@ public class CometStellarPupTest extends CardTestPlayerBase { */ private final static String comet = "Comet, Stellar Pup"; - private final static String cometAbility = "0: Roll a six-sided die." - + "
1 or 2 — [+2], then create two 1/1 green Squirrel creature tokens. They gain haste until end of turn." - + "
3 — [-1], then return a card with mana value 2 or less from your graveyard to your hand." - + "
4 or 5 — {this} deals damage equal to the number of loyalty counters on him to a creature or player, then [-2]." - + "
6 — [+1], and you may activate Comet, Stellar Pup's loyalty ability two more times this turn."; + private final static String cometAbility = "0: Roll a six-sided die."; @Test public void testRoll1() { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/woc/UnfinishedBusinessTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/woc/UnfinishedBusinessTest.java index 0a6684a6bd3..31a630235e8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/woc/UnfinishedBusinessTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/woc/UnfinishedBusinessTest.java @@ -92,6 +92,7 @@ public class UnfinishedBusinessTest extends CardTestPlayerBase { // EEB should never have been attached and therefore the White knight should be untapped assertTapped(APOSTLE,false); assertAttachedTo(playerA, EEB, APOSTLE,false); + assertPermanentCount(playerA, EEB, 1); // Check that Ghoulflesh never entered the battlefield assertLife(playerA, 20); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/znr/YasharnImplacableEarthTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/znr/YasharnImplacableEarthTest.java index 5e3c2131f92..2daabf2511d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/znr/YasharnImplacableEarthTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/znr/YasharnImplacableEarthTest.java @@ -1,23 +1,22 @@ package org.mage.test.cards.single.znr; -import mage.cards.decks.Deck; import mage.constants.PhaseStep; import mage.constants.Zone; -import org.assertj.core.api.Assertions; import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * {@link mage.cards.y.YasharnImplacableEarth Yasharn, Implacable Earth} - * When Yasharn enters the battlefield, search your library for a basic Forest card and a basic Plains card, reveal those cards, put them into your hand, then shuffle. - * Players can’t pay life or sacrifice nonland permanents to cast spells or activate abilities. - * * @author Alex-Vasile */ public class YasharnImplacableEarthTest extends CardTestPlayerBase { + /** + * {@link mage.cards.y.YasharnImplacableEarth Yasharn, Implacable Earth} + * When Yasharn enters the battlefield, search your library for a basic Forest card and a basic Plains card, reveal those cards, put them into your hand, then shuffle. + * Players can’t pay life or sacrifice nonland permanents to cast spells or activate abilities. + */ private static final String yasharn = "Yasharn, Implacable Earth"; /** @@ -143,6 +142,8 @@ public class YasharnImplacableEarthTest extends CardTestPlayerBase { */ @Test public void canSacrificeLandToActivate() { + removeAllCardsFromLibrary(playerA); + addCard(Zone.BATTLEFIELD, playerA, yasharn); addCard(Zone.BATTLEFIELD, playerA, "Evolving Wilds"); addCard(Zone.LIBRARY, playerA, "Island"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/EnterLeaveBattlefieldExileTargetTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/EnterLeaveBattlefieldExileTargetTest.java index f334f88dba2..2217cb4ee82 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/EnterLeaveBattlefieldExileTargetTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/EnterLeaveBattlefieldExileTargetTest.java @@ -77,7 +77,8 @@ public class EnterLeaveBattlefieldExileTargetTest extends CardTestPlayerBase { // test NPE error while AI targeting battlefield with tokens // Flying - // When Angel of Serenity enters the battlefield, you may exile up to three other target creatures from the battlefield and/or creature cards from graveyards. + // When Angel of Serenity enters the battlefield, you may exile up to three other target creatures + // from the battlefield and/or creature cards from graveyards. addCard(Zone.HAND, playerA, "Angel of Serenity"); addCard(Zone.BATTLEFIELD, playerA, "Plains", 7); // @@ -98,6 +99,7 @@ public class EnterLeaveBattlefieldExileTargetTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Angel of Serenity"); setChoice(playerA, true); //addTarget(playerA, "Silvercoat Lion^Balduvian Bears"); // AI must target + //addTarget(playerA, TestPlayer.TARGET_SKIP); setStrictChooseMode(false); // AI must target setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToBattlefieldEffectsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToBattlefieldEffectsTest.java index ba897e5a889..f0b2d87c89f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToBattlefieldEffectsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToBattlefieldEffectsTest.java @@ -157,4 +157,62 @@ public class ReturnToBattlefieldEffectsTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Reassembling Skeleton", 1); } + + // issue #12974 + private static final String rOrb = "Resurrection Orb"; + // Whenever equipped creature dies, return that card to the battlefield under its owner's control at the beginning of the next end step. + private static final String lMiss = "Lone Missionary"; // ETB gain 4 + private static final String cFeeder = "Carrion Feeder"; // sacrifice a creature: +1/+1 counter + + @Test + public void testReturnAttachedToBattlefield() { + addCard(Zone.BATTLEFIELD, playerA, rOrb); + addCard(Zone.BATTLEFIELD, playerA, lMiss); + addCard(Zone.BATTLEFIELD, playerA, cFeeder); + addCard(Zone.BATTLEFIELD, playerA, "Wastes", 4); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip", lMiss); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice"); + setChoice(playerA, lMiss); + + setStrictChooseMode(true); + setStopAt(2, PhaseStep.UPKEEP); + execute(); + + assertLife(playerA, 24); + assertPermanentCount(playerA, lMiss, 1); + assertPowerToughness(playerA, cFeeder, 2, 2); + + } + + @Test + public void testNotReturnAttachedToBattlefieldAfterZoneChange() { + addCard(Zone.BATTLEFIELD, playerA, rOrb); + addCard(Zone.BATTLEFIELD, playerA, lMiss); + addCard(Zone.BATTLEFIELD, playerA, cFeeder); + addCard(Zone.BATTLEFIELD, playerA, "Wastes", 4); + addCard(Zone.BATTLEFIELD, playerB, "Crypt Creeper"); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip", lMiss); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice"); + setChoice(playerA, lMiss); + + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Sacrifice"); + addTarget(playerB, lMiss); + + setStrictChooseMode(true); + setStopAt(2, PhaseStep.UPKEEP); + execute(); + + assertLife(playerA, 20); + assertExileCount(playerA, lMiss, 1); + assertPowerToughness(playerA, cFeeder, 2, 2); + assertGraveyardCount(playerB, "Crypt Creeper", 1); + + } + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/watchers/AureliasFuryTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/watchers/AureliasFuryTest.java new file mode 100644 index 00000000000..ad26ba67646 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/watchers/AureliasFuryTest.java @@ -0,0 +1,71 @@ +package org.mage.test.cards.watchers; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author xenohedron + */ +public class AureliasFuryTest extends CardTestPlayerBase { + + // see issue #13774 + + private static final String fury = "Aurelia's Fury"; // XRW + // Aurelia’s Fury deals X damage divided as you choose among any number of targets. + // Tap each creature dealt damage this way. Players dealt damage this way can’t cast noncreature spells this turn. + + private static final String elementalist = "Ardent Elementalist"; // 3R 2/1 + // When this creature enters, return target instant or sorcery card from your graveyard to your hand. + private static final String hatchling = "Kraken Hatchling"; // 0/4 + private static final String glimmerbell = "Glimmerbell"; // 1/3 flying; 1U: untap ~ + private static final String crab = "Fortress Crab"; // 1/6 + + + @Test + public void testAureliasFury() { + addCard(Zone.BATTLEFIELD, playerA, "Plateau", 5 + 4 + 4); + addCard(Zone.BATTLEFIELD, playerA, hatchling); + addCard(Zone.BATTLEFIELD, playerB, glimmerbell); + addCard(Zone.BATTLEFIELD, playerB, crab); + addCard(Zone.HAND, playerA, fury); + addCard(Zone.HAND, playerA, elementalist); + addCard(Zone.BATTLEFIELD, playerB, "Island", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, fury); + setChoice(playerA, "X=3"); + addTargetAmount(playerA, hatchling, 2); + addTargetAmount(playerA, glimmerbell, 1); + + checkDamage("first cast", 1, PhaseStep.BEGIN_COMBAT, playerA, hatchling, 2); + checkDamage("first cast", 1, PhaseStep.BEGIN_COMBAT, playerB, glimmerbell, 1); + checkPermanentTapped("first cast", 1, PhaseStep.BEGIN_COMBAT, playerA, hatchling, true, 1); + checkPermanentTapped("first cast", 1, PhaseStep.BEGIN_COMBAT, playerB, glimmerbell, true, 1); + checkPermanentTapped("first cast", 1, PhaseStep.BEGIN_COMBAT, playerB, crab, false, 1); + + activateAbility(1, PhaseStep.END_COMBAT, playerB, "{1}{U}: Untap"); // untap glimmerbell + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, elementalist); + addTarget(playerA, fury); // return to hand + waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, fury); + setChoice(playerA, "X=2"); + addTargetAmount(playerA, crab, 1); + addTargetAmount(playerA, playerB, 1); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertDamageReceived(playerA, hatchling, 2); + assertDamageReceived(playerB, glimmerbell, 1); + assertDamageReceived(playerB, crab, 1); + assertLife(playerA, 20); + assertLife(playerB, 19); + assertTapped(hatchling, true); + assertTapped(glimmerbell, false); + assertTapped(crab, true); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/watchers/CathedralMembraneTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/watchers/CathedralMembraneTest.java new file mode 100644 index 00000000000..c1b47a2556d --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/watchers/CathedralMembraneTest.java @@ -0,0 +1,109 @@ +package org.mage.test.cards.watchers; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author xenohedron + */ +public class CathedralMembraneTest extends CardTestPlayerBase { + + // see issue #13774 + + private static final String cathedralMembrane = "Cathedral Membrane"; // 0/6 + // Defender + // When this creature dies during combat, it deals 6 damage to each creature it blocked this combat. + + private static final String wurm = "Autochthon Wurm"; // 9/14 convoke trample + private static final String gigantosaurus = "Gigantosaurus"; // 10/10 + + private static final String moraug = "Moraug, Fury of Akoum"; // 6/6 + // Each creature you control gets +1/+0 for each time it has attacked this turn. + // Landfall — Whenever a land you control enters, if it's your main phase, + // there's an additional combat phase after this phase. At the beginning of that combat, untap all creatures you control. + + private static final String recovery = "Miraculous Recovery"; // 4W instant + // Return target creature card from your graveyard to the battlefield. Put a +1/+1 counter on it. + + @Test + public void testMembraneTrigger() { + addCard(Zone.HAND, playerA, "Mountain"); + addCard(Zone.BATTLEFIELD, playerA, wurm); + addCard(Zone.BATTLEFIELD, playerA, gigantosaurus); + addCard(Zone.BATTLEFIELD, playerA, moraug); + addCard(Zone.HAND, playerB, cathedralMembrane); + addCard(Zone.HAND, playerB, recovery); + addCard(Zone.BATTLEFIELD, playerB, "Plains", 6); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, cathedralMembrane); + setChoice(playerB, true); // pay life + + attack(3, playerA, wurm, playerB); + + block(3, playerB, cathedralMembrane, wurm); + setChoiceAmount(playerA, 6); // assign trample damage + + setStrictChooseMode(true); + setStopAt(3, PhaseStep.END_TURN); + execute(); + + assertTapped(wurm, true); + assertTapped(gigantosaurus, false); + assertTapped(moraug, false); + assertGraveyardCount(playerB, cathedralMembrane, 1); + assertLife(playerA, 20); + assertLife(playerB, 20 - 2 - 4); + assertDamageReceived(playerA, wurm, 6); + assertDamageReceived(playerA, gigantosaurus, 0); + assertDamageReceived(playerA, moraug, 0); + + } + + @Test + public void testMembraneTriggerAgain() { + addCard(Zone.HAND, playerA, "Mountain"); + addCard(Zone.BATTLEFIELD, playerA, wurm); + addCard(Zone.BATTLEFIELD, playerA, gigantosaurus); + addCard(Zone.BATTLEFIELD, playerA, moraug); + addCard(Zone.HAND, playerB, cathedralMembrane); + addCard(Zone.HAND, playerB, recovery); + addCard(Zone.BATTLEFIELD, playerB, "Plains", 6); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, cathedralMembrane); + setChoice(playerB, true); // pay life + + attack(3, playerA, wurm, playerB); + + block(3, playerB, cathedralMembrane, wurm); + setChoiceAmount(playerA, 6); // assign trample damage + + setStrictChooseMode(true); + setStopAt(3, PhaseStep.END_COMBAT); + execute(); // separate execute needed to separate commands from second combat phase + + playLand(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Mountain"); + castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerB, recovery, cathedralMembrane); + + attack(3, playerA, wurm, playerB); + attack(3, playerA, gigantosaurus, playerB); + + block(3, playerB, cathedralMembrane, gigantosaurus); + + setStopAt(3, PhaseStep.END_TURN); + execute(); + + assertTapped(wurm, true); + assertTapped(gigantosaurus, true); + assertTapped(moraug, false); + assertGraveyardCount(playerB, cathedralMembrane, 1); + assertLife(playerA, 20); + assertLife(playerB, 20 - 2 - 4 - 11); + assertDamageReceived(playerA, wurm, 6); + assertDamageReceived(playerA, gigantosaurus, 1 + 6); + assertDamageReceived(playerA, moraug, 0); + + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/dialogs/TestableDialogsTest.java b/Mage.Tests/src/test/java/org/mage/test/dialogs/TestableDialogsTest.java new file mode 100644 index 00000000000..7a41de3d740 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/dialogs/TestableDialogsTest.java @@ -0,0 +1,328 @@ +package org.mage.test.dialogs; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.continuous.PlayAdditionalLandsAllEffect; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.utils.testers.TestableDialog; +import mage.utils.testers.TestableDialogsRunner; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.player.TestPlayer; +import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Try to test all possible game dialogs by TestableDialogsRunner + *

+ * TODO: fill ai results for all generated dialogs + * + * @author JayDi85 + */ +public class TestableDialogsTest extends CardTestPlayerBaseWithAIHelps { + + TestableDialogsRunner runner = new TestableDialogsRunner(); + Ability fakeAbility = new SimpleStaticAbility(new InfoEffect("fake")); + + @Test + public void test_RunSingle_Manual() { + prepareCards(); + + runCode("run single", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { + TestableDialog dialog = findDialog(runner, "target.choose(you, target)", "any 0-3"); + dialog.prepare(); + dialog.showDialog(playerA, fakeAbility, game, playerB); + }); + + // choice for 0-3 + setChoice(playerA, "Mountain"); + setChoice(playerA, "Mountain"); + setChoice(playerA, TestPlayer.CHOICE_SKIP); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + // it's ok to have wrong targets message cause manual testing selected x2, not AI's x3 + assertAndPrintRunnerResults(false, false); + } + + @Test + public void test_RunSingle_AI() { + prepareCards(); + + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, PhaseStep.END_TURN, playerA); + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, PhaseStep.END_TURN, playerB); + runCode("run single", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, (info, player, game) -> { + TestableDialog dialog = findDialog(runner, "target.choose(you, target)", "any 0-3"); + dialog.prepare(); + dialog.showDialog(playerA, fakeAbility, game, playerB); + }); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertAndPrintRunnerResults(false, true); + } + + @Test + public void test_RunAll_AI() { + // it's impossible to setup 700+ dialogs, so all choices made by AI + // current AI uses only simple choices in dialogs, not simulations + + prepareCards(); + + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, PhaseStep.END_TURN, playerA); + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, PhaseStep.END_TURN, playerB); + runCode("run all", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, (info, player, game) -> { + runner.getDialogs().forEach(dialog -> { + System.out.println(String.format("run testable dialog %d of %d (%s, %s - %s)", + dialog.getRegNumber(), + runner.getDialogs().size(), + dialog.getClass().getSimpleName(), + dialog.getGroup(), + dialog.getName() + )); + dialog.prepare(); + dialog.showDialog(playerA, fakeAbility, game, playerB); + }); + }); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertAndPrintRunnerResults(true, true); + } + + @Test + @Ignore // debug only - run single dialog by reg number + public void test_RunSingle_Debugging() { + int needRegNumber = 557; + + prepareCards(); + + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, PhaseStep.END_TURN, playerA); + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, PhaseStep.END_TURN, playerB); + runCode("run by number", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, (info, player, game) -> { + TestableDialog dialog = findDialog(runner, needRegNumber); + dialog.prepare(); + dialog.showDialog(playerA, fakeAbility, game, playerB); + }); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertAndPrintRunnerResults(false, true); + } + + private void prepareCards() { + // runner calls dialogs for both A and B, so players must have same cards + removeAllCardsFromLibrary(playerA); + removeAllCardsFromLibrary(playerB); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6); + addCard(Zone.HAND, playerA, "Forest", 6); + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 6); + addCard(Zone.HAND, playerB, "Forest", 6); + + runCode("restrict lands", 1, PhaseStep.UPKEEP, playerA, (info, player, game) -> { + // restrict any lands play, so AI will keep lands in hand + game.addEffect(new PlayAdditionalLandsAllEffect(-1), fakeAbility); + }); + } + + private TestableDialog findDialog(TestableDialogsRunner runner, String byGroup, String byName) { + List res = runner.getDialogs().stream() + .filter(dialog -> dialog.getGroup().equals(byGroup)) + .filter(dialog -> dialog.getName().equals(byName)) + .collect(Collectors.toList()); + Assert.assertEquals("must found only 1 dialog", 1, res.size()); + return res.get(0); + } + + private TestableDialog findDialog(TestableDialogsRunner runner, Integer byRegNumber) { + List res = runner.getDialogs().stream() + .filter(dialog -> dialog.getRegNumber().equals(byRegNumber)) + .collect(Collectors.toList()); + Assert.assertEquals("must found only 1 dialog", 1, res.size()); + return res.get(0); + } + + private void assertAndPrintRunnerResults(boolean showFullList, boolean failOnBadResults) { + // print table with full dialogs list and assert results + + // auto-size for columns + int maxNumberLength = "9999".length(); + int maxGroupLength = "Group".length(); + int maxNameLength = "Name".length(); + int maxResultLength = "Result".length(); + int needTotalsSize = 0; + for (TestableDialog dialog : runner.getDialogs()) { + if (!showFullList && !dialog.getResult().isFinished()) { + continue; + } + maxGroupLength = Math.max(maxGroupLength, dialog.getGroup().length()); + maxNameLength = Math.max(maxNameLength, dialog.getName().length()); + + // resize group to keep space for bigger total message like assert res + String resAssert = dialog.getResult().getResAssert(); + resAssert = resAssert == null ? "" : resAssert; + needTotalsSize = Math.max(needTotalsSize, dialog.getResult().getResDebugSource().length()); + needTotalsSize = Math.max(needTotalsSize, resAssert.length()); + int currentTotalsSize = maxNumberLength + maxGroupLength + maxNameLength + maxResultLength + 9; + if (currentTotalsSize < needTotalsSize) { + maxGroupLength = maxGroupLength + needTotalsSize - currentTotalsSize; + } + } + + String rowFormat = "| %-" + maxNumberLength + "s | %-" + maxGroupLength + "s | %-" + maxNameLength + "s | %-" + maxResultLength + "s |%n"; + String horizontalBorder = "+-" + + String.join("", Collections.nCopies(maxNumberLength, "-")) + "-+-" + + String.join("", Collections.nCopies(maxGroupLength, "-")) + "-+-" + + String.join("", Collections.nCopies(maxNameLength, "-")) + "-+-" + + String.join("", Collections.nCopies(maxResultLength, "-")) + "-+"; + String totalsLeftFormat = "| %-" + (maxNumberLength + maxGroupLength + maxNameLength + maxResultLength + 9) + "s |%n"; + String totalsRightFormat = "| %" + (maxNumberLength + maxGroupLength + maxNameLength + maxResultLength + 9) + "s |%n"; + + // print header row + System.out.println(horizontalBorder); + System.out.printf(rowFormat, "N", "Group", "Name", "Result"); + System.out.println(horizontalBorder); + + // print data rows + String prevGroup = ""; + int totalDialogs = 0; + int totalGood = 0; + int totalBad = 0; + int totalUnknown = 0; + TestableDialog firstBadDialog = null; + String firstBadAssert = ""; + String firstBadDebugSource = ""; + boolean usedHorizontalBorder = true; // mark that last print used horizontal border (fix duplicates) + Map coloredTexts = new HashMap<>(); // must colorize after string format to keep pretty table + for (TestableDialog dialog : runner.getDialogs()) { + if (!showFullList && !dialog.getResult().isFinished()) { + // print only required dialogs + continue; + } + totalDialogs++; + if (!prevGroup.isEmpty() && !prevGroup.equals(dialog.getGroup())) { + if (!usedHorizontalBorder) { + System.out.println(horizontalBorder); + usedHorizontalBorder = true; + } + } + prevGroup = dialog.getGroup(); + + // print dialog stats + String status; + coloredTexts.clear(); + String resAssert = dialog.getResult().getResAssert(); + String resDebugSource = dialog.getResult().getResDebugSource(); + String assertError = ""; + if (resAssert == null) { + totalUnknown++; + status = "?"; + coloredTexts.put("?", asYellow("?")); + } else if (resAssert.isEmpty()) { + totalGood++; + status = "OK"; + coloredTexts.put("OK", asGreen("OK")); + } else { + totalBad++; + status = "FAIL"; + coloredTexts.put("FAIL", asRed("FAIL")); + assertError = resAssert; + } + if (!assertError.isEmpty()) { + if (!usedHorizontalBorder) { + System.out.println(horizontalBorder); + usedHorizontalBorder = true; + } + } + System.out.print(getColoredRow(rowFormat, coloredTexts, dialog.getRegNumber(), dialog.getGroup(), dialog.getName(), status)); + usedHorizontalBorder = false; + + // print dialog error + if (!assertError.isEmpty()) { + coloredTexts.clear(); + coloredTexts.put(resAssert, asRed(resAssert)); + coloredTexts.put(resDebugSource, asRed(resDebugSource)); + String badAssert = getColoredRow(totalsRightFormat, coloredTexts, resAssert); + String badDebugSource = getColoredRow(totalsRightFormat, coloredTexts, resDebugSource); + if (firstBadDialog == null) { + firstBadDialog = dialog; + firstBadAssert = badAssert; + firstBadDebugSource = badDebugSource; + } + System.out.print(badAssert); + System.out.print(badDebugSource); + System.out.println(horizontalBorder); + usedHorizontalBorder = true; + } + } + if (!usedHorizontalBorder) { + System.out.println(horizontalBorder); + usedHorizontalBorder = true; + } + + // print totals + System.out.printf(totalsLeftFormat, "Total dialogs: " + totalDialogs); + usedHorizontalBorder = false; + String goodStats = String.format("%d good", totalGood); + String badStats = String.format("%d bad", totalBad); + String unknownStats = String.format("%d unknown", totalUnknown); + coloredTexts.clear(); + coloredTexts.put(goodStats, String.format("%s good", asGreen(String.valueOf(totalGood)))); + coloredTexts.put(badStats, String.format("%s bad", asRed(String.valueOf(totalBad)))); + coloredTexts.put(unknownStats, String.format("%s unknown", asYellow(String.valueOf(totalUnknown)))); + System.out.print(getColoredRow(totalsLeftFormat, coloredTexts, String.format("Total results: %s, %s, %s", + goodStats, badStats, unknownStats))); + // first error for fast access in big list + if (totalDialogs > 1 && firstBadDialog != null) { + System.out.println(horizontalBorder); + System.out.print(getColoredRow(totalsRightFormat, coloredTexts, "First bad dialog: " + firstBadDialog.getRegNumber())); + System.out.print(getColoredRow(totalsRightFormat, coloredTexts, firstBadDialog.getName() + " - " + firstBadDialog.getDescription())); + System.out.print(firstBadAssert); + System.out.print(firstBadDebugSource); + } + + // table end + System.out.println(horizontalBorder); + usedHorizontalBorder = true; + + if (failOnBadResults && totalBad > 0) { + Assert.fail(String.format("Testable dialogs has %d bad results, try to fix it", totalBad)); + } + } + + private String getColoredRow(String rowFormat, Map coloredTexts, Object... args) { + String line = String.format(rowFormat, args); + for (String coloredText : coloredTexts.keySet()) { + line = line.replace(coloredText, coloredTexts.get(coloredText)); + } + return line; + } + + private String asRed(String text) { + return "\u001B[31m" + text + "\u001B[0m"; + } + + private String asGreen(String text) { + return "\u001B[32m" + text + "\u001B[0m"; + } + + private String asYellow(String text) { + return "\u001B[33m" + text + "\u001B[0m"; + } +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/load/LoadTest.java b/Mage.Tests/src/test/java/org/mage/test/load/LoadTest.java index 97b27a023ea..eec1b306034 100644 --- a/Mage.Tests/src/test/java/org/mage/test/load/LoadTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/load/LoadTest.java @@ -54,8 +54,8 @@ public class LoadTest { private static final String TEST_AI_RANDOM_DECK_SETS = ""; // sets list for random generated decks (GRN,ACR for specific sets, empty for all sets, PELP for lands only - communication test) private static final String TEST_AI_RANDOM_DECK_COLORS_FOR_EMPTY_GAME = "GR"; // colors list for deck generation, empty for all colors private static final String TEST_AI_RANDOM_DECK_COLORS_FOR_AI_GAME = "WUBRG"; - private static final String TEST_AI_CUSTOM_DECK_PATH_1 = ""; // custom deck file instead random for player 1 (empty for random) - private static final String TEST_AI_CUSTOM_DECK_PATH_2 = ""; // custom deck file instead random for player 2 (empty for random) + private static String TEST_AI_CUSTOM_DECK_PATH_1 = ""; // custom deck file instead random for player 1 (empty for random) + private static String TEST_AI_CUSTOM_DECK_PATH_2 = ""; // custom deck file instead random for player 2 (empty for random) @BeforeClass public static void initDatabase() { @@ -150,6 +150,10 @@ public class LoadTest { Thread.sleep(minimumSleepTime); Assert.assertEquals("Can't see users count change 2", startUsersCount + 2, monitor.getAllRoomUsers().size()); Assert.assertNotNull("Can't find user 2", monitor.findUser(player2.userName)); + + player1.disconnect(); + player2.disconnect(); + monitor.disconnect(); } @Test @@ -213,6 +217,10 @@ public class LoadTest { logger.error(e.getMessage(), e); } } + + player1.disconnect(); + player2.disconnect(); + monitor.disconnect(); } public void playTwoAIGame(String gameName, Integer taskNumber, TasksProgress tasksProgress, long randomSeed, String deckColors, String deckAllowedSets, LoadTestGameResult gameResult) { @@ -251,12 +259,21 @@ public class LoadTest { String finishInfo = ""; if (state == TableState.FINISHED) { - finishInfo = gameView == null ? "??" : gameView.getStep().getStepShortText().toLowerCase(Locale.ENGLISH); + finishInfo = gameView == null || gameView.getStep() == null ? "??" : gameView.getStep().getStepShortText().toLowerCase(Locale.ENGLISH); } tasksProgress.update(taskNumber, finishInfo, gameView == null ? 0 : gameView.getTurn()); String globalProgress = tasksProgress.getInfo(); monitor.client.updateGlobalProgress(globalProgress); + // disconnected by unknown reason TODO: research the reason + if (!monitor.session.isConnected()) { + logger.error(monitor.userName + " disconnected from server on game " + gameView); + if (gameView != null) { + gameResult.finish(gameView); + } + break; + } + if (gameView != null && checkGame != null) { logger.info(globalProgress + ", " + checkGame.getTableName() + ": ---"); logger.info(String.format("%s, %s: turn %d, step %s, state %s", @@ -314,7 +331,7 @@ public class LoadTest { } // all done, can disconnect now - monitor.session.connectStop(false, false); + monitor.disconnect(); } @Test @@ -330,6 +347,31 @@ public class LoadTest { printGameResults(gameResults); } + @Test + @Ignore + public void test_TwoAIPlayGame_Debug() { + // usage: + // - run test_TwoAIPlayGame_Multiple + // - wait some freeze games and stop + // - find active table and game in server's games history + // - set deck files here + // - run single game and debug on server side like stack dump + long randomSeed = 1708140198; // 0 for random + TEST_AI_CUSTOM_DECK_PATH_1 = ".\\deck_player_1.dck"; + TEST_AI_CUSTOM_DECK_PATH_2 = ".\\deck_player_2.dck"; + + LoadTestGameResultsList gameResults = new LoadTestGameResultsList(); + if (randomSeed == 0) { + randomSeed = RandomUtil.nextInt(); + } + LoadTestGameResult gameResult = gameResults.createGame(0, "test game", randomSeed); + TasksProgress tasksProgress = new TasksProgress(); + tasksProgress.update(1, "", 0); + playTwoAIGame("Single AI game", 1, tasksProgress, randomSeed, "WGUBR", TEST_AI_RANDOM_DECK_SETS, gameResult); + + printGameResults(gameResults); + } + @Test @Ignore public void test_TwoAIPlayGame_Multiple() { @@ -673,7 +715,8 @@ public class LoadTest { this.client.setSession(this.session); this.roomID = this.session.getMainRoomId(); - Assert.assertTrue("client must be connected to server", this.session.isServerReady()); + Assert.assertTrue("client must be connected to server", this.session.isConnected()); + Assert.assertTrue("client must get server data", this.session.isServerReady()); } public ArrayList getAllRoomUsers() { @@ -918,12 +961,17 @@ public class LoadTest { public int getTotalEffectsCount() { return finalGameView == null ? 0 : this.finalGameView.getTotalEffectsCount(); } + + public int getGameCycle() { + return finalGameView == null ? 0 : this.finalGameView.getGameCycle(); + } } private static class LoadTestGameResultsList extends HashMap { - private static final String tableFormatHeader = "|%-10s|%-15s|%-20s|%-10s|%-10s|%-10s|%-10s|%-10s|%-15s|%-15s|%-10s|%n"; - private static final String tableFormatData = "|%-10s|%15s|%20s|%10s|%10s|%10s|%10s|%10s|%15s|%15s|%10s|%n"; + // index, name, random sid, game cycle, errors, effects, turn, life p1, life p2, creatures p1, creatures p2, =time, sec, ~time, sec + private static final String tableFormatHeader = "|%-10s|%-15s|%-20s|%-10s|%-10s|%-10s|%-10s|%-10s|%-10s|%-15s|%-15s|%-15s|%-15s|%n"; + private static final String tableFormatData = "|%-10s|%15s|%20s|%10s|%10s|%10s|%10s|%10s|%10s|%15s|%15s|%15s|%15s|%n"; public LoadTestGameResult createGame(int index, String name, long randomSeed) { if (this.containsKey(index)) { @@ -939,6 +987,7 @@ public class LoadTest { "index", "name", "random sid", + "game cycles", "errors", "effects", "turn", @@ -946,8 +995,8 @@ public class LoadTest { "life p2", "creatures p1", "creatures p2", - "time, sec", - "time per turn, sec" + "=time, sec", + "~time, sec" ); System.out.printf(tableFormatHeader, data.toArray()); } @@ -961,6 +1010,7 @@ public class LoadTest { String.valueOf(gameResult.index), //"index", gameResult.name, //"name", String.valueOf(gameResult.randomSeed), // "random sid", + String.valueOf(gameResult.getGameCycle()), // "game cycles", String.valueOf(gameResult.getTotalErrorsCount()), // "errors", String.valueOf(gameResult.getTotalEffectsCount()), // "effects", gameResult.getTurnInfo(), //"turn", @@ -979,15 +1029,16 @@ public class LoadTest { "TOTAL/AVG", //"index", String.valueOf(this.size()), //"name", "total, secs: " + String.format("%.3f", (float) this.getTotalDurationMs() / 1000), // "random sid", - String.valueOf(this.getTotalErrorsCount()), // errors - String.valueOf(this.getAvgEffectsCount()), // effects - String.valueOf(this.getAvgTurn()), // turn - String.valueOf(this.getAvgLife1()), // life p1 - String.valueOf(this.getAvgLife2()), // life p2 - String.valueOf(this.getAvgCreaturesCount1()), // creatures p1 - String.valueOf(this.getAvgCreaturesCount2()), // creatures p2 - String.valueOf(String.format("%.3f", (float) this.getAvgDurationMs() / 1000)), // time, sec - String.valueOf(String.format("%.3f", (float) this.getAvgDurationPerTurnMs() / 1000)) // time per turn, sec + "~" + this.getAvgGameCycle(), // game cycles + "=" + this.getTotalErrorsCount(), // errors + "~" + this.getAvgEffectsCount(), // effects + "~" + this.getAvgTurn(), // turn + "~" + this.getAvgLife1(), // life p1 + "~" + this.getAvgLife2(), // life p2 + "~" + this.getAvgCreaturesCount1(), // creatures p1 + "~" + this.getAvgCreaturesCount2(), // creatures p2 + "~" + String.format("%.3f", (float) this.getAvgDurationMs() / 1000), // time, sec + "~" + String.format("%.3f", (float) this.getAvgDurationPerTurnMs() / 1000) // time per turn, sec ); System.out.printf(tableFormatData, data.toArray()); } @@ -996,6 +1047,10 @@ public class LoadTest { return this.values().stream().mapToInt(LoadTestGameResult::getTotalErrorsCount).sum(); } + private int getAvgGameCycle() { + return this.size() == 0 ? 0 : this.values().stream().mapToInt(LoadTestGameResult::getGameCycle).sum() / this.size(); + } + private int getAvgEffectsCount() { return this.size() == 0 ? 0 : this.values().stream().mapToInt(LoadTestGameResult::getTotalEffectsCount).sum() / this.size(); } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 80ce3115065..ca3a223ea3b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -543,7 +543,7 @@ public class TestPlayer implements Player { if (currentTarget.getOriginalTarget() instanceof TargetCreaturePermanentAmount) { // supports only to set the complete amount to one target TargetCreaturePermanentAmount targetAmount = (TargetCreaturePermanentAmount) currentTarget.getOriginalTarget(); - targetAmount.setAmount(ability, game); + targetAmount.prepareAmount(ability, game); int amount = targetAmount.getAmountRemaining(); targetAmount.addTarget(id, amount, ability, game); targetsSet++; @@ -775,7 +775,12 @@ public class TestPlayer implements Player { AIRealGameControlUntil = endStep; // disable on end step computerPlayer.priority(game); actions.remove(action); - computerPlayer.resetPassed(); // remove AI's pass, so runtime/check commands can be executed in same priority + // remove AI's pass, so runtime/check commands can be executed in same priority + // aiPlayStep can cause double priority call, but it's better to have workable checkXXX commands + // (AI will do nothing on second priority call anyway) + if (!actions.isEmpty()) { + computerPlayer.resetPassed(); + } return true; } @@ -2097,15 +2102,12 @@ public class TestPlayer implements Player { return "Ability: null"; } - private String getInfo(Target target, Ability source, Game game) { + private String getInfo(Target target, Ability source, Game game, Cards cards) { if (target == null) { return "Target: null"; } - UUID abilityControllerId = getId(); - if (target.getTargetController() != null && target.getAbilityController() != null) { - abilityControllerId = target.getAbilityController(); - } - Set possibleTargets = target.possibleTargets(abilityControllerId, source, game); + UUID abilityControllerId = target.getAffectedAbilityControllerId(this.getId()); + Set possibleTargets = target.possibleTargets(abilityControllerId, source, game, cards); return "Target: selected " + target.getSize() + ", possible " + possibleTargets.size() + ", " + target.getClass().getSimpleName() + ": " + target.getMessage(game); @@ -2267,20 +2269,19 @@ public class TestPlayer implements Player { @Override public boolean choose(Outcome outcome, Target target, Ability source, Game game, Map options) { - UUID abilityControllerId = this.getId(); - if (target.getTargetController() != null && target.getAbilityController() != null) { - abilityControllerId = target.getAbilityController(); + + // choose itself for starting player all the time + if (target.getMessage(game).equals("Select a starting player")) { + target.add(this.getId(), game); + return true; } + UUID abilityControllerId = target.getAffectedAbilityControllerId(this.getId()); + // TODO: warning, some cards call player.choose methods instead target.choose, see #8254 // most use cases - discard and other cost with choice like that method // must migrate all choices.remove(xxx) to choices.remove(0), takeMaxTargetsPerChoose can help to find it - // ignore player select - if (target.getMessage(game).equals("Select a starting player")) { - return computerPlayer.choose(outcome, target, source, game, options); - } - boolean isAddedSomething = false; // must return true on any changes in targets, so game can ask next choose dialog until finish assertAliasSupportInChoices(true); @@ -2328,7 +2329,7 @@ public class TestPlayer implements Player { continue; } if (hasObjectTargetNameOrAlias(permanent, targetName)) { - if (target.isNotTarget() || target.canTarget(abilityControllerId, permanent.getId(), source, game)) { + if (target.canTarget(abilityControllerId, permanent.getId(), source, game) && !target.contains(permanent.getId())) { if ((permanent.isCopy() && !originOnly) || (!permanent.isCopy() && !copyOnly)) { target.add(permanent.getId(), game); isAddedSomething = true; @@ -2336,7 +2337,7 @@ public class TestPlayer implements Player { } } } else if ((permanent.getName() + '-' + permanent.getExpansionSetCode()).equals(targetName)) { // TODO: remove search by exp code? - if (target.isNotTarget() || target.canTarget(abilityControllerId, permanent.getId(), source, game)) { + if (target.canTarget(abilityControllerId, permanent.getId(), source, game) && !target.contains(permanent.getId())) { if ((permanent.isCopy() && !originOnly) || (!permanent.isCopy() && !copyOnly)) { target.add(permanent.getId(), game); isAddedSomething = true; @@ -2371,7 +2372,7 @@ public class TestPlayer implements Player { isAddedSomething = false; for (Player player : game.getPlayers().values()) { if (player.getName().equals(choiceRecord)) { - if (target.canTarget(abilityControllerId, player.getId(), null, game) && !target.contains(player.getId())) { + if (target.canTarget(abilityControllerId, player.getId(), source, game) && !target.contains(player.getId())) { target.add(player.getId(), game); isAddedSomething = true; } @@ -2479,7 +2480,7 @@ public class TestPlayer implements Player { } } - this.chooseStrictModeFailed("choice", game, getInfo(source, game) + "\n" + getInfo(target, source, game)); + this.chooseStrictModeFailed("choice", game, getInfo(source, game) + "\n" + getInfo(target, source, game, null)); return computerPlayer.choose(outcome, target, source, game, options); } @@ -2507,11 +2508,7 @@ public class TestPlayer implements Player { @Override public boolean chooseTarget(Outcome outcome, Target target, Ability source, Game game) { - UUID abilityControllerId = this.getId(); - if (target.getTargetController() != null && target.getAbilityController() != null) { - abilityControllerId = target.getAbilityController(); - } - UUID sourceId = source != null ? source.getSourceId() : null; + UUID abilityControllerId = target.getAffectedAbilityControllerId(this.getId()); assertAliasSupportInTargets(true); if (!targets.isEmpty()) { @@ -2538,7 +2535,8 @@ public class TestPlayer implements Player { String playerName = targetDefinition.substring(targetDefinition.indexOf("targetPlayer=") + 13); for (Player player : game.getPlayers().values()) { if (player.getName().equals(playerName) - && target.canTarget(abilityControllerId, player.getId(), source, game)) { + && target.canTarget(abilityControllerId, player.getId(), source, game) + && !target.contains(player.getId())) { target.addTarget(player.getId(), source, game); targets.remove(targetDefinition); return true; @@ -2808,16 +2806,13 @@ public class TestPlayer implements Player { Assert.fail(message); } - this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target, source, game)); + this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target, source, game, null)); return computerPlayer.chooseTarget(outcome, target, source, game); } @Override public boolean chooseTarget(Outcome outcome, Cards cards, TargetCard target, Ability source, Game game) { - UUID abilityControllerId = this.getId(); - if (target.getTargetController() != null && target.getAbilityController() != null) { - abilityControllerId = target.getAbilityController(); - } + UUID abilityControllerId = target.getAffectedAbilityControllerId(this.getId()); assertAliasSupportInTargets(false); if (!targets.isEmpty()) { @@ -2854,7 +2849,7 @@ public class TestPlayer implements Player { LOGGER.warn("Wrong target"); } - this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target, source, game)); + this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target, source, game, cards)); return computerPlayer.chooseTarget(outcome, cards, target, source, game); } @@ -2887,7 +2882,7 @@ public class TestPlayer implements Player { @Override public boolean chooseUse(Outcome outcome, String message, String secondMessage, String trueText, String falseText, Ability source, Game game) { - if (message.equals("Scry 1?")) { + if (message != null && message.equals("Scry 1?")) { return false; } assertAliasSupportInChoices(false); @@ -3448,7 +3443,7 @@ public class TestPlayer implements Player { @Override public boolean isComputer() { // all players in unit tests are computers, so it allows testing different logic (Human vs AI) - if (isTestsMode()) { + if (isTestMode()) { // AIRealGameSimulation = true - full plyable AI // AIRealGameSimulation = false - choose assisted AI (Human) return AIRealGameSimulation; @@ -3884,8 +3879,8 @@ public class TestPlayer implements Player { } @Override - public boolean isTestsMode() { - return computerPlayer.isTestsMode(); + public boolean isTestMode() { + return computerPlayer.isTestMode(); } @Override @@ -3893,6 +3888,16 @@ public class TestPlayer implements Player { computerPlayer.setTestMode(value); } + @Override + public boolean isFastFailInTestMode() { + return computerPlayer.isFastFailInTestMode(); + } + + @Override + public void setFastFailInTestMode(boolean value) { + computerPlayer.setFastFailInTestMode(value); + } + @Override public boolean isTopCardRevealed() { return computerPlayer.isTopCardRevealed(); @@ -4315,7 +4320,7 @@ public class TestPlayer implements Player { assertWrongChoiceUsage(choices.size() > 0 ? choices.get(0) : "empty list"); } - this.chooseStrictModeFailed("choice", game, getInfo(source, game) + "\n" + getInfo(target, source, game)); + this.chooseStrictModeFailed("choice", game, getInfo(source, game) + "\n" + getInfo(target, source, game, cards)); return computerPlayer.choose(outcome, cards, target, source, game); } @@ -4326,10 +4331,20 @@ public class TestPlayer implements Player { // chooseTargetAmount calls for EACH target cycle (e.g. one target per click, see TargetAmount) // if use want to stop choosing then chooseTargetAmount must return false (example: up to xxx) - Assert.assertNotEquals("chooseTargetAmount needs non zero amount remaining", 0, target.getAmountRemaining()); + // nothing to choose + target.prepareAmount(source, game); + if (target.getAmountRemaining() <= 0) { + return false; + } + if (target.getMaxNumberOfTargets() == 0 && target.getMinNumberOfTargets() == 0) { + return false; + } + + UUID abilityControllerId = target.getAffectedAbilityControllerId(this.getId()); assertAliasSupportInTargets(true); - if (!targets.isEmpty()) { + + while (!targets.isEmpty()) { // skip targets if (targets.get(0).equals(TARGET_SKIP)) { @@ -4381,14 +4396,18 @@ public class TestPlayer implements Player { // can select target.addTarget(possibleTarget, targetAmount, source, game); targets.remove(0); - return true; // one target per choose call + // allow test player to choose as much as possible until skip command + if (target.getAmountRemaining() <= 0) { + return true; + } + break; // try next target } } } } } - this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target, source, game)); + this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target, source, game, null)); return computerPlayer.chooseTargetAmount(outcome, target, source, game); } @@ -4737,7 +4756,7 @@ public class TestPlayer implements Player { Assert.fail(String.format("Found wrong choice command (%s):\n%s\n%s\n%s", reason, lastChoice, - getInfo(target, source, game), + getInfo(target, source, game, null), getInfo(source, game) )); } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java index a0c6cf587e1..436daf44d55 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java @@ -13,6 +13,7 @@ import mage.cards.decks.importer.DeckImporter; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.cards.repository.CardScanner; +import mage.collectors.DataCollectorServices; import mage.constants.*; import mage.counters.CounterType; import mage.filter.Filter; @@ -30,6 +31,7 @@ import mage.players.ManaPool; import mage.players.Player; import mage.server.game.GameSessionPlayer; import mage.util.CardUtil; +import mage.util.DebugUtil; import mage.util.ThreadUtils; import mage.utils.SystemUtil; import mage.view.GameView; @@ -244,6 +246,11 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement ThreadUtils.ensureRunInGameThread(); + DataCollectorServices.init( + true, + DebugUtil.TESTS_DATA_COLLECTORS_ENABLE_SAVE_GAME_HISTORY + ); + // check stop command int maxTurn = 1; int maxPhase = 0; diff --git a/Mage.Tests/src/test/java/org/mage/test/utils/DebugUtilTest.java b/Mage.Tests/src/test/java/org/mage/test/utils/DebugUtilTest.java index 45ff3069e33..65b89f753a3 100644 --- a/Mage.Tests/src/test/java/org/mage/test/utils/DebugUtilTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/utils/DebugUtilTest.java @@ -15,9 +15,9 @@ public class DebugUtilTest extends CardTestPlayerBase { } private void secondMethod() { - String resCurrent = DebugUtil.getMethodNameWithSource(0); - String resPrev = DebugUtil.getMethodNameWithSource(1); - String resPrevPrev = DebugUtil.getMethodNameWithSource(2); + String resCurrent = DebugUtil.getMethodNameWithSource(0, "method"); + String resPrev = DebugUtil.getMethodNameWithSource(1, "method"); + String resPrevPrev = DebugUtil.getMethodNameWithSource(2, "method"); Assert.assertTrue("must find secondMethod, but get " + resCurrent, resCurrent.startsWith("secondMethod")); Assert.assertTrue("must find firstMethod, but get " + resPrev, resPrev.startsWith("firstMethod")); Assert.assertTrue("must find test_StackTraceWithSourceName, but get " + resPrevPrev, resPrevPrev.startsWith("test_StackTraceWithSourceName")); diff --git a/Mage.Verify/src/main/java/mage/verify/mtgjson/MtgJsonCard.java b/Mage.Verify/src/main/java/mage/verify/mtgjson/MtgJsonCard.java index fcbeae82ef9..2adafa6e7d0 100644 --- a/Mage.Verify/src/main/java/mage/verify/mtgjson/MtgJsonCard.java +++ b/Mage.Verify/src/main/java/mage/verify/mtgjson/MtgJsonCard.java @@ -42,6 +42,7 @@ public final class MtgJsonCard { public boolean isFullArt; public String frameVersion; public List printings; // set codes with that card + public boolean isFunny; @Override public String toString() { diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index 9c9afcfc5bd..d7506a09c4b 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -16,6 +16,7 @@ import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; import mage.abilities.effects.common.FightTargetsEffect; +import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.counter.ProliferateEffect; import mage.abilities.effects.keyword.ScryEffect; import mage.abilities.hint.common.CitysBlessingHint; @@ -36,6 +37,7 @@ import mage.constants.*; import mage.filter.Filter; import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicates; +import mage.game.FakeGame; import mage.game.Game; import mage.game.command.Dungeon; import mage.game.command.Plane; @@ -83,10 +85,22 @@ public class VerifyCardDataTest { private static final Logger logger = Logger.getLogger(VerifyCardDataTest.class); - private static final String FULL_ABILITIES_CHECK_SET_CODES = "BLC"; // check ability text due mtgjson, can use multiple sets like MAT;CMD or * for all - private static final boolean CHECK_ONLY_ABILITIES_TEXT = false; // use when checking text locally, suppresses unnecessary checks and output messages + private static String FULL_ABILITIES_CHECK_SET_CODES = ""; // check ability text due mtgjson, can use multiple sets like MAT;CMD or * for all + private static boolean CHECK_ONLY_ABILITIES_TEXT = false; // use when checking text locally, suppresses unnecessary checks and output messages private static final boolean CHECK_COPYABLE_FIELDS = true; // disable for better verify test performance + // for automated local testing support + static { + String val = System.getProperty("xmage.tests.verifyCheckSetCodes"); + if (val != null) { + FULL_ABILITIES_CHECK_SET_CODES = val; + } + val = System.getProperty("xmage.tests.verifyCheckOnlyText"); + if (val != null) { + CHECK_ONLY_ABILITIES_TEXT = Boolean.parseBoolean(val); + } + } + private static final boolean AUTO_FIX_SAMPLE_DECKS = false; // debug only: auto-fix sample decks by test_checkSampleDecks test run private static final Set checkedNames = new HashSet<>(); // skip already checked cards @@ -1683,6 +1697,61 @@ public class VerifyCardDataTest { } } + @Test + @Ignore + // experimental test to find potentially fail conditions with NPE see https://github.com/magefree/mage/issues/13752 + public void test_checkBadConditions() { + // all conditions in AsThoughEffect must be compatible with empty source param (e.g. must be able to use inside ConditionalAsThoughEffect) + // see AsThoughEffectType.needAffectedAbility ? + // 370+ failed conditions + Collection errorsList = new ArrayList<>(); + Game fakeGame = new FakeGame(); + Ability fakeAbility = new SimpleStaticAbility(new InfoEffect("fake")); + + // TODO: add classes support (see example with tokens and default constructor)? + Reflections reflections = new Reflections("mage."); + Set> conditionEnums = reflections.getSubTypesOf(Condition.class) + .stream() + .filter(Class::isEnum) + .sorted(Comparator.comparing(Class::toString)) + .collect(Collectors.toCollection(LinkedHashSet::new)); + for (Class enumClass : conditionEnums) { + for (Object enumItem : enumClass.getEnumConstants()) { + // miss watcher will fail in both use cases, but miss ability only one + String errorOnAbility = ""; + try { + ((Condition) enumItem).apply(fakeGame, fakeAbility); + } catch (Exception e) { + errorOnAbility = Arrays.stream(e.getStackTrace()) + .map(StackTraceElement::toString) + .limit(5) + .collect(Collectors.joining("\n")); + } + + String errorOnEmptyAbility = ""; + try { + ((Condition) enumItem).apply(fakeGame, null); + } catch (Exception e) { + errorOnEmptyAbility = Arrays.stream(e.getStackTrace()) + .map(StackTraceElement::toString) + .limit(5) + .collect(Collectors.joining("\n")); + } + + if (errorOnAbility.isEmpty() && !errorOnEmptyAbility.isEmpty()) { + System.out.println(); + System.out.println("bad condition " + enumClass.getName() + "\n" + errorOnEmptyAbility); + errorsList.add("Error: condition must support empty and non-empty source params: " + enumClass.getName()); + } + } + } + + printMessages(errorsList); + if (!errorsList.isEmpty()) { + Assert.fail("Found conditions errors: " + errorsList.size()); + } + } + private void check(Card card, int cardIndex) { MtgJsonCard ref = MtgJsonService.cardFromSet(card.getExpansionSetCode(), card.getName(), card.getCardNumber()); if (ref != null) { @@ -1986,7 +2055,13 @@ public class VerifyCardDataTest { expected.removeIf(subtypesToIgnore::contains); for (SubType subType : card.getSubtype()) { - if (!subType.isCustomSet() && !subType.canGain(card)) { + if (subType.isCustomSet()) { + if (!ref.isFunny) { + fail(card, "subtypes", "subtype " + subType + " is marked as \"custom\" but is in an official set"); + } + continue; + } + if (!subType.canGain(card)) { String cardTypeString = card .getCardType() .stream() @@ -3338,4 +3413,4 @@ public class VerifyCardDataTest { System.out.println(String.format("ALL DONE, found and write %d combos", allCombos.size())); } -} \ No newline at end of file +} diff --git a/Mage/pom.xml b/Mage/pom.xml index f148552c45f..8759c48b385 100644 --- a/Mage/pom.xml +++ b/Mage/pom.xml @@ -22,10 +22,14 @@ com.google.code.gson gson + + org.jsoup + jsoup + com.google.protobuf protobuf-java - 3.19.3 + 3.25.8 @@ -42,34 +46,34 @@ - com.github.os72 protoc-jar-maven-plugin 3.11.4 - generate-sources - - run - - - - com.google.protobuf:protoc:3.18.0 - - ${project.basedir}/src/main/proto - - - - java - none - ${project.build.directory}/generated-sources - - - + generate-sources + + run + + + + com.google.protobuf:protoc:3.25.8 + + ${project.basedir}/src/main/proto + + + + java + none + ${project.build.directory}/generated-sources + + + + org.codehaus.mojo @@ -89,12 +93,10 @@ - + mage - - diff --git a/Mage/src/main/java/mage/abilities/Ability.java b/Mage/src/main/java/mage/abilities/Ability.java index 31dee95d241..a834cf8be68 100644 --- a/Mage/src/main/java/mage/abilities/Ability.java +++ b/Mage/src/main/java/mage/abilities/Ability.java @@ -516,6 +516,10 @@ public interface Ability extends Controllable, Serializable { */ void initSourceObjectZoneChangeCounter(Game game, boolean force); + // TODO: it's activating time of ability, not current object's zcc, see #13737, + // in most use cases you must use game.getState().getZoneChangeCounter or input.getObject().getZoneChangeCounter(game) + // only ability related logic can use it (example: delayed triggers) + @Deprecated int getSourceObjectZoneChangeCounter(); /** diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index ad735b98e74..50340177526 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -377,7 +377,7 @@ public abstract class AbilityImpl implements Ability { // unit tests only: it allows to add targets/choices by two ways: // 1. From cast/activate command params (process it here) // 2. From single addTarget/setChoice, it's a preferred method for tests (process it in normal choose dialogs like human player) - if (controller.isTestsMode()) { + if (controller.isTestMode()) { if (!controller.addTargets(this, game)) { return false; } @@ -1226,10 +1226,7 @@ public abstract class AbilityImpl implements Ability { for (Mode mode : modes.values()) { boolean validTargets = true; for (Target target : mode.getTargets()) { - UUID abilityControllerId = controllerId; - if (target.getTargetController() != null) { - abilityControllerId = target.getTargetController(); - } + UUID abilityControllerId = target.getAffectedAbilityControllerId(controllerId); if (!target.canChoose(abilityControllerId, ability, game)) { validTargets = false; break; diff --git a/Mage/src/main/java/mage/abilities/ActivatedAbility.java b/Mage/src/main/java/mage/abilities/ActivatedAbility.java index 02205c61626..33399fbb77a 100644 --- a/Mage/src/main/java/mage/abilities/ActivatedAbility.java +++ b/Mage/src/main/java/mage/abilities/ActivatedAbility.java @@ -75,7 +75,7 @@ public interface ActivatedAbility extends Ability { * * @param mayActivate */ - void setMayActivate(TargetController mayActivate); + ActivatedAbility setMayActivate(TargetController mayActivate); /** * Returns the minimal possible cost for what the ability can be activated diff --git a/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java b/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java index 0290cb0b6e1..08ec1313fc2 100644 --- a/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java @@ -182,8 +182,9 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa } @Override - public void setMayActivate(TargetController mayActivate) { + public ActivatedAbilityImpl setMayActivate(TargetController mayActivate) { this.mayActivate = mayActivate; + return this; } public UUID getActivatorId() { diff --git a/Mage/src/main/java/mage/abilities/DelayedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/DelayedTriggeredAbility.java index 15d9a52a61c..4f8afbc5d97 100644 --- a/Mage/src/main/java/mage/abilities/DelayedTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/DelayedTriggeredAbility.java @@ -10,7 +10,7 @@ import mage.game.Game; */ public abstract class DelayedTriggeredAbility extends TriggeredAbilityImpl { - private final Duration duration; + private Duration duration; protected boolean triggerOnlyOnce; protected DelayedTriggeredAbility(Effect effect) { @@ -44,6 +44,10 @@ public abstract class DelayedTriggeredAbility extends TriggeredAbilityImpl { return duration; } + public void setDuration(Duration duration) { + this.duration = duration; + } + public boolean getTriggerOnlyOnce() { return triggerOnlyOnce; } diff --git a/Mage/src/main/java/mage/abilities/TriggeredAbilities.java b/Mage/src/main/java/mage/abilities/TriggeredAbilities.java index 3d9a78b5acb..bb683bce3ea 100644 --- a/Mage/src/main/java/mage/abilities/TriggeredAbilities.java +++ b/Mage/src/main/java/mage/abilities/TriggeredAbilities.java @@ -27,6 +27,7 @@ public class TriggeredAbilities extends LinkedHashMap // reason: game engine can generate additional events and triggers while checking another one, // it can generate multiple bugs, freeze, etc, see https://github.com/magefree/mage/issues/8426 // all checks can be catches by existing tests + private boolean enableIntegrityChecks = false; // TODO: disabled by default, enable for load tests or debug only private boolean enableIntegrityCheck1_MustKeepSameTriggersOrder = true; // good private boolean enableIntegrityCheck2_MustKeepSameTriggersList = false; // bad, impossible to fix due dynamic triggers gen private boolean enableIntegrityCheck3_CantStartEventProcessingBeforeFinishPrev = false; // bad, impossible to fix due dynamic triggers gen @@ -52,6 +53,7 @@ public class TriggeredAbilities extends LinkedHashMap sources.put(entry.getKey(), entry.getValue()); } + this.enableIntegrityChecks = abilities.enableIntegrityChecks; this.enableIntegrityCheck1_MustKeepSameTriggersOrder = abilities.enableIntegrityCheck1_MustKeepSameTriggersOrder; this.enableIntegrityCheck2_MustKeepSameTriggersList = abilities.enableIntegrityCheck2_MustKeepSameTriggersList; this.enableIntegrityCheck3_CantStartEventProcessingBeforeFinishPrev = abilities.enableIntegrityCheck3_CantStartEventProcessingBeforeFinishPrev; @@ -66,7 +68,7 @@ public class TriggeredAbilities extends LinkedHashMap this.processingDone = CardUtil.deepCopyObject(abilities.processingDone); // runtime check: triggers order (not required by paper rules, by required by xmage to make same result for all game instances) - if (this.enableIntegrityCheck1_MustKeepSameTriggersOrder) { + if (this.enableIntegrityChecks && this.enableIntegrityCheck1_MustKeepSameTriggersOrder) { if (!Objects.equals(this.values().stream().findFirst().orElse(null) + "", abilities.values().stream().findFirst().orElse(null) + "")) { // how-to fix: use LinkedHashMap instead HashMap/ConcurrentHashMap @@ -119,7 +121,12 @@ public class TriggeredAbilities extends LinkedHashMap } private void makeSureNotProcessing(GameEvent newEvent) { - if (this.enableIntegrityCheck2_MustKeepSameTriggersList + if (!this.enableIntegrityChecks) { + return; + } + + if (this.enableIntegrityChecks + && this.enableIntegrityCheck2_MustKeepSameTriggersList && this.processingStarted) { List info = new ArrayList<>(); info.add("old event: " + this.processingStartedEvent); @@ -131,6 +138,10 @@ public class TriggeredAbilities extends LinkedHashMap } private void processingStart(GameEvent newEvent) { + if (!this.enableIntegrityChecks) { + return; + } + makeSureNotProcessing(newEvent); this.processingStarted = true; @@ -141,12 +152,21 @@ public class TriggeredAbilities extends LinkedHashMap } private void processingDone(TriggeredAbility trigger) { + if (!this.enableIntegrityChecks) { + return; + } + this.processingDone.add(trigger); } private void processingEnd(boolean needErrorChecks) { + if (!this.enableIntegrityChecks) { + return; + } + if (needErrorChecks) { - if (this.enableIntegrityCheck3_CantStartEventProcessingBeforeFinishPrev + if (this.enableIntegrityChecks + && this.enableIntegrityCheck3_CantStartEventProcessingBeforeFinishPrev && !this.processingStarted) { throw new IllegalArgumentException("Triggers integrity failed: can't finish event before start"); } @@ -170,19 +190,22 @@ public class TriggeredAbilities extends LinkedHashMap + "\n" + "Done: " + "\n" + (doneInfo.isEmpty() ? "-" : doneInfo); - if (this.enableIntegrityCheck4_EventMustProcessAllOldTriggers + if (this.enableIntegrityChecks + && this.enableIntegrityCheck4_EventMustProcessAllOldTriggers && this.processingDone.size() < this.processingNeed.size()) { throw new IllegalArgumentException("Triggers integrity failed: event processing miss some triggers" + errorInfo); } - if (this.enableIntegrityCheck5_EventMustProcessInSameOrder + if (this.enableIntegrityChecks + && this.enableIntegrityCheck5_EventMustProcessInSameOrder && this.processingDone.size() > 0 && this.processingDone.size() == this.processingNeed.size() && !needIds.toString().equals(doneIds.toString())) { throw new IllegalArgumentException("Triggers integrity failed: event processing used wrong order" + errorInfo); } - if (this.enableIntegrityCheck6_EventMustNotProcessNewTriggers + if (this.enableIntegrityChecks + && this.enableIntegrityCheck6_EventMustNotProcessNewTriggers && this.processingDone.size() > this.processingNeed.size()) { throw new IllegalArgumentException("Triggers integrity failed: event processing must not process new triggers" + errorInfo); } diff --git a/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java b/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java index 93100ce08c3..b3e20a2d92b 100644 --- a/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java @@ -218,6 +218,7 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge @Override public TriggeredAbility withInterveningIf(Condition interveningIfCondition) { this.interveningIfCondition = interveningIfCondition; + this.replaceRuleText = false; return this; } @@ -301,6 +302,9 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge if (!conditionText.isEmpty()) { // e.g. CaseSolveAbility if (replaceRuleText && triggerPhrase != null && triggerPhrase.contains("{this}")) { conditionText = conditionText.replace("{this}", "it"); + if (conditionText.startsWith("it is ")) { + conditionText = conditionText.replace("it is ", "it's "); + } } if (!conditionText.startsWith("if ")) { sb.append("if "); @@ -329,7 +333,7 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge } } if (replaceRuleText && triggerPhrase != null) { - superRule = superRule.replaceFirst("^((?:you may )?sacrifice |(put|remove) [^ ]+ [^ ]+ counters? (on|from) |return |transform |untap |regenerate )?\\{this\\}", "$1it"); + superRule = superRule.replaceFirst("^((?:you may )?sacrifice |(put|remove) [^ ]+ [^ ]+ counters? (on|from) |return |transform |untap |regenerate |attach )?\\{this\\}", "$1it"); } sb.append(superRule); if (triggerLimitEachTurn != Integer.MAX_VALUE) { diff --git a/Mage/src/main/java/mage/abilities/common/ActivateIfConditionActivatedAbility.java b/Mage/src/main/java/mage/abilities/common/ActivateIfConditionActivatedAbility.java index 8d9804f7504..06906571472 100644 --- a/Mage/src/main/java/mage/abilities/common/ActivateIfConditionActivatedAbility.java +++ b/Mage/src/main/java/mage/abilities/common/ActivateIfConditionActivatedAbility.java @@ -5,55 +5,81 @@ import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; import mage.abilities.costs.Cost; import mage.abilities.effects.Effect; +import mage.abilities.effects.Effects; +import mage.constants.EffectType; import mage.constants.TimingRule; import mage.constants.Zone; +import mage.game.Game; +import mage.util.CardUtil; /** * @author LevelX2 */ public class ActivateIfConditionActivatedAbility extends ActivatedAbilityImpl { + private static final Effects emptyEffects = new Effects(); + + private String conditionText = null; + public ActivateIfConditionActivatedAbility(Effect effect, Cost cost, Condition condition) { - this(Zone.BATTLEFIELD, effect, cost, condition, TimingRule.INSTANT); + this(Zone.BATTLEFIELD, effect, cost, condition); } public ActivateIfConditionActivatedAbility(Zone zone, Effect effect, Cost cost, Condition condition) { - this(zone, effect, cost, condition, TimingRule.INSTANT); - } - - public ActivateIfConditionActivatedAbility(Zone zone, Effect effect, Cost cost, Condition condition, TimingRule timing) { super(zone, effect, cost); this.condition = condition; - this.timing = timing; } protected ActivateIfConditionActivatedAbility(final ActivateIfConditionActivatedAbility ability) { super(ability); + this.conditionText = ability.conditionText; + } + + @Override + public Effects getEffects(Game game, EffectType effectType) { + if (!condition.apply(game, this)) { + return emptyEffects; + } + return super.getEffects(game, effectType); + } + + public ActivateIfConditionActivatedAbility hideCondition() { + return withConditionText(""); + } + + public ActivateIfConditionActivatedAbility withConditionText(String conditionText) { + this.conditionText = conditionText; + return this; } @Override public String getRule() { - StringBuilder sb = new StringBuilder(super.getRule()); - if (condition.toString().startsWith("You may also")) { - sb.append(' ').append(condition.toString()).append('.'); - return sb.toString(); + if (conditionText != null) { + if (conditionText.isEmpty()) { + return super.getRule(); + } + return super.getRule() + ' ' + CardUtil.getTextWithFirstCharUpperCase(conditionText) + '.'; } + String conditionText = condition.toString(); + if (conditionText.startsWith("You may also")) { + return super.getRule() + ' ' + conditionText + '.'; + } + StringBuilder sb = new StringBuilder(super.getRule()); if (condition instanceof InvertCondition) { sb.append(" You can't activate this ability "); } else { sb.append(" Activate only "); } - if (!condition.toString().startsWith("during") - && !condition.toString().startsWith("before") - && !condition.toString().startsWith("if")) { + if (!conditionText.startsWith("during") + && !conditionText.startsWith("before") + && !conditionText.startsWith("if")) { sb.append("if "); } - sb.append(condition.toString()); + sb.append(conditionText); if (timing == TimingRule.SORCERY) { sb.append(" and only as a sorcery"); } sb.append('.'); - return sb.toString(); } @@ -61,5 +87,4 @@ public class ActivateIfConditionActivatedAbility extends ActivatedAbilityImpl { public ActivateIfConditionActivatedAbility copy() { return new ActivateIfConditionActivatedAbility(this); } - } diff --git a/Mage/src/main/java/mage/abilities/common/AnimateDeadTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/AnimateDeadTriggeredAbility.java index 71579f05a60..7e11167725e 100644 --- a/Mage/src/main/java/mage/abilities/common/AnimateDeadTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/AnimateDeadTriggeredAbility.java @@ -17,7 +17,7 @@ import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; import mage.watchers.Watcher; @@ -63,13 +63,13 @@ class AnimateDeadReplaceAbilityEffect extends ContinuousEffectImpl { private final boolean becomesAura; private Ability newAbility; - private TargetCreaturePermanent newTarget; + private TargetPermanent newTarget; public AnimateDeadReplaceAbilityEffect(boolean becomesAura) { super(Duration.Custom, Outcome.AddAbility); this.becomesAura = becomesAura; staticText = (becomesAura ? "it becomes an Aura with" : - "it loses \"enchant creature card in a graveyard\" and gains" + "it loses \"enchant creature card in a graveyard\" and gains" ) + " \"enchant creature put onto the battlefield with {this}.\""; if (becomesAura) { dependencyTypes.add(DependencyType.AuraAddingRemoving); @@ -95,7 +95,7 @@ class AnimateDeadReplaceAbilityEffect extends ContinuousEffectImpl { FilterCreaturePermanent filter = new FilterCreaturePermanent("creature put onto the battlefield with {this}"); filter.add(new AnimateDeadPredicate(source.getSourceId())); - newTarget = new TargetCreaturePermanent(filter); + newTarget = new TargetPermanent(filter); newAbility = new EnchantAbility(newTarget); } diff --git a/Mage/src/main/java/mage/abilities/common/AttachableToRestrictedAbility.java b/Mage/src/main/java/mage/abilities/common/AttachableToRestrictedAbility.java index fac6a4a26b6..fc11c56c0e7 100644 --- a/Mage/src/main/java/mage/abilities/common/AttachableToRestrictedAbility.java +++ b/Mage/src/main/java/mage/abilities/common/AttachableToRestrictedAbility.java @@ -4,35 +4,30 @@ import mage.abilities.Ability; import mage.abilities.effects.common.InfoEffect; import mage.constants.Zone; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.target.Target; +import java.util.UUID; + /** * * @author LevelX2 */ public class AttachableToRestrictedAbility extends SimpleStaticAbility { - + private final Target attachable; public AttachableToRestrictedAbility(Target target) { super(Zone.BATTLEFIELD, new InfoEffect("{this} can be attached only to a " + target.getTargetName())); - addTarget(target); + this.attachable = target.copy(); } private AttachableToRestrictedAbility(AttachableToRestrictedAbility ability) { super(ability); + this.attachable = ability.attachable; // Since we never modify the target, we don't need to re-copy it } - public boolean canEquip(Permanent toEquip, Ability source, Game game) { - for (Target target : getTargets()) { - if (source == null) { - if (!target.canTarget(toEquip.getId(), game)) { - return false; - } - } else if (!target.canTarget(toEquip.getId(), source, game)) { - return false; - } - } - return true; + public boolean canEquip(UUID toEquip, Ability source, Game game) { + if (source == null) { + return attachable.canTarget(toEquip, game); + } else return attachable.canTarget(toEquip, source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/common/AttacksPlayerWithCreaturesTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/AttacksPlayerWithCreaturesTriggeredAbility.java new file mode 100644 index 00000000000..1264c40f4cd --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/AttacksPlayerWithCreaturesTriggeredAbility.java @@ -0,0 +1,107 @@ +package mage.abilities.common; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.constants.SetTargetPointer; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.DefenderAttackedEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; +import mage.target.targetpointer.FixedTargets; +import mage.util.CardUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * based heavily on AttacksWithCreaturesTriggeredAbility + * @author notgreat + */ +public class AttacksPlayerWithCreaturesTriggeredAbility extends TriggeredAbilityImpl { + private final FilterPermanent filter; + private final int minAttackers; + private final boolean onlyOpponents; + private final SetTargetPointer setTargetPointer; + + public AttacksPlayerWithCreaturesTriggeredAbility(Effect effect, SetTargetPointer setTargetPointer) { + this(effect, StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED, setTargetPointer); + } + + public AttacksPlayerWithCreaturesTriggeredAbility(Effect effect, FilterPermanent filter, SetTargetPointer setTargetPointer) { + this(effect, 1, filter, setTargetPointer, false); + } + + public AttacksPlayerWithCreaturesTriggeredAbility(Effect effect, int minAttackers, FilterPermanent filter, SetTargetPointer setTargetPointer, boolean onlyOpponents) { + this(Zone.BATTLEFIELD, effect, minAttackers, filter, setTargetPointer, onlyOpponents, false); + } + + public AttacksPlayerWithCreaturesTriggeredAbility(Zone zone, Effect effect, int minAttackers, FilterPermanent filter, SetTargetPointer setTargetPointer, boolean onlyOpponents, boolean optional) { + super(zone, effect, optional); + this.filter = filter; + this.minAttackers = minAttackers; + this.onlyOpponents = onlyOpponents; + this.setTargetPointer = setTargetPointer; + if (minAttackers == 1 && StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED.equals(filter) && !onlyOpponents) { + setTriggerPhrase("Whenever you attack a player, "); + } else { + setTriggerPhrase("Whenever " + CardUtil.numberToText(minAttackers) + " or more " + filter.getMessage() + + " attack " + (onlyOpponents ? "an opponent" : "a player") + ", "); + } + } + + protected AttacksPlayerWithCreaturesTriggeredAbility(final AttacksPlayerWithCreaturesTriggeredAbility ability) { + super(ability); + this.filter = ability.filter; + this.minAttackers = ability.minAttackers; + this.onlyOpponents = ability.onlyOpponents; + this.setTargetPointer = ability.setTargetPointer; + } + + @Override + public AttacksPlayerWithCreaturesTriggeredAbility copy() { + return new AttacksPlayerWithCreaturesTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DEFENDER_ATTACKED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Player player = game.getPlayer(getControllerId()); + UUID attackedId = event.getTargetId(); + if (player == null || game.getPlayer(attackedId) == null) { + return false; + } + DefenderAttackedEvent attackedEvent = (DefenderAttackedEvent) event; + List attackers = attackedEvent.getAttackers(game).stream() + .filter(permanent -> filter.match(permanent, controllerId, this, game)) + .collect(Collectors.toList()); + if (attackers.size() < minAttackers || (onlyOpponents && !game.isOpponent(player, attackedId))) { + return false; + } + switch (setTargetPointer){ + case NONE: + break; + case PLAYER: + getEffects().setTargetPointer(new FixedTarget(attackedId)); + break; + case PERMANENT: + getEffects().setTargetPointer(new FixedTargets(new ArrayList<>(attackers), game)); + break; + default: + throw new UnsupportedOperationException("Unexpected setTargetPointer in AttacksPlayerWithCreaturesTriggeredAbility: " + setTargetPointer); + + } + this.getEffects().setValue("playerAttacked",attackedId); + return true; + } +} diff --git a/Mage/src/main/java/mage/abilities/common/BecomesAuraAttachToManifestSourceEffect.java b/Mage/src/main/java/mage/abilities/common/BecomesAuraAttachToManifestSourceEffect.java index ccf51904b2b..f0f9a747137 100644 --- a/Mage/src/main/java/mage/abilities/common/BecomesAuraAttachToManifestSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/common/BecomesAuraAttachToManifestSourceEffect.java @@ -12,6 +12,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.util.CardUtil; @@ -47,7 +48,7 @@ public class BecomesAuraAttachToManifestSourceEffect extends OneShotEffect { if (enchantedCreature != null) { enchantedCreature.addAttachment(enchantment.getId(), source, game); FilterCreaturePermanent filter = new FilterCreaturePermanent(); - Target target = new TargetCreaturePermanent(filter); + Target target = new TargetPermanent(filter); target.addTarget(enchantedCreature.getId(), source, game); game.addEffect(new BecomesAuraSourceEffect(target), source); } diff --git a/Mage/src/main/java/mage/abilities/common/BecomesTargetAnyTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/BecomesTargetAnyTriggeredAbility.java index 01816dc7446..bcd65966258 100644 --- a/Mage/src/main/java/mage/abilities/common/BecomesTargetAnyTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/BecomesTargetAnyTriggeredAbility.java @@ -12,7 +12,6 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.stack.StackObject; import mage.target.targetpointer.FixedTarget; -import mage.util.CardUtil; /** * @author xenohedron @@ -70,7 +69,7 @@ public class BecomesTargetAnyTriggeredAbility extends TriggeredAbilityImpl { if (permanent == null || !filterTarget.match(permanent, getControllerId(), this, game)) { return false; } - StackObject targetingObject = CardUtil.findTargetingStackObject(this.getId().toString(), event, game); + StackObject targetingObject = game.findTargetingStackObject(this.getId().toString(), event); if (targetingObject == null || !filterStack.match(targetingObject, getControllerId(), this, game)) { return false; } diff --git a/Mage/src/main/java/mage/abilities/common/BecomesTargetAttachedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/BecomesTargetAttachedTriggeredAbility.java index 54481419723..93501b89c17 100644 --- a/Mage/src/main/java/mage/abilities/common/BecomesTargetAttachedTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/BecomesTargetAttachedTriggeredAbility.java @@ -8,10 +8,9 @@ import mage.filter.FilterStackObject; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.stack.StackObject; import mage.game.permanent.Permanent; +import mage.game.stack.StackObject; import mage.target.targetpointer.FixedTarget; -import mage.util.CardUtil; /** * @author LoneFox @@ -54,7 +53,7 @@ public class BecomesTargetAttachedTriggeredAbility extends TriggeredAbilityImpl if (enchantment == null || enchantment.getAttachedTo() == null || !event.getTargetId().equals(enchantment.getAttachedTo())) { return false; } - StackObject targetingObject = CardUtil.findTargetingStackObject(this.getId().toString(), event, game); + StackObject targetingObject = game.findTargetingStackObject(this.getId().toString(), event); if (targetingObject == null || !filter.match(targetingObject, getControllerId(), this, game)) { return false; } diff --git a/Mage/src/main/java/mage/abilities/common/BecomesTargetControllerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/BecomesTargetControllerTriggeredAbility.java index c6948f53828..83006241427 100644 --- a/Mage/src/main/java/mage/abilities/common/BecomesTargetControllerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/BecomesTargetControllerTriggeredAbility.java @@ -3,15 +3,14 @@ package mage.abilities.common; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; import mage.constants.SetTargetPointer; +import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.FilterStackObject; -import mage.game.events.GameEvent; -import mage.constants.Zone; import mage.game.Game; +import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.stack.StackObject; import mage.target.targetpointer.FixedTarget; -import mage.util.CardUtil; /** * @author xenohedron @@ -63,7 +62,7 @@ public class BecomesTargetControllerTriggeredAbility extends TriggeredAbilityImp return false; } } - StackObject targetingObject = CardUtil.findTargetingStackObject(this.getId().toString(), event, game); + StackObject targetingObject = game.findTargetingStackObject(this.getId().toString(), event); if (targetingObject == null || !filterStack.match(targetingObject, getControllerId(), this, game)) { return false; } diff --git a/Mage/src/main/java/mage/abilities/common/BecomesTargetSourceTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/BecomesTargetSourceTriggeredAbility.java index 0f61e332e7d..df3cd8ca8af 100644 --- a/Mage/src/main/java/mage/abilities/common/BecomesTargetSourceTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/BecomesTargetSourceTriggeredAbility.java @@ -10,7 +10,6 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.StackObject; import mage.target.targetpointer.FixedTarget; -import mage.util.CardUtil; /** * @author North @@ -57,7 +56,7 @@ public class BecomesTargetSourceTriggeredAbility extends TriggeredAbilityImpl { if (!event.getTargetId().equals(getSourceId())) { return false; } - StackObject targetingObject = CardUtil.findTargetingStackObject(this.getId().toString(), event, game); + StackObject targetingObject = game.findTargetingStackObject(this.getId().toString(), event); if (targetingObject == null || !filter.match(targetingObject, getControllerId(), this, game)) { return false; } diff --git a/Mage/src/main/java/mage/abilities/common/CaseAbility.java b/Mage/src/main/java/mage/abilities/common/CaseAbility.java index 21e95e09bd5..9b736f1a3b9 100644 --- a/Mage/src/main/java/mage/abilities/common/CaseAbility.java +++ b/Mage/src/main/java/mage/abilities/common/CaseAbility.java @@ -5,7 +5,6 @@ import mage.abilities.TriggeredAbility; import mage.abilities.condition.CompoundCondition; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SolvedSourceCondition; -import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.decorator.ConditionalAsThoughEffect; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalReplacementEffect; @@ -62,7 +61,7 @@ public class CaseAbility extends SimpleStaticAbility { * * The "Solved" ability must be one of the following: *

    - *
  • {@link ConditionalActivatedAbility} using the condition {@link SolvedSourceCondition}.SOLVED
  • + *
  • {@link ActivateIfConditionActivatedAbility} using the condition {@link SolvedSourceCondition}.SOLVED
  • *
  • {@link TriggeredAbility} using the condition {@link SolvedSourceCondition}.SOLVED
  • *
  • {@link SimpleStaticAbility} with only {@link ConditionalAsThoughEffect} or {@link ConditionalContinuousEffect} effects
  • *
@@ -81,7 +80,7 @@ public class CaseAbility extends SimpleStaticAbility { addSubAbility(new CaseSolveAbility(toSolveCondition)); - if (!(solvedAbility instanceof ConditionalActivatedAbility)) { + if (!(solvedAbility instanceof ActivateIfConditionActivatedAbility)) { if (solvedAbility instanceof TriggeredAbility) { if (!(((TriggeredAbility) solvedAbility).getTriggerCondition() instanceof SolvedSourceCondition)) { throw new IllegalArgumentException("Wrong code usage: if solvedAbility is a TriggeredAbility it must have SolvedSourceCondition as its trigger condition"); @@ -92,17 +91,17 @@ public class CaseAbility extends SimpleStaticAbility { if (!(effect instanceof ConditionalContinuousEffect || effect instanceof ConditionalAsThoughEffect || effect instanceof ConditionalReplacementEffect)) { - throw new IllegalArgumentException("Wrong code usage: solvedAbility must be one of ConditionalActivatedAbility, " + + throw new IllegalArgumentException("Wrong code usage: solvedAbility must be one of ActivateIfConditionActivatedAbility, " + "TriggeredAbility, or StaticAbility with conditional effects."); } } } else { - throw new IllegalArgumentException("Wrong code usage: solvedAbility must be one of ConditionalActivatedAbility, " + + throw new IllegalArgumentException("Wrong code usage: solvedAbility must be one of ActivateIfConditionActivatedAbility, " + "TriggeredAbility, or StaticAbility with conditional effects."); } } } else { - ((ConditionalActivatedAbility) solvedAbility).hideCondition(); + ((ActivateIfConditionActivatedAbility) solvedAbility).hideCondition(); } addSubAbility(solvedAbility.withFlavorWord("Solved")); // TODO: Technically this shouldn't be italicized } diff --git a/Mage/src/main/java/mage/abilities/common/CastSpellPaidBySourceTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/CastSpellPaidBySourceTriggeredAbility.java index 501f68e9c74..058440e135e 100644 --- a/Mage/src/main/java/mage/abilities/common/CastSpellPaidBySourceTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/CastSpellPaidBySourceTriggeredAbility.java @@ -71,7 +71,8 @@ public class CastSpellPaidBySourceTriggeredAbility extends TriggeredAbilityImpl if (setTargetPointer) { this.getAllEffects().setTargetPointer(new FixedTarget(spell.getId(), game)); } + this.getEffects().setValue("spellCast", spell); return true; } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/abilities/common/CycleTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/CycleTriggeredAbility.java index 0e08ea66c72..606b36db71c 100644 --- a/Mage/src/main/java/mage/abilities/common/CycleTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/CycleTriggeredAbility.java @@ -6,6 +6,7 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.StackObject; +import mage.util.CardUtil; /** * @author Plopman @@ -40,6 +41,7 @@ public class CycleTriggeredAbility extends ZoneChangeTriggeredAbility { return false; } this.getEffects().setValue("cycleCosts", object.getStackAbility().getCosts()); + this.getEffects().setValue("cycleXValue", CardUtil.getSourceCostsTag(game, object.getStackAbility(), "X", 0)); return true; } diff --git a/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java index 7df6846dc67..30e3b9c6e58 100644 --- a/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java @@ -12,6 +12,7 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; /** * @author North @@ -52,12 +53,13 @@ public class DiesCreatureTriggeredAbility extends TriggeredAbilityImpl { public DiesCreatureTriggeredAbility(Zone zone, Effect effect, boolean optional, FilterPermanent filter, boolean setTargetPointer) { this(zone, effect, optional, filter, (setTargetPointer ? SetTargetPointer.PERMANENT : SetTargetPointer.NONE)); } + public DiesCreatureTriggeredAbility(Zone zone, Effect effect, boolean optional, FilterPermanent filter, SetTargetPointer setTargetPointer) { super(zone, effect, optional); this.filter = filter; this.setTargetPointer = setTargetPointer; setLeavesTheBattlefieldTrigger(true); - setTriggerPhrase("Whenever " + filter.getMessage() + (filter.getMessage().startsWith("one or more") ? " die, " : " dies, ")); + setTriggerPhrase("Whenever " + CardUtil.addArticle(filter.getMessage()) + (filter.getMessage().startsWith("one or more") ? " die, " : " dies, ")); } protected DiesCreatureTriggeredAbility(final DiesCreatureTriggeredAbility ability) { diff --git a/Mage/src/main/java/mage/abilities/common/DiscardedByOpponentTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DiscardedByOpponentTriggeredAbility.java index 0d86a1058c2..dbbd43d354e 100644 --- a/Mage/src/main/java/mage/abilities/common/DiscardedByOpponentTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DiscardedByOpponentTriggeredAbility.java @@ -14,7 +14,7 @@ public class DiscardedByOpponentTriggeredAbility extends TriggeredAbilityImpl { public DiscardedByOpponentTriggeredAbility(Effect effect) { super(Zone.GRAVEYARD, effect, false); - setTriggerPhrase("When a spell or ability an opponent controls causes you to discard this card"); + setTriggerPhrase("When a spell or ability an opponent controls causes you to discard this card, "); } protected DiscardedByOpponentTriggeredAbility(final DiscardedByOpponentTriggeredAbility ability) { diff --git a/Mage/src/main/java/mage/abilities/common/EndOfCombatTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/EndOfCombatTriggeredAbility.java index a6d36c6fa6a..b09494c8ef7 100644 --- a/Mage/src/main/java/mage/abilities/common/EndOfCombatTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/EndOfCombatTriggeredAbility.java @@ -40,7 +40,7 @@ public class EndOfCombatTriggeredAbility extends AtStepTriggeredAbility { case ANY: return "At end of combat, "; case YOU: - return "At the end of combat on your turn, "; + return "At end of combat on your turn, "; default: throw new UnsupportedOperationException("Unsupported TargetController in EndOfCombatTriggeredAbility: " + targetController); } diff --git a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAllTriggeredAbility.java index b01369d0766..8f7b39b603a 100644 --- a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAllTriggeredAbility.java @@ -76,8 +76,9 @@ public class EntersBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl { String filterMessage = filter.getMessage(); if (filterMessage.startsWith("one or more")) { setTriggerPhrase(getWhen() + filterMessage + " enter, "); + } else { + setTriggerPhrase(getWhen() + CardUtil.addArticle(filterMessage) + " enters, "); } - setTriggerPhrase(getWhen() + CardUtil.addArticle(filterMessage) + " enters, "); } @Override diff --git a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAttachToTarget.java b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAttachToTarget.java index d2f45004c13..3c3195d00d8 100644 --- a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAttachToTarget.java +++ b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAttachToTarget.java @@ -16,7 +16,8 @@ public class EntersBattlefieldAttachToTarget extends EntersBattlefieldTriggeredA } public EntersBattlefieldAttachToTarget(FilterPermanent filter) { - super(new AttachEffect(Outcome.BoostCreature, "attach it to target " + filter.getMessage())); + super(new AttachEffect(Outcome.BoostCreature, "attach {this} to target " + filter.getMessage())); + this.withRuleTextReplacement(true); // default "it" but a few exceptions this.addTarget(new TargetPermanent(filter)); } diff --git a/Mage/src/main/java/mage/abilities/common/OnEventTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/OnEventTriggeredAbility.java deleted file mode 100644 index a0f648c5643..00000000000 --- a/Mage/src/main/java/mage/abilities/common/OnEventTriggeredAbility.java +++ /dev/null @@ -1,62 +0,0 @@ - -package mage.abilities.common; - -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; - -/** - * @author BetaSteward_at_googlemail.com - */ -public class OnEventTriggeredAbility extends TriggeredAbilityImpl { - - private final EventType eventType; - private final String eventName; - private final boolean allPlayers; - - public OnEventTriggeredAbility(EventType eventType, String eventName, Effect effect) { - this(eventType, eventName, effect, false); - } - - public OnEventTriggeredAbility(EventType eventType, String eventName, Effect effect, boolean optional) { - this(eventType, eventName, false, effect, optional); - } - - public OnEventTriggeredAbility(EventType eventType, String eventName, boolean allPlayers, Effect effect) { - this(eventType, eventName, allPlayers, effect, false); - } - - public OnEventTriggeredAbility(EventType eventType, String eventName, boolean allPlayers, Effect effect, boolean optional) { - super(Zone.BATTLEFIELD, effect, optional); - this.eventType = eventType; - this.eventName = eventName; - this.allPlayers = allPlayers; - setTriggerPhrase("At the " + eventName + ", "); - } - - protected OnEventTriggeredAbility(final OnEventTriggeredAbility ability) { - super(ability); - this.eventType = ability.eventType; - this.eventName = ability.eventName; - this.allPlayers = ability.allPlayers; - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == eventType; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - return allPlayers || event.getPlayerId().equals(this.controllerId); - } - - @Override - public OnEventTriggeredAbility copy() { - return new OnEventTriggeredAbility(this); - } - -} diff --git a/Mage/src/main/java/mage/abilities/common/OpponentPlaysLandTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/OpponentPlaysLandTriggeredAbility.java index bbd90879091..9f702612c74 100644 --- a/Mage/src/main/java/mage/abilities/common/OpponentPlaysLandTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/OpponentPlaysLandTriggeredAbility.java @@ -12,7 +12,11 @@ import mage.game.permanent.Permanent; */ public class OpponentPlaysLandTriggeredAbility extends TriggeredAbilityImpl { - public OpponentPlaysLandTriggeredAbility(Zone zone, Effect effect, Boolean optional) { + public OpponentPlaysLandTriggeredAbility(Effect effect, boolean optional) { + this(Zone.BATTLEFIELD, effect, optional); + } + + public OpponentPlaysLandTriggeredAbility(Zone zone, Effect effect, boolean optional) { super(zone, effect, optional); setTriggerPhrase("Whenever an opponent plays a land, "); } diff --git a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldAllTriggeredAbility.java index e798718f028..a0d5ac75c7a 100644 --- a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldAllTriggeredAbility.java @@ -10,6 +10,7 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; /** * @author LevelX2 @@ -30,7 +31,7 @@ public class PutIntoGraveFromBattlefieldAllTriggeredAbility extends TriggeredAbi this.filter = filter; this.onlyToControllerGraveyard = onlyToControllerGraveyard; this.setTargetPointer = setTargetPointer; - setTriggerPhrase("Whenever " + filter.getMessage() + " is put into " + + setTriggerPhrase("Whenever " + CardUtil.addArticle(filter.getMessage()) + " is put into " + (onlyToControllerGraveyard ? "your" : "a") + " graveyard, "); } diff --git a/Mage/src/main/java/mage/abilities/common/SanctuaryInterveningIfTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/SanctuaryTriggeredAbility.java similarity index 53% rename from Mage/src/main/java/mage/abilities/common/SanctuaryInterveningIfTriggeredAbility.java rename to Mage/src/main/java/mage/abilities/common/SanctuaryTriggeredAbility.java index 450811e56c1..f91dd75d01c 100644 --- a/Mage/src/main/java/mage/abilities/common/SanctuaryInterveningIfTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/SanctuaryTriggeredAbility.java @@ -1,14 +1,10 @@ - package mage.abilities.common; import mage.ObjectColor; -import mage.abilities.TriggeredAbility; import mage.abilities.condition.CompoundCondition; import mage.abilities.condition.Condition; -import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.filter.FilterPermanent; @@ -18,10 +14,10 @@ import mage.filter.predicate.mageobject.ColorPredicate; /** * @author TheElk801 */ -public class SanctuaryInterveningIfTriggeredAbility extends ConditionalInterveningIfTriggeredAbility { +public class SanctuaryTriggeredAbility extends BeginningOfUpkeepTriggeredAbility { private static Condition makeOrCondition(ObjectColor color1, ObjectColor color2) { - FilterPermanent filter = new FilterPermanent(); + FilterPermanent filter = new FilterPermanent("you control a " + color1.getDescription() + " or " + color2.getDescription() + " permanent"); filter.add(Predicates.or( new ColorPredicate(color1), new ColorPredicate(color2) @@ -39,24 +35,17 @@ public class SanctuaryInterveningIfTriggeredAbility extends ConditionalInterveni return new CompoundCondition(condition1, condition2); } - private static TriggeredAbility makeTrigger(OneShotEffect effect1, OneShotEffect effect2, ObjectColor color1, ObjectColor color2) { - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility( - new ConditionalOneShotEffect(effect1, new InvertCondition(makeAndCondition(color1, color2))) - ); - ability.addEffect(new ConditionalOneShotEffect(effect2, makeAndCondition(color1, color2))); - return ability; + public SanctuaryTriggeredAbility(OneShotEffect effect1, OneShotEffect effect2, ObjectColor color1, ObjectColor color2, String text) { + super(new ConditionalOneShotEffect(effect2, effect1, makeAndCondition(color1, color2), text)); + this.withInterveningIf(makeOrCondition(color1, color2)); } - public SanctuaryInterveningIfTriggeredAbility(OneShotEffect effect1, OneShotEffect effect2, ObjectColor color1, ObjectColor color2, String text) { - super(makeTrigger(effect1, effect2, color1, color2), makeOrCondition(color1, color2), text); - } - - protected SanctuaryInterveningIfTriggeredAbility(final SanctuaryInterveningIfTriggeredAbility ability) { + protected SanctuaryTriggeredAbility(final SanctuaryTriggeredAbility ability) { super(ability); } @Override - public SanctuaryInterveningIfTriggeredAbility copy() { - return new SanctuaryInterveningIfTriggeredAbility(this); + public SanctuaryTriggeredAbility copy() { + return new SanctuaryTriggeredAbility(this); } } diff --git a/Mage/src/main/java/mage/abilities/common/SourceDealsNoncombatDamageToOpponentTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/SourceDealsNoncombatDamageToOpponentTriggeredAbility.java new file mode 100644 index 00000000000..198412dccff --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/SourceDealsNoncombatDamageToOpponentTriggeredAbility.java @@ -0,0 +1,66 @@ +package mage.abilities.common; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.constants.SetTargetPointer; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.DamagedPlayerEvent; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +/** + * @author notgreat + */ +public class SourceDealsNoncombatDamageToOpponentTriggeredAbility extends TriggeredAbilityImpl { + SetTargetPointer setTargetPointer; + + public SourceDealsNoncombatDamageToOpponentTriggeredAbility(Effect effect) { + this(effect, SetTargetPointer.NONE); + } + public SourceDealsNoncombatDamageToOpponentTriggeredAbility(Effect effect, SetTargetPointer setTargetPointer) { + this(effect, false, setTargetPointer); + } + + public SourceDealsNoncombatDamageToOpponentTriggeredAbility(Effect effect, boolean optional, SetTargetPointer setTargetPointer) { + super(Zone.BATTLEFIELD, effect, optional); + this.setTargetPointer = setTargetPointer; + setTriggerPhrase("Whenever a source you control deals noncombat damage to an opponent, "); + } + + protected SourceDealsNoncombatDamageToOpponentTriggeredAbility(final SourceDealsNoncombatDamageToOpponentTriggeredAbility ability) { + super(ability); + setTargetPointer = ability.setTargetPointer; + } + + @Override + public SourceDealsNoncombatDamageToOpponentTriggeredAbility copy() { + return new SourceDealsNoncombatDamageToOpponentTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Player opponent = game.getPlayer(event.getTargetId()); + DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; + if (opponent == null || !game.isOpponent(opponent, getControllerId()) + || !isControlledBy(game.getControllerId(event.getSourceId())) + || damageEvent.isCombatDamage()) { + return false; + } + int damageAmount = event.getAmount(); + if (damageAmount < 1) { + return false; + } + this.getEffects().setValue("damage", damageAmount); + if (setTargetPointer == SetTargetPointer.PLAYER) { + getEffects().setTargetPointer(new FixedTarget(event.getSourceId())); + } + return true; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/InvertCondition.java b/Mage/src/main/java/mage/abilities/condition/InvertCondition.java index ecdf51ba30d..245a46b957f 100644 --- a/Mage/src/main/java/mage/abilities/condition/InvertCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/InvertCondition.java @@ -1,4 +1,3 @@ - package mage.abilities.condition; import mage.abilities.Ability; @@ -7,16 +6,22 @@ import mage.game.Game; /** * A simple {@link Condition} to invert a decorated conditions * {@link Condition#apply(mage.game.Game, mage.abilities.Ability) apply(mage.game.Game, mage.abilities.Ability)} - * method invocation. - * + * method invocation. + * * @author maurer.it_at_gmail.com */ public class InvertCondition implements Condition { private final Condition condition; + private final String message; - public InvertCondition ( Condition condition ) { + public InvertCondition(Condition condition) { + this(condition, null); + } + + public InvertCondition(Condition condition, String message) { this.condition = condition; + this.message = message; } /* @@ -29,7 +34,10 @@ public class InvertCondition implements Condition { @Override public String toString() { + if (message != null && !message.isEmpty()) { + return message; + } return condition.toString(); } - + } diff --git a/Mage/src/main/java/mage/abilities/condition/common/AdamantCondition.java b/Mage/src/main/java/mage/abilities/condition/common/AdamantCondition.java index aefb7c3e6d1..e1d23c639ae 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/AdamantCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/AdamantCondition.java @@ -27,11 +27,11 @@ public enum AdamantCondition implements Condition { private final boolean colorless; - private AdamantCondition(ColoredManaSymbol coloredManaSymbol) { + AdamantCondition(ColoredManaSymbol coloredManaSymbol) { this(coloredManaSymbol, false); } - private AdamantCondition(ColoredManaSymbol coloredManaSymbol, boolean colorless) { + AdamantCondition(ColoredManaSymbol coloredManaSymbol, boolean colorless) { this.coloredManaSymbol = coloredManaSymbol; this.colorless = colorless; } @@ -44,9 +44,9 @@ public enum AdamantCondition implements Condition { } if (coloredManaSymbol == null) { return Arrays - .stream(ColoredManaSymbol.values()) - .map(source.getManaCostsToPay().getUsedManaToPay()::getColor) - .anyMatch(i -> i > 2); + .stream(ColoredManaSymbol.values()) + .map(source.getManaCostsToPay().getUsedManaToPay()::getColor) + .anyMatch(i -> i > 2); } return source.getManaCostsToPay().getUsedManaToPay().getColor(coloredManaSymbol) > 2; } @@ -63,9 +63,9 @@ public enum AdamantCondition implements Condition { } if (coloredManaSymbol == null) { return Arrays - .stream(ColoredManaSymbol.values()) - .map(payment::getColor) - .anyMatch(i -> i > 2); + .stream(ColoredManaSymbol.values()) + .map(payment::getColor) + .anyMatch(i -> i > 2); } return payment.getColor(coloredManaSymbol) > 2; } @@ -74,4 +74,17 @@ public enum AdamantCondition implements Condition { public boolean caresAboutManaColor() { return true; } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("at least three "); + if (coloredManaSymbol == null && !colorless) { + sb.append("mana of the same color"); + } else { + sb.append(coloredManaSymbol != null ? coloredManaSymbol.getColorName() : "colorless"); + sb.append(" mana"); + } + sb.append(" was spent to cast it"); + return sb.toString(); + } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/AddendumCondition.java b/Mage/src/main/java/mage/abilities/condition/common/AddendumCondition.java index 81324372212..b5c3c8d0131 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/AddendumCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/AddendumCondition.java @@ -27,4 +27,9 @@ public enum AddendumCondition implements Condition { Spell spell = game.getSpell(source.getSourceId()); return spell != null && !spell.isCopy(); // copies are not casted } + + @Override + public String toString() { + return "you cast it during your main phase"; + } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/AttackedPlayersPoisonedCondition.java b/Mage/src/main/java/mage/abilities/condition/common/AttackedPlayersPoisonedCondition.java deleted file mode 100644 index aa6cf7b4315..00000000000 --- a/Mage/src/main/java/mage/abilities/condition/common/AttackedPlayersPoisonedCondition.java +++ /dev/null @@ -1,37 +0,0 @@ -package mage.abilities.condition.common; - -import mage.abilities.Ability; -import mage.abilities.condition.Condition; -import mage.counters.CounterType; -import mage.game.Game; -import mage.game.combat.CombatGroup; - -import java.util.Objects; - -/** - * A condition which checks whether any players being attacked are poisoned - * (have one or more poison counters on them) - * - * @author alexander-novo - */ -public enum AttackedPlayersPoisonedCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - return game.getCombat() - .getGroups() - .stream() - .map(CombatGroup::getDefenderId) - .filter(Objects::nonNull) - .distinct() - .map(game::getPlayer) - .filter(Objects::nonNull) - .anyMatch(player -> player.getCountersCount(CounterType.POISON) > 0); - } - - @Override - public String toString() { - return "one or more players being attacked are poisoned"; - } -} diff --git a/Mage/src/main/java/mage/abilities/condition/common/BargainedCondition.java b/Mage/src/main/java/mage/abilities/condition/common/BargainedCondition.java index 80435d4b3cc..82ca09582a6 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/BargainedCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/BargainedCondition.java @@ -12,7 +12,6 @@ import mage.util.CardUtil; * @author Susucr */ public enum BargainedCondition implements Condition { - instance; @Override @@ -22,7 +21,6 @@ public enum BargainedCondition implements Condition { @Override public String toString() { - return "{this} was Bargained"; + return "it was bargained"; } - } diff --git a/Mage/src/main/java/mage/abilities/condition/common/CollectedEvidenceCondition.java b/Mage/src/main/java/mage/abilities/condition/common/CollectedEvidenceCondition.java index 377e456eeaf..21e1aa9e1e4 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/CollectedEvidenceCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/CollectedEvidenceCondition.java @@ -21,7 +21,6 @@ public enum CollectedEvidenceCondition implements Condition { @Override public String toString() { - // must use "used" instead "collected" because it can be visible as card hint on stack before real collect - return "Evidence was used"; + return "evidence was collected"; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/CovenCondition.java b/Mage/src/main/java/mage/abilities/condition/common/CovenCondition.java index 6d2b558ac0b..0a8a6cee560 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/CovenCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/CovenCondition.java @@ -33,6 +33,6 @@ public enum CovenCondition implements Condition { @Override public String toString() { - return "if you control three or more creatures with different powers"; + return "you control three or more creatures with different powers"; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/DealtDamageToAnOpponent.java b/Mage/src/main/java/mage/abilities/condition/common/DealtDamageToAnOpponent.java index 57e48306403..e803b3c4aca 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/DealtDamageToAnOpponent.java +++ b/Mage/src/main/java/mage/abilities/condition/common/DealtDamageToAnOpponent.java @@ -1,27 +1,31 @@ - package mage.abilities.condition.common; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.game.Game; import mage.watchers.common.PlayerDamagedBySourceWatcher; +import java.util.UUID; + /** * @author LevelX2 */ -public class DealtDamageToAnOpponent implements Condition { +public enum DealtDamageToAnOpponent implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, opponentId); - if (watcher != null) { - if (watcher.hasSourceDoneDamage(source.getSourceId(), game)) { - return true; - } + if (watcher != null && watcher.hasSourceDoneDamage(source.getSourceId(), game)) { + return true; } } return false; } + + @Override + public String toString() { + return "{this} dealt damage to an opponent this turn"; + } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/DrewTwoOrMoreCardsCondition.java b/Mage/src/main/java/mage/abilities/condition/common/DrewTwoOrMoreCardsCondition.java index fb5fd5ceef3..f457ff9dc4a 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/DrewTwoOrMoreCardsCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/DrewTwoOrMoreCardsCondition.java @@ -19,6 +19,6 @@ public enum DrewTwoOrMoreCardsCondition implements Condition { @Override public String toString() { - return "you've drawn two or more cards this turn"; + return "you've drawn more than one card this turn"; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/EnchantedSourceCondition.java b/Mage/src/main/java/mage/abilities/condition/common/EnchantedSourceCondition.java index c4a58e6234c..4921b46aa38 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/EnchantedSourceCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/EnchantedSourceCondition.java @@ -1,17 +1,17 @@ package mage.abilities.condition.common; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.constants.ComparisonType; import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author North */ public class EnchantedSourceCondition implements Condition { @@ -51,6 +51,6 @@ public class EnchantedSourceCondition implements Condition { @Override public String toString() { - return "enchanted"; + return "{this} is enchanted" + (numberOfEnchantments > 1 ? " by " + CardUtil.numberToText(numberOfEnchantments) + " or more Auras" : ""); } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/HateCondition.java b/Mage/src/main/java/mage/abilities/condition/common/HateCondition.java index 4d42a696c45..7fcba68d0d2 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/HateCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/HateCondition.java @@ -24,6 +24,6 @@ public enum HateCondition implements Condition { @Override public String toString() { - return "if an opponent lost life from source other than combat damage this turn"; + return "an opponent lost life from source other than combat damage this turn"; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/HaveInitiativeCondition.java b/Mage/src/main/java/mage/abilities/condition/common/HaveInitiativeCondition.java index 1110482c5a9..0a813233b2f 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/HaveInitiativeCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/HaveInitiativeCondition.java @@ -17,6 +17,6 @@ public enum HaveInitiativeCondition implements Condition { @Override public String toString() { - return "if you have the initiative"; + return "you have the initiative"; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/IsStepCondition.java b/Mage/src/main/java/mage/abilities/condition/common/IsStepCondition.java index ad4387727fd..e347ed79e1a 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/IsStepCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/IsStepCondition.java @@ -7,13 +7,17 @@ import mage.constants.PhaseStep; import mage.game.Game; /** - * * @author LevelX2 */ public class IsStepCondition implements Condition { protected PhaseStep phaseStep; protected boolean onlyDuringYourSteps; + private static final IsStepCondition myUpkeep = new IsStepCondition(PhaseStep.UPKEEP, true); + + public static IsStepCondition getMyUpkeep() { + return myUpkeep; + } public IsStepCondition(PhaseStep phaseStep) { this(phaseStep, true); diff --git a/Mage/src/main/java/mage/abilities/condition/common/LandfallCondition.java b/Mage/src/main/java/mage/abilities/condition/common/LandfallCondition.java index 2b6d991c540..a91b10c6d09 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/LandfallCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/LandfallCondition.java @@ -16,4 +16,9 @@ public enum LandfallCondition implements Condition { LandfallWatcher watcher = game.getState().getWatcher(LandfallWatcher.class); return watcher != null && watcher.landPlayed(source.getControllerId()); } + + @Override + public String toString() { + return "you had a land enter the battlefield under your control this turn"; + } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/LastTimeCounterRemovedCondition.java b/Mage/src/main/java/mage/abilities/condition/common/LastTimeCounterRemovedCondition.java index fb2bf28163c..7dbba8a1a62 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/LastTimeCounterRemovedCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/LastTimeCounterRemovedCondition.java @@ -2,29 +2,28 @@ package mage.abilities.condition.common; import mage.abilities.Ability; import mage.abilities.condition.Condition; -import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; -import mage.game.permanent.Permanent; + +import java.util.Optional; /** * Created by glerman on 20/6/15. */ -public enum LastTimeCounterRemovedCondition implements Condition{ +public enum LastTimeCounterRemovedCondition implements Condition { + instance; -instance; + @Override + public boolean apply(Game game, Ability source) { + return Optional + .ofNullable(source.getSourcePermanentOrLKI(game)) + .map(permanent -> permanent.getCounters(game).getCount(CounterType.TIME)) + .filter(x -> x == 0) + .isPresent(); + } - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent == null) { - permanent = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD); + @Override + public String toString() { + return "it had no time counters on it"; } - if (permanent != null) { - final int timeCounters = permanent.getCounters(game).getCount(CounterType.TIME); - return timeCounters == 0; - } else { - return false; - } - } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/LifeCompareCondition.java b/Mage/src/main/java/mage/abilities/condition/common/LifeCompareCondition.java index 76be7c9ad27..66b7158a4e7 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/LifeCompareCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/LifeCompareCondition.java @@ -8,6 +8,7 @@ import mage.game.Game; import mage.players.Player; import java.util.Objects; +import java.util.Optional; /** * @author xenohedron @@ -20,9 +21,10 @@ public class LifeCompareCondition implements Condition { /** * "As long as [player] has [number] or [more/less] life" + * * @param targetController YOU, OPPONENT, ANY, EACH_PLAYER - * @param comparisonType comparison operator - * @param amount life threshold + * @param comparisonType comparison operator + * @param amount life threshold */ public LifeCompareCondition(TargetController targetController, ComparisonType comparisonType, int amount) { this.targetController = targetController; @@ -40,7 +42,8 @@ public class LifeCompareCondition implements Condition { case YOU: return ComparisonType.compare(controller.getLife(), comparisonType, amount); case OPPONENT: - return game.getOpponents(controller.getId()) + return game + .getOpponents(controller.getId()) .stream() .map(game::getPlayer) .filter(Objects::nonNull) @@ -48,7 +51,9 @@ public class LifeCompareCondition implements Condition { .map(Player::getLife) .anyMatch(l -> ComparisonType.compare(l, comparisonType, amount)); case ANY: - return game.getState().getPlayersInRange(controller.getId(), game) + return game + .getState() + .getPlayersInRange(controller.getId(), game) .stream() .map(game::getPlayer) .filter(Objects::nonNull) @@ -56,13 +61,23 @@ public class LifeCompareCondition implements Condition { .map(Player::getLife) .anyMatch(l -> ComparisonType.compare(l, comparisonType, amount)); case EACH_PLAYER: - return game.getState().getPlayersInRange(controller.getId(), game) + return game + .getState() + .getPlayersInRange(controller.getId(), game) .stream() .map(game::getPlayer) .filter(Objects::nonNull) .filter(Player::isInGame) .map(Player::getLife) .allMatch(l -> ComparisonType.compare(l, comparisonType, amount)); + case ACTIVE: + return Optional + .ofNullable(game) + .map(Game::getActivePlayerId) + .map(game::getPlayer) + .map(Player::getLife) + .filter(l -> ComparisonType.compare(l, comparisonType, amount)) + .isPresent(); default: throw new IllegalArgumentException("Unsupported TargetController in LifeCompareCondition: " + targetController); } @@ -84,27 +99,30 @@ public class LifeCompareCondition implements Condition { case EACH_PLAYER: sb.append("each player has "); break; + case ACTIVE: + sb.append("that player has "); + break; default: throw new IllegalArgumentException("Unsupported TargetController in LifeCompareCondition: " + targetController); } switch (comparisonType) { - case MORE_THAN: - sb.append("more than ").append(amount); - break; - case FEWER_THAN: - sb.append("less than ").append(amount); - break; - case EQUAL_TO: - sb.append("exactly ").append(amount); - break; - case OR_GREATER: - sb.append(amount).append(" or more"); - break; - case OR_LESS: - sb.append(amount).append(" or less"); - break; - default: - throw new IllegalArgumentException("Unsupported ComparisonType in LifeCompareCondition: " + comparisonType); + case MORE_THAN: + sb.append("more than ").append(amount); + break; + case FEWER_THAN: + sb.append("less than ").append(amount); + break; + case EQUAL_TO: + sb.append("exactly ").append(amount); + break; + case OR_GREATER: + sb.append(amount).append(" or more"); + break; + case OR_LESS: + sb.append(amount).append(" or less"); + break; + default: + throw new IllegalArgumentException("Unsupported ComparisonType in LifeCompareCondition: " + comparisonType); } sb.append(" life"); return sb.toString(); diff --git a/Mage/src/main/java/mage/abilities/condition/common/LiveLostLastTurnCondition.java b/Mage/src/main/java/mage/abilities/condition/common/LiveLostLastTurnCondition.java index fc625230ab8..fde812b4aab 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/LiveLostLastTurnCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/LiveLostLastTurnCondition.java @@ -1,28 +1,24 @@ - package mage.abilities.condition.common; import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.game.Game; -import mage.watchers.WatcherUtils; import mage.watchers.common.PlayerLostLifeWatcher; /** - * * @author LevelX */ public enum LiveLostLastTurnCondition implements Condition { - instance; @Override public boolean apply(Game game, Ability source) { PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class); - if (watcher != null) { - return watcher.getLifeLostLastTurn(source.getControllerId()) > 0; - } else { - WatcherUtils.logMissingWatcher(game, source, PlayerLostLifeWatcher.class, this.getClass()); - } - return false; + return watcher != null && watcher.getLifeLostLastTurn(source.getControllerId()) > 0; + } + + @Override + public String toString() { + return "you lost life last turn"; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/MonarchIsNotSetCondition.java b/Mage/src/main/java/mage/abilities/condition/common/MonarchIsNotSetCondition.java index f489ddfa2e9..e46e06afac8 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/MonarchIsNotSetCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/MonarchIsNotSetCondition.java @@ -1,4 +1,3 @@ - package mage.abilities.condition.common; import mage.abilities.Ability; @@ -19,6 +18,6 @@ public enum MonarchIsNotSetCondition implements Condition { @Override public String toString() { - return "if there is no monarch"; + return "there is no monarch"; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/MonstrousCondition.java b/Mage/src/main/java/mage/abilities/condition/common/MonstrousCondition.java index d52277a8171..5723bee4556 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/MonstrousCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/MonstrousCondition.java @@ -1,5 +1,3 @@ - - package mage.abilities.condition.common; import mage.abilities.Ability; @@ -7,21 +5,22 @@ import mage.abilities.condition.Condition; import mage.game.Game; import mage.game.permanent.Permanent; - /** * Checks if a Permanent is monstrous * * @author LevelX2 */ public enum MonstrousCondition implements Condition { - instance; + @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - return permanent.isMonstrous(); - } - return false; + return permanent != null && permanent.isMonstrous(); + } + + @Override + public String toString() { + return "{this} is monstrous"; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/OpponentHasMoreLifeCondition.java b/Mage/src/main/java/mage/abilities/condition/common/OpponentHasMoreLifeCondition.java index 5ea4d9a6131..d4db69c9a0e 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/OpponentHasMoreLifeCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/OpponentHasMoreLifeCondition.java @@ -1,5 +1,3 @@ - - package mage.abilities.condition.common; import mage.abilities.Ability; @@ -10,25 +8,23 @@ import mage.players.Player; import java.util.UUID; /** - * * @author fireshoes */ public enum OpponentHasMoreLifeCondition implements Condition { instance; - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - for (UUID uuid : game.getOpponents(controller.getId())) { - Player opponent = game.getPlayer(uuid); - if (opponent != null) { - if (opponent.getLife() > controller.getLife()) { - return true; - } - } + if (controller == null) { + return false; + } + for (UUID uuid : game.getOpponents(controller.getId())) { + Player opponent = game.getPlayer(uuid); + if (opponent != null && opponent.getLife() > controller.getLife()) { + return true; } } return false; diff --git a/Mage/src/main/java/mage/abilities/condition/common/ProwlCostWasPaidCondition.java b/Mage/src/main/java/mage/abilities/condition/common/ProwlCostWasPaidCondition.java index 640daa6d727..6975d72c1a0 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/ProwlCostWasPaidCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/ProwlCostWasPaidCondition.java @@ -22,7 +22,7 @@ public enum ProwlCostWasPaidCondition implements Condition { @Override public String toString() { - return "this spell's prowl cost was paid"; + return "its prowl cost was paid"; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/RenownedSourceCondition.java b/Mage/src/main/java/mage/abilities/condition/common/RenownedSourceCondition.java index 3b49012cfef..03af32c71d4 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/RenownedSourceCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/RenownedSourceCondition.java @@ -6,27 +6,32 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * Checks if a Permanent is renown + * Checks if a Permanent is renowned * * @author LevelX2 */ public enum RenownedSourceCondition implements Condition { - instance; + THIS("{this} is"), + ITS("it's"); + private final String name; + + RenownedSourceCondition(String name) { + this.name = name; + } + @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { - return permanent.isRenowned(); + return permanent.isRenowned(); } return false; } @Override public String toString() { - return "it's renowned"; + return name + " renowned"; } - - -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/RevealedOrControlledDragonCondition.java b/Mage/src/main/java/mage/abilities/condition/common/RevealedOrControlledDragonCondition.java index 8658e5897bf..c13f4a2f6fc 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/RevealedOrControlledDragonCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/RevealedOrControlledDragonCondition.java @@ -27,4 +27,9 @@ public enum RevealedOrControlledDragonCondition implements Condition { = game.getState().getWatcher(DragonOnTheBattlefieldWhileSpellWasCastWatcher.class); return watcher != null && watcher.checkCondition(source, game); } + + @Override + public String toString() { + return "you revealed a Dragon card or controlled a Dragon as you cast this spell"; + } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/SourceAttackingPlayerWithMostLifeCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SourceAttackingPlayerWithMostLifeCondition.java index 7d066f2e29b..d2e2639c92d 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/SourceAttackingPlayerWithMostLifeCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/SourceAttackingPlayerWithMostLifeCondition.java @@ -31,6 +31,6 @@ public enum SourceAttackingPlayerWithMostLifeCondition implements Condition { @Override public String toString() { - return "{this} is attacking the player with the most life or tied for most life"; + return "it's attacking the player with the most life or tied for most life"; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/SourceEnteredThisTurnCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SourceEnteredThisTurnCondition.java index 2ff18a230b8..8007d430b84 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/SourceEnteredThisTurnCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/SourceEnteredThisTurnCondition.java @@ -25,6 +25,6 @@ public enum SourceEnteredThisTurnCondition implements Condition { @Override public String toString() { - return "{this} " + (flag ? "entered" : "didn't enter") + " the battlefield this turn"; + return "{this} " + (flag ? "entered" : "didn't enter the battlefield") + " this turn"; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/SourceHasCountersCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SourceHasCountersCondition.java index b7aab4c8403..ed372d5dea7 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/SourceHasCountersCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/SourceHasCountersCondition.java @@ -12,14 +12,17 @@ public enum SourceHasCountersCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Permanent permanent = source.getSourcePermanentOrLKI(game); - if (permanent == null) { - return false; - } - return permanent + return permanent != null + && permanent .getCounters(game) .values() .stream() .mapToInt(Counter::getCount) .anyMatch(x -> x > 0); } + + @Override + public String toString() { + return "{this} has counters on it"; + } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/SourceInExileCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SourceInExileCondition.java index 0625f697a11..7570560e115 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/SourceInExileCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/SourceInExileCondition.java @@ -10,7 +10,6 @@ import mage.game.Game; * * @author Susucr */ - public enum SourceInExileCondition implements Condition { instance; @@ -18,4 +17,9 @@ public enum SourceInExileCondition implements Condition { public boolean apply(Game game, Ability source) { return game.getState().getZone(source.getSourceId()) == Zone.EXILED; } + + @Override + public String toString() { + return "this card is exiled"; + } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/SourceIsEnchantmentCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SourceIsEnchantmentCondition.java new file mode 100644 index 00000000000..246308b6e59 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/SourceIsEnchantmentCondition.java @@ -0,0 +1,27 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.game.Game; + +import java.util.Optional; + +/** + * @author TheElk801 + */ +public enum SourceIsEnchantmentCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return Optional + .ofNullable(source.getSourcePermanentOrLKI(game)) + .filter(permanent -> permanent.isEnchantment(game)) + .isPresent(); + } + + @Override + public String toString() { + return "this permanent is an enchantment"; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/SourceOnBattlefieldCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SourceOnBattlefieldCondition.java index d5b042add5b..81d0170a292 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/SourceOnBattlefieldCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/SourceOnBattlefieldCondition.java @@ -20,6 +20,6 @@ public enum SourceOnBattlefieldCondition implements Condition { @Override public String toString() { - return "if {this} is on the battlefield"; + return "{this} is on the battlefield"; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/SpectacleCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SpectacleCondition.java index 5a9370e416b..d97499b4024 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/SpectacleCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/SpectacleCondition.java @@ -1,4 +1,3 @@ - package mage.abilities.condition.common; import mage.abilities.Ability; @@ -11,11 +10,15 @@ import mage.util.CardUtil; * @author TheElk801 */ public enum SpectacleCondition implements Condition { - instance; @Override public boolean apply(Game game, Ability source) { return CardUtil.checkSourceCostsTagExists(game, source, SpectacleAbility.SPECTACLE_ACTIVATION_VALUE_KEY); } + + @Override + public String toString() { + return "its spectacle cost was paid"; + } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/SurgedCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SurgedCondition.java index 8b65ebdc690..6ded9090265 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/SurgedCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/SurgedCondition.java @@ -1,4 +1,3 @@ - package mage.abilities.condition.common; import mage.abilities.Ability; @@ -8,15 +7,18 @@ import mage.game.Game; import mage.util.CardUtil; /** - * * @author LevelX2 */ public enum SurgedCondition implements Condition { - instance; @Override public boolean apply(Game game, Ability source) { return CardUtil.checkSourceCostsTagExists(game, source, SurgeAbility.SURGE_ACTIVATION_VALUE_KEY); } + + @Override + public String toString() { + return "its surge cost was paid"; + } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/SuspendedCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SuspendedCondition.java index 83dcaad3e73..06bb40c33ce 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/SuspendedCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/SuspendedCondition.java @@ -43,7 +43,6 @@ public enum SuspendedCondition implements Condition { @Override public String toString() { - return "{this} is suspended"; + return "this card is suspended"; } - } diff --git a/Mage/src/main/java/mage/abilities/condition/common/TreasureSpentToCastCondition.java b/Mage/src/main/java/mage/abilities/condition/common/TreasureSpentToCastCondition.java index 11035124bda..f598aef57d2 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/TreasureSpentToCastCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/TreasureSpentToCastCondition.java @@ -19,4 +19,9 @@ public enum TreasureSpentToCastCondition implements Condition { } return ManaPaidSourceWatcher.getTreasurePaid(source.getSourceId(), game) > 0; } + + @Override + public String toString() { + return "mana from a Treasure was spent to cast it"; + } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/TributeNotPaidCondition.java b/Mage/src/main/java/mage/abilities/condition/common/TributeNotPaidCondition.java index b6da7a564fd..1c972e33416 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/TributeNotPaidCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/TributeNotPaidCondition.java @@ -1,4 +1,3 @@ - package mage.abilities.condition.common; import mage.abilities.Ability; @@ -11,8 +10,7 @@ import mage.game.Game; * @author LevelX2 */ public enum TributeNotPaidCondition implements Condition { - - instance; + instance; @Override public boolean apply(Game game, Ability source) { @@ -22,4 +20,9 @@ public enum TributeNotPaidCondition implements Condition { } return false; } + + @Override + public String toString() { + return "tribute wasn't paid"; + } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/TwoOrMoreSpellsWereCastLastTurnCondition.java b/Mage/src/main/java/mage/abilities/condition/common/TwoOrMoreSpellsWereCastLastTurnCondition.java index 1f905605a41..f8d755fa332 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/TwoOrMoreSpellsWereCastLastTurnCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/TwoOrMoreSpellsWereCastLastTurnCondition.java @@ -1,4 +1,3 @@ - package mage.abilities.condition.common; import mage.abilities.Ability; @@ -10,22 +9,21 @@ import mage.watchers.common.CastSpellLastTurnWatcher; * @author nantuko */ public enum TwoOrMoreSpellsWereCastLastTurnCondition implements Condition { - - instance; + instance; @Override public boolean apply(Game game, Ability source) { - CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); - if(watcher == null){ - return false; - } - // if any player cast more than two spells, return true - for (Integer count : watcher.getAmountOfSpellsCastOnPrevTurn().values()) { - if (count >= 2) { - return true; - } - } - // no one cast two or more spells last turn - return false; + return game + .getState() + .getWatcher(CastSpellLastTurnWatcher.class) + .getAmountOfSpellsCastOnPrevTurn() + .values() + .stream() + .anyMatch(x -> x >= 2); + } + + @Override + public String toString() { + return "a player cast two or more spells last turn"; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/VoidCondition.java b/Mage/src/main/java/mage/abilities/condition/common/VoidCondition.java new file mode 100644 index 00000000000..c701de76610 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/VoidCondition.java @@ -0,0 +1,32 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.game.Game; +import mage.watchers.common.VoidWatcher; + +/** + * Requires {@link mage.watchers.common.VoidWatcher} + * + * @author TheElk801 + */ +public enum VoidCondition implements Condition { + instance; + private static final Hint hint = new ConditionHint(instance); + + public static Hint getHint() { + return hint; + } + + @Override + public boolean apply(Game game, Ability source) { + return VoidWatcher.checkPlayer(source.getControllerId(), game); + } + + @Override + public String toString() { + return "a nonland permanent left the battlefield this turn or a spell was warped this turn"; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/YouControlTwoOrMoreGatesCondition.java b/Mage/src/main/java/mage/abilities/condition/common/YouControlTwoOrMoreGatesCondition.java new file mode 100644 index 00000000000..73b5f2517d8 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/YouControlTwoOrMoreGatesCondition.java @@ -0,0 +1,26 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.game.Game; + +/** + * @author TheElk801 + */ +public enum YouControlTwoOrMoreGatesCondition implements Condition { + instance; + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.GATE); + + @Override + public boolean apply(Game game, Ability source) { + return game.getBattlefield().count(filter, source.getControllerId(), source, game) >= 2; + } + + @Override + public String toString() { + return "you control two or more Gates"; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/YouGainedLifeCondition.java b/Mage/src/main/java/mage/abilities/condition/common/YouGainedLifeCondition.java index fd848917998..7e142f8b1a6 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/YouGainedLifeCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/YouGainedLifeCondition.java @@ -32,6 +32,6 @@ public class YouGainedLifeCondition extends IntCompareCondition { @Override public String toString() { - return "if you gained " + (value == 0 ? "" : (value + 1) + " or more ") + "life this turn"; + return "you gained " + (value == 0 ? "" : (value + 1) + " or more ") + "life this turn"; } } diff --git a/Mage/src/main/java/mage/abilities/costs/AbilityCosts.java b/Mage/src/main/java/mage/abilities/costs/AbilityCosts.java deleted file mode 100644 index a63ebc1b81a..00000000000 --- a/Mage/src/main/java/mage/abilities/costs/AbilityCosts.java +++ /dev/null @@ -1,15 +0,0 @@ - - -package mage.abilities.costs; - -import java.io.Serializable; - -/** - * - * @author BetaSteward_at_googlemail.com - */ -public class AbilityCosts implements Serializable { - - - -} diff --git a/Mage/src/main/java/mage/abilities/costs/common/TapTargetCost.java b/Mage/src/main/java/mage/abilities/costs/common/TapTargetCost.java index 0d8a5b77059..ea468535e43 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/TapTargetCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/TapTargetCost.java @@ -4,6 +4,7 @@ import mage.abilities.Ability; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.constants.Outcome; +import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetControlledPermanent; @@ -20,6 +21,18 @@ public class TapTargetCost extends CostImpl { TargetControlledPermanent target; + public TapTargetCost(FilterControlledPermanent filter) { + this(1, filter); + } + + public TapTargetCost(int amount, FilterControlledPermanent filter) { + this(amount, amount, filter); + } + + public TapTargetCost(int minAmount, int maxAmount, FilterControlledPermanent filter) { + this(new TargetControlledPermanent(minAmount, maxAmount, filter, true)); + } + public TapTargetCost(TargetControlledPermanent target) { this.target = target; this.target.withNotTarget(true); // costs are never targeted diff --git a/Mage/src/main/java/mage/abilities/decorator/ConditionalActivatedAbility.java b/Mage/src/main/java/mage/abilities/decorator/ConditionalActivatedAbility.java deleted file mode 100644 index 6f7d8681e50..00000000000 --- a/Mage/src/main/java/mage/abilities/decorator/ConditionalActivatedAbility.java +++ /dev/null @@ -1,81 +0,0 @@ -package mage.abilities.decorator; - -import mage.abilities.ActivatedAbilityImpl; -import mage.abilities.condition.Condition; -import mage.abilities.costs.Cost; -import mage.abilities.effects.Effect; -import mage.abilities.effects.Effects; -import mage.constants.EffectType; -import mage.constants.TimingRule; -import mage.constants.Zone; -import mage.game.Game; - -/** - * @author LevelX - */ -public class ConditionalActivatedAbility extends ActivatedAbilityImpl { - - private static final Effects emptyEffects = new Effects(); - - private String ruleText = null; - private boolean showCondition = true; - - public ConditionalActivatedAbility(Effect effect, Cost cost, Condition condition) { - this(Zone.BATTLEFIELD, effect, cost, condition); - } - - public ConditionalActivatedAbility(Zone zone, Effect effect, Cost cost, Condition condition) { - super(zone, effect, cost); - this.condition = condition; - } - - public ConditionalActivatedAbility(Zone zone, Effect effect, Cost cost, Condition condition, String rule) { - this(zone, effect, cost, condition); - this.ruleText = rule; - } - - protected ConditionalActivatedAbility(final ConditionalActivatedAbility ability) { - super(ability); - this.ruleText = ability.ruleText; - this.showCondition = ability.showCondition; - } - - @Override - public Effects getEffects(Game game, EffectType effectType) { - if (!condition.apply(game, this)) { - return emptyEffects; - } - return super.getEffects(game, effectType); - } - - @Override - public ConditionalActivatedAbility copy() { - return new ConditionalActivatedAbility(this); - } - - public ConditionalActivatedAbility hideCondition() { - this.showCondition = false; - return this; - } - - @Override - public String getRule() { - if (ruleText != null && !ruleText.isEmpty()) { - return ruleText; - } - StringBuilder sb = new StringBuilder(super.getRule()); - if (showCondition) { - sb.append(" Activate only "); - if (timing == TimingRule.SORCERY) { - sb.append("as a sorcery and only "); - } - String conditionText = condition.toString(); - if (!conditionText.startsWith("during") && !conditionText.startsWith("before") && !conditionText.startsWith("if")) { - sb.append("if "); - } - sb.append(conditionText); - sb.append('.'); - } - return sb.toString(); - } -} diff --git a/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java b/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java deleted file mode 100644 index f975727ef27..00000000000 --- a/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java +++ /dev/null @@ -1,158 +0,0 @@ -package mage.abilities.decorator; - -import mage.MageObject; -import mage.abilities.Modes; -import mage.abilities.TriggeredAbility; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.condition.Condition; -import mage.abilities.effects.Effect; -import mage.abilities.effects.Effects; -import mage.abilities.hint.Hint; -import mage.constants.EffectType; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.watchers.Watcher; - -import java.util.ArrayList; -import java.util.List; - -/** - * Adds condition to {@link mage.abilities.effects.ContinuousEffect}. Acts as - * decorator. - * - * @author nantuko - */ -public class ConditionalInterveningIfTriggeredAbility extends TriggeredAbilityImpl { - - protected TriggeredAbility ability; - protected Condition condition; - protected String abilityText; - - /** - * Triggered ability with a condition. Set the optionality for the trigger - * ability itself. - * - * @param ability - * @param condition - * @param text explicit rule text for the ability, if null or empty, the - * rule text generated by the triggered ability itself is used. - */ - public ConditionalInterveningIfTriggeredAbility(TriggeredAbility ability, Condition condition, String text) { - super(ability.getZone(), null); - if (ability.isLeavesTheBattlefieldTrigger()) { - setLeavesTheBattlefieldTrigger(true); - } - this.ability = ability; - this.condition = condition; - this.abilityText = text; - } - - protected ConditionalInterveningIfTriggeredAbility(final ConditionalInterveningIfTriggeredAbility triggered) { - super(triggered); - this.ability = triggered.ability.copy(); - this.condition = triggered.condition; - this.abilityText = triggered.abilityText; - } - - @Override - public boolean checkInterveningIfClause(Game game) { - return condition.apply(game, this); - } - - @Override - public ConditionalInterveningIfTriggeredAbility copy() { - return new ConditionalInterveningIfTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return ability.checkEventType(event, game); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - ability.setSourceId(this.getSourceId()); - ability.setControllerId(this.getControllerId()); - return ability.checkTrigger(event, game); - } - - @Override - public String getRule() { - if (abilityText == null || abilityText.isEmpty()) { - return ability.getRule(); - } - return addRulePrefix(abilityText + (abilityText.endsWith(".") || abilityText.endsWith("\"") || abilityText.endsWith(">") ? "" : ".")); - } - - @Override - public Effects getEffects() { - return ability.getEffects(); - } - - @Override - public void addEffect(Effect effect) { - ability.addEffect(effect); - } - - @Override - public Modes getModes() { - return ability.getModes(); - } - - @Override - public List getWatchers() { - return ability.getWatchers(); - } - - @Override - public void addWatcher(Watcher watcher) { - ability.addWatcher(watcher); - } - - @Override - public List getHints() { - List res = new ArrayList<>(super.getHints()); - res.addAll(ability.getHints()); - return res; - } - - @Override - public Effects getEffects(Game game, EffectType effectType) { - return ability.getEffects(game, effectType); - } - - @Override - public boolean isOptional() { - return ability.isOptional(); - } - - @Override - public void setSourceObjectZoneChangeCounter(int sourceObjectZoneChangeCounter) { - ability.setSourceObjectZoneChangeCounter(sourceObjectZoneChangeCounter); - } - - @Override - public void initSourceObjectZoneChangeCounter(Game game, boolean force) { - ability.initSourceObjectZoneChangeCounter(game, force); - } - - @Override - public int getSourceObjectZoneChangeCounter() { - return ability.getSourceObjectZoneChangeCounter(); - } - - @Override - public boolean caresAboutManaColor() { - return condition.caresAboutManaColor(); - } - - @Override - public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) { - if (isLeavesTheBattlefieldTrigger()) { - // TODO: leaves battlefield and die are not same! Is it possible make a diff logic? - return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game); - } else { - return super.isInUseableZone(game, sourceObject, event); - } - } -} diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/EffectKeyValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/EffectKeyValue.java index b3cbe5cb55d..e3671c7aafb 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/EffectKeyValue.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/EffectKeyValue.java @@ -10,36 +10,36 @@ import mage.game.Game; * @author stravant */ public class EffectKeyValue implements DynamicValue { - private String key; - private String description; + + private final String key; + private final String description; public EffectKeyValue(String key) { - this.key = key; - this.description = key; + this(key, key); } public EffectKeyValue(String key, String description) { - this(key); + this.key = key; this.description = description; } @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - return (Integer)effect.getValue(key); + return (Integer) effect.getValue(key); } @Override - public EffectKeyValue copy(){ + public EffectKeyValue copy() { return new EffectKeyValue(this.key, this.description); } @Override public String toString() { - return "equal to"; + return description; } @Override public String getMessage() { - return description; + return ""; } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/GreatestAmongPermanentsValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/GreatestAmongPermanentsValue.java index c800465d79c..5fa525f2808 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/GreatestAmongPermanentsValue.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/GreatestAmongPermanentsValue.java @@ -7,6 +7,7 @@ import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -25,6 +26,8 @@ public class GreatestAmongPermanentsValue implements DynamicValue { = new GreatestAmongPermanentsValue(Quality.Power, StaticFilters.FILTER_CONTROLLED_CREATURES); public static final GreatestAmongPermanentsValue POWER_OTHER_CONTROLLED_CREATURES = new GreatestAmongPermanentsValue(Quality.Power, StaticFilters.FILTER_OTHER_CONTROLLED_CREATURES); + public static final GreatestAmongPermanentsValue POWER_ALL_CREATURES + = new GreatestAmongPermanentsValue(Quality.Power, new FilterCreaturePermanent("creatures on the battlefield")); public static final GreatestAmongPermanentsValue TOUGHNESS_CONTROLLED_CREATURES = new GreatestAmongPermanentsValue(Quality.Toughness, StaticFilters.FILTER_CONTROLLED_CREATURES); public static final GreatestAmongPermanentsValue TOUGHNESS_OTHER_CONTROLLED_CREATURES @@ -114,4 +117,4 @@ public class GreatestAmongPermanentsValue implements DynamicValue { public Hint getHint() { return new ValueHint("Greatest " + quality.text + " among " + filter.getMessage(), this); } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/SavedDamageValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/SavedDamageValue.java index ac6e0cd6b8c..1753578e2a7 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/SavedDamageValue.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/SavedDamageValue.java @@ -10,7 +10,8 @@ import mage.game.Game; */ public enum SavedDamageValue implements DynamicValue { MANY("many"), - MUCH("much"); + MUCH("much"), + AMOUNT("amount of"); private final String message; diff --git a/Mage/src/main/java/mage/abilities/effects/CreateTokenCopySourceEffect.java b/Mage/src/main/java/mage/abilities/effects/CreateTokenCopySourceEffect.java index 2e8b722c0fa..deebf3897d7 100644 --- a/Mage/src/main/java/mage/abilities/effects/CreateTokenCopySourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/CreateTokenCopySourceEffect.java @@ -6,6 +6,7 @@ import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; /** * Created by glerman on 20/6/15. @@ -27,8 +28,8 @@ public class CreateTokenCopySourceEffect extends OneShotEffect { super(Outcome.PutCreatureInPlay); this.number = copies; this.tapped = tapped; - staticText = "create " + (copies > 1 ? copies : "a") + " " + (tapped ? "tapped " : "") - + (copies > 1 ? "tokens that are" : "token that's") + " a copy of {this}"; + staticText = "create " + CardUtil.numberToText(copies, "a") + " " + (tapped ? "tapped " : "") + + (copies > 1 ? "tokens that are copies of " : "token that's a copy of ") + "{this}"; } protected CreateTokenCopySourceEffect(final CreateTokenCopySourceEffect effect) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenAttachSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenAttachSourceEffect.java index 11d45ac59f1..91eab7dae25 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenAttachSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenAttachSourceEffect.java @@ -2,11 +2,17 @@ package mage.abilities.effects.common; import mage.abilities.Ability; import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.Token; +import mage.players.Player; +import mage.target.TargetPermanent; -import java.util.Optional; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; /** * @author weirddan455 @@ -42,22 +48,42 @@ public class CreateTokenAttachSourceEffect extends CreateTokenEffect { @Override public boolean apply(Game game, Ability source) { super.apply(game, source); - Permanent token = this - .getLastAddedTokenIds() - .stream() - .findFirst() - .map(game::getPermanent) - .orElse(null); - if (token == null || optional - && !Optional - .ofNullable(game.getPlayer(source.getControllerId())) - .map(player -> player.chooseUse( - Outcome.BoostCreature, "Attach the equipment to the token?", source, game - )) - .orElse(false)) { + Player player = game.getPlayer(source.getControllerId()); + Permanent equipment = source.getSourcePermanentIfItStillExists(game); + if (player == null + || equipment == null + || optional + && !player.chooseUse( + Outcome.BoostCreature, "Attach " + + equipment.getLogName() + " to the token?", source, game + )) { return false; } - token.addAttachment(source.getSourceId(), source, game); + List permanents = this + .getLastAddedTokenIds() + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + Permanent token; + switch (permanents.size()) { + case 0: + return false; + case 1: + token = permanents.get(0); + break; + default: + FilterPermanent filter = new FilterPermanent("token"); + filter.add(new PermanentReferenceInCollectionPredicate(permanents, game)); + TargetPermanent target = new TargetPermanent(filter); + target.withNotTarget(true); + target.withChooseHint("to attach to"); + player.choose(outcome, target, source, game); + token = game.getPermanent(target.getFirstTarget()); + } + if (token != null) { + token.addAttachment(source.getSourceId(), source, game); + } return true; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/GainLifeAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/GainLifeAllEffect.java new file mode 100644 index 00000000000..6f164dee867 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/GainLifeAllEffect.java @@ -0,0 +1,83 @@ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.game.Game; + +import java.util.Collection; +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public class GainLifeAllEffect extends OneShotEffect { + + private final int amount; + private final TargetController targetController; + + public GainLifeAllEffect(int amount) { + this(amount, TargetController.EACH_PLAYER); + } + + public GainLifeAllEffect(int amount, TargetController targetController) { + super(Outcome.Benefit); + this.amount = amount; + this.targetController = targetController; + staticText = makeRule(amount, targetController); + } + + private GainLifeAllEffect(final GainLifeAllEffect effect) { + super(effect); + this.amount = effect.amount; + this.targetController = effect.targetController; + } + + @Override + public GainLifeAllEffect copy() { + return new GainLifeAllEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID playerId : getPlayers(targetController, game, source)) { + Optional.ofNullable(playerId) + .map(game::getPlayer) + .ifPresent(player -> player.gainLife(amount, game, source)); + } + return true; + } + + private static Collection getPlayers(TargetController targetController, Game game, Ability source) { + switch (targetController) { + case ANY: + case EACH_PLAYER: + return game.getState().getPlayersInRange(source.getControllerId(), game); + case OPPONENT: + return game.getOpponents(source.getControllerId()); + default: + throw new IllegalArgumentException("TargetController " + targetController + " not supported"); + } + } + + private static String makeRule(int amount, TargetController targetController) { + StringBuilder sb = new StringBuilder("each "); + switch (targetController) { + case ANY: + case EACH_PLAYER: + sb.append("player"); + break; + case OPPONENT: + sb.append("opponent"); + break; + default: + throw new IllegalArgumentException("TargetController " + targetController + " not supported"); + } + sb.append(" gains "); + sb.append(amount); + sb.append(" life"); + return sb.toString(); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/LearnEffect.java b/Mage/src/main/java/mage/abilities/effects/common/LearnEffect.java index 907eb42bc7e..88e6399b2f9 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/LearnEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/LearnEffect.java @@ -20,12 +20,11 @@ public class LearnEffect extends OneShotEffect { filter.add(SubType.LESSON.getPredicate()); } - private static final String defaultText = "learn. (You may reveal a Lesson card you own from outside the game " + - "and put it into your hand, or discard a card to draw a card.)"; public LearnEffect() { super(Outcome.Neutral); - staticText = defaultText; + staticText = "learn. (You may reveal a Lesson card you own " + + "from outside the game and put it into your hand, or discard a card to draw a card.)"; } private LearnEffect(final LearnEffect effect) { @@ -50,8 +49,4 @@ public class LearnEffect extends OneShotEffect { public LearnEffect copy() { return new LearnEffect(this); } - - public static String getDefaultText() { - return defaultText; - } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/MeldEffect.java b/Mage/src/main/java/mage/abilities/effects/common/MeldEffect.java index 60e54932be2..0d85288b5dd 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/MeldEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/MeldEffect.java @@ -41,6 +41,7 @@ public class MeldEffect extends OneShotEffect { this.meldWithName = meldWithName; this.meldIntoName = meldIntoName; this.attacking = attacking; + this.staticText = "exile them, then meld them into " + meldIntoName; } protected MeldEffect(final MeldEffect effect) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/MillHalfLibraryTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/MillHalfLibraryTargetEffect.java index 155bcf15157..8f9a78084cd 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/MillHalfLibraryTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/MillHalfLibraryTargetEffect.java @@ -7,6 +7,8 @@ import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** * @author TheElk801 */ @@ -31,12 +33,15 @@ public class MillHalfLibraryTargetEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - if (player == null) { - return false; + for (UUID playerId : getTargetPointer().getTargets(game, source)) { + Player player = game.getPlayer(playerId); + if (player == null) { + return false; + } + int count = player.getLibrary().size(); + player.millCards(count / 2 + (roundUp ? count % 2 : 0), source, game); } - int count = player.getLibrary().size(); - return player.millCards(count / 2 + (roundUp ? count % 2 : 0), source, game).size() > 0; + return true; } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlAttachedEffect.java index 163470b756d..15767c750a0 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlAttachedEffect.java @@ -45,16 +45,14 @@ public class ReturnToBattlefieldUnderOwnerControlAttachedEffect extends OneShotE if (controller == null) { return false; } - Object object = getValue("attachedTo"); - if (object instanceof Permanent) { - Card card = game.getCard(((Permanent) object).getId()); - if (card != null) { - if (controller.moveCards(card, Zone.BATTLEFIELD, source, game, this.tapped, false, true, null)) { - return true; - } + Object attached = getValue("attachedTo"); + Object zcc = getValue("zcc"); + if (attached instanceof Permanent && zcc instanceof Integer) { + Card card = game.getCard(((Permanent) attached).getId()); + if (card != null && (int) zcc == card.getZoneChangeCounter(game)) { + return controller.moveCards(card, Zone.BATTLEFIELD, source, game, this.tapped, false, true, null); } } - return false; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/WishEffect.java b/Mage/src/main/java/mage/abilities/effects/common/WishEffect.java index b9b8d3793b6..9d76b9a82f3 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/WishEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/WishEffect.java @@ -125,7 +125,7 @@ public class WishEffect extends OneShotEffect { TargetCard target = new TargetCard(Zone.ALL, filter); target.withNotTarget(true); - if (controller.choose(Outcome.Benefit, filteredCards, target, source, game)) { + if (controller.choose(Outcome.PutCardInPlay, filteredCards, target, source, game)) { Card card = controller.getSideboard().get(target.getFirstTarget(), game); if (card == null && alsoFromExile) { card = game.getCard(target.getFirstTarget()); diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/GoadTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/GoadTargetEffect.java index 4fe12b5667b..9c2619323cc 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/GoadTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/GoadTargetEffect.java @@ -25,6 +25,7 @@ public class GoadTargetEffect extends ContinuousEffectImpl { * turn of the controller of that spell or ability, that creature attacks * each combat if able and attacks a player other than that player if able. */ + public static String goadReminderText = "(Until your next turn, that creature attacks each combat if able and attacks a player other than you if able.)"; public GoadTargetEffect() { this(Duration.UntilYourNextTurn); } @@ -74,6 +75,6 @@ public class GoadTargetEffect extends ContinuousEffectImpl { return staticText; } return "goad " + getTargetPointer().describeTargets(mode.getTargets(), "that creature") - + ". (Until your next turn, that creature attacks each combat if able and attacks a player other than you if able.)"; + + ". "+goadReminderText; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByAllTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByAllTargetEffect.java index fd41ecea46e..2a227ac59ab 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByAllTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByAllTargetEffect.java @@ -19,7 +19,7 @@ public class MustBeBlockedByAllTargetEffect extends RequirementEffect { public MustBeBlockedByAllTargetEffect(Duration duration) { super(duration); - staticText = "All creatures able to block target creature " + + staticText = "all creatures able to block target creature " + (this.getDuration() == Duration.EndOfTurn ? "this turn " : "") + "do so"; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityControllerEffect.java index 07a75f3c492..50784744666 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityControllerEffect.java @@ -2,12 +2,12 @@ package mage.abilities.effects.common.continuous; +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffectImpl; import mage.constants.Duration; import mage.constants.Layer; import mage.constants.Outcome; import mage.constants.SubLayer; -import mage.abilities.Ability; -import mage.abilities.effects.ContinuousEffectImpl; import mage.game.Game; import mage.players.Player; @@ -34,7 +34,7 @@ public class GainAbilityControllerEffect extends ContinuousEffectImpl { public GainAbilityControllerEffect(Ability ability, Duration duration) { super(duration, Layer.PlayerEffects, SubLayer.NA, Outcome.AddAbility); this.ability = ability; - staticText = "You have " + ability.getRule(); + staticText = "you " + (duration == Duration.WhileOnBattlefield ? "have" : "gain") + ' ' + ability.getRule(); if (!duration.toString().isEmpty()) { staticText += ' ' + duration.toString(); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/SwitchPowerToughnessTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/SwitchPowerToughnessTargetEffect.java index 0ece62d0101..b4885a2a020 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/SwitchPowerToughnessTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/SwitchPowerToughnessTargetEffect.java @@ -10,6 +10,8 @@ import mage.abilities.effects.ContinuousEffectImpl; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** * @author ayratn */ @@ -30,13 +32,15 @@ public class SwitchPowerToughnessTargetEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - Permanent target = game.getPermanent(this.getTargetPointer().getFirst(game, source)); - if (target == null) { - return false; + int affectedTargets = 0; + for (UUID uuid : getTargetPointer().getTargets(game, source)) { + Permanent target = game.getPermanent(uuid); + if (target != null) { + target.switchPowerToughness(); + affectedTargets++; + } } - - target.switchPowerToughness(); - return true; + return affectedTargets > 0; } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/CastFromHandForFreeEffect.java b/Mage/src/main/java/mage/abilities/effects/common/cost/CastFromHandForFreeEffect.java index 75b5b17d635..f71c5c2796d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/cost/CastFromHandForFreeEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/cost/CastFromHandForFreeEffect.java @@ -24,7 +24,7 @@ public class CastFromHandForFreeEffect extends OneShotEffect { public CastFromHandForFreeEffect(FilterCard filter) { super(Outcome.PlayForFree); this.filter = filter; - this.staticText = "you may cast " + filter.getMessage() + " from your hand without paying its mana cost"; + this.staticText = "you may cast " + filter.getMessage() + (filter.getMessage().contains("your hand") ? "" : " from your hand") + " without paying its mana cost"; } protected CastFromHandForFreeEffect(final CastFromHandForFreeEffect effect) { @@ -35,10 +35,9 @@ public class CastFromHandForFreeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - return CardUtil.castSpellWithAttributesForFree(controller, source, game, new CardsImpl(controller.getHand()), filter); + return controller != null && CardUtil.castSpellWithAttributesForFree( + controller, source, game, new CardsImpl(controller.getHand()), filter + ); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/counter/AddPoisonCounterTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/counter/AddPoisonCounterTargetEffect.java index c2f35e9449b..86e32efe3ff 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/counter/AddPoisonCounterTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/counter/AddPoisonCounterTargetEffect.java @@ -51,8 +51,8 @@ public class AddPoisonCounterTargetEffect extends OneShotEffect { if (staticText != null && !staticText.isEmpty()) { return staticText; } - return getTargetPointer().describeTargets(mode.getTargets(), "it") + + return getTargetPointer().describeTargets(mode.getTargets(), "that player") + (getTargetPointer().isPlural(mode.getTargets()) ? " get " : " gets ") + - CardUtil.getSimpleCountersText(amount, "a", "poison"); + CardUtil.getSimpleCountersText(amount, "a", "poison"); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/replacement/AdditionalTriggerControlledETBReplacementEffect.java b/Mage/src/main/java/mage/abilities/effects/common/replacement/AdditionalTriggerControlledETBReplacementEffect.java index c4b4b464a24..ffa3c03b2bb 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/replacement/AdditionalTriggerControlledETBReplacementEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/replacement/AdditionalTriggerControlledETBReplacementEffect.java @@ -17,7 +17,7 @@ public class AdditionalTriggerControlledETBReplacementEffect extends Replacement public AdditionalTriggerControlledETBReplacementEffect() { super(Duration.WhileOnBattlefield, Outcome.Benefit); - staticText = "If a permanent entering the battlefield causes a triggered ability " + + staticText = "If a permanent entering causes a triggered ability " + "of a permanent you control to trigger, that ability triggers an additional time"; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/DontCauseTriggerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/DontCauseTriggerEffect.java index 55139f9daba..1cbdf35d610 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/DontCauseTriggerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/DontCauseTriggerEffect.java @@ -41,7 +41,7 @@ public class DontCauseTriggerEffect extends ContinuousRuleModifyingEffectImpl { this.filterEntering = filterEntering; this.orDying = orDying; this.filterTriggering = filterTriggering; - staticText = filterEntering.getMessage() + " entering the battlefield" + staticText = filterEntering.getMessage() + " entering" + (orDying ? " or dying" : "") + " don't cause abilities" + (filterTriggering == null ? "" : " of " + filterTriggering.getMessage()) + " to trigger"; diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/SupportEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/SupportEffect.java index 1edcde3b5b1..5d44fbe1263 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/SupportEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/SupportEffect.java @@ -6,7 +6,6 @@ import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.Card; import mage.counters.CounterType; -import mage.filter.common.FilterCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import mage.util.CardUtil; @@ -23,7 +22,7 @@ public class SupportEffect extends AddCountersTargetEffect { this.amountSupportTargets = StaticValue.get(amount); this.otherPermanent = otherPermanent; if (card.isInstantOrSorcery()) { - card.getSpellAbility().addTarget(new TargetCreaturePermanent(0, amount, new FilterCreaturePermanent("target creatures"), false)); + card.getSpellAbility().addTarget(new TargetCreaturePermanent(0, amount)); } staticText = setText(); } diff --git a/Mage/src/main/java/mage/abilities/effects/mana/AddManaInAnyCombinationEffect.java b/Mage/src/main/java/mage/abilities/effects/mana/AddManaInAnyCombinationEffect.java index e81528cfa43..f65cdd8e12d 100644 --- a/Mage/src/main/java/mage/abilities/effects/mana/AddManaInAnyCombinationEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/mana/AddManaInAnyCombinationEffect.java @@ -150,7 +150,7 @@ public class AddManaInAnyCombinationEffect extends ManaEffect { } private String setText() { - StringBuilder sb = new StringBuilder("Add "); + StringBuilder sb = new StringBuilder("add "); String amountString = CardUtil.numberToText(amount.toString()); sb.append(amountString); sb.append(" mana in any combination of "); diff --git a/Mage/src/main/java/mage/abilities/hint/common/EvidenceHint.java b/Mage/src/main/java/mage/abilities/hint/common/EvidenceHint.java index 046f54d737f..e52a025871c 100644 --- a/Mage/src/main/java/mage/abilities/hint/common/EvidenceHint.java +++ b/Mage/src/main/java/mage/abilities/hint/common/EvidenceHint.java @@ -14,7 +14,7 @@ public class EvidenceHint extends ConditionHint { private final int needAmount; public EvidenceHint(int needAmount) { - super(CollectedEvidenceCondition.instance); + super(CollectedEvidenceCondition.instance, "Evidence was used"); this.needAmount = needAmount; } diff --git a/Mage/src/main/java/mage/abilities/hint/common/RenownedHint.java b/Mage/src/main/java/mage/abilities/hint/common/RenownedHint.java index 97e63519f07..5ddd3e5a8f6 100644 --- a/Mage/src/main/java/mage/abilities/hint/common/RenownedHint.java +++ b/Mage/src/main/java/mage/abilities/hint/common/RenownedHint.java @@ -8,7 +8,7 @@ import mage.game.Game; public enum RenownedHint implements Hint { instance; - private static final ConditionHint hint = new ConditionHint(RenownedSourceCondition.instance, + private static final ConditionHint hint = new ConditionHint(RenownedSourceCondition.THIS, "{this} is renowned", null, "{this} isn't renowned", null, true); diff --git a/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java b/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java index 134adc1f246..de792ae59e5 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java @@ -29,7 +29,7 @@ import mage.game.stack.Spell; import mage.players.ManaPool; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.util.CardUtil; import java.util.*; @@ -131,7 +131,7 @@ public class ConvokeAbility extends SimpleStaticAbility implements AlternateMana } filter.add(Predicates.or(colorPredicates)); } - Target target = new TargetControlledCreaturePermanent(1, 1, filter, true); + Target target = new TargetPermanent(1, 1, filter, true); target.withTargetName("creature to tap for convoke"); specialAction.addTarget(target); if (specialAction.canActivate(source.getControllerId(), game).canActivate()) { diff --git a/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java b/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java index eff1c18aa26..627f2f2756c 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java @@ -22,7 +22,7 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.util.CardUtil; import java.awt.*; @@ -146,7 +146,7 @@ class CrewCost extends CostImpl { paid = true; return true; } - Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true) { + Target target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true) { @Override public String getMessage(Game game) { // shows selected power diff --git a/Mage/src/main/java/mage/abilities/keyword/ForecastAbility.java b/Mage/src/main/java/mage/abilities/keyword/ForecastAbility.java index 00e28429ab3..e4eb9ddb428 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ForecastAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ForecastAbility.java @@ -2,12 +2,10 @@ package mage.abilities.keyword; import mage.abilities.ActivatedAbilityImpl; -import mage.abilities.condition.Condition; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.Cost; import mage.abilities.costs.common.RevealSourceFromYourHandCost; import mage.abilities.effects.Effect; -import mage.constants.PhaseStep; import mage.constants.Zone; /** @@ -26,12 +24,10 @@ import mage.constants.Zone; */ public class ForecastAbility extends ActivatedAbilityImpl { - private static final Condition upkeepCondition = new IsStepCondition(PhaseStep.UPKEEP, true); - public ForecastAbility(Effect effect, Cost cost) { super(Zone.HAND, effect, cost); this.maxActivationsPerTurn = 1; - this.condition = upkeepCondition; + this.condition = IsStepCondition.getMyUpkeep(); this.addCost(new RevealSourceFromYourHandCost()); } diff --git a/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java b/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java index b1c532974e2..7297698bac1 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java @@ -291,4 +291,9 @@ enum MadnessCondition implements Condition { return ((Spell) madnessSpell).getSpellAbility().getSpellAbilityCastMode() == SpellAbilityCastMode.MADNESS; } + + @Override + public String toString() { + return "its madness cost was paid"; + } } diff --git a/Mage/src/main/java/mage/abilities/keyword/MentorAbility.java b/Mage/src/main/java/mage/abilities/keyword/MentorAbility.java index 7938ccdc3d7..efb24b269e3 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MentorAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MentorAbility.java @@ -13,6 +13,7 @@ import mage.filter.predicate.permanent.AttackingPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public class MentorAbility extends AttacksTriggeredAbility { public MentorAbility() { super(new MentorEffect(), false); - this.addTarget(new TargetCreaturePermanent(filter)); + this.addTarget(new TargetPermanent(filter)); } protected MentorAbility(final MentorAbility ability) { diff --git a/Mage/src/main/java/mage/abilities/keyword/ProvokeAbility.java b/Mage/src/main/java/mage/abilities/keyword/ProvokeAbility.java index 4d7bd7f0dd6..7108aa802e1 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ProvokeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ProvokeAbility.java @@ -1,19 +1,19 @@ package mage.abilities.keyword; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.common.UntapTargetEffect; import mage.constants.Duration; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.constants.SetTargetPointer; +import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; + +import java.util.UUID; /** * 702.38. Provoke 702.38a Provoke is a triggered ability. “Provoke” means @@ -31,28 +31,16 @@ public class ProvokeAbility extends AttacksTriggeredAbility { } public ProvokeAbility(String text) { - super(new UntapTargetEffect(), true, text); + super(new UntapTargetEffect(), true, text, SetTargetPointer.PLAYER); this.addEffect(new ProvokeRequirementEffect()); + this.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE)); + this.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); } protected ProvokeAbility(final ProvokeAbility ability) { super(ability); } - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (super.checkTrigger(event, game)) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); - UUID defendingPlayerId = game.getCombat().getDefendingPlayerId(sourceId, game); - filter.add(new ControllerIdPredicate(defendingPlayerId)); - this.getTargets().clear(); - TargetCreaturePermanent target = new TargetCreaturePermanent(filter); - this.addTarget(target); - return true; - } - return false; - } - @Override public ProvokeAbility copy() { return new ProvokeAbility(this); diff --git a/Mage/src/main/java/mage/abilities/keyword/RenownAbility.java b/Mage/src/main/java/mage/abilities/keyword/RenownAbility.java index df811a37cfa..0b93bc9172e 100644 --- a/Mage/src/main/java/mage/abilities/keyword/RenownAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/RenownAbility.java @@ -15,7 +15,6 @@ import mage.game.permanent.Permanent; import mage.util.CardUtil; /** - * * @author LevelX2 */ public class RenownAbility extends TriggeredAbilityImpl { diff --git a/Mage/src/main/java/mage/abilities/keyword/SaddleAbility.java b/Mage/src/main/java/mage/abilities/keyword/SaddleAbility.java index a9b2d74730f..c187c930330 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SaddleAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SaddleAbility.java @@ -20,7 +20,7 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.watchers.common.SaddledMountWatcher; import java.awt.*; @@ -128,7 +128,7 @@ class SaddleCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true) { + Target target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true) { @Override public String getMessage(Game game) { // shows selected power diff --git a/Mage/src/main/java/mage/abilities/keyword/SoulshiftAbility.java b/Mage/src/main/java/mage/abilities/keyword/SoulshiftAbility.java index c1b08e6947e..6a4eb980ccd 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SoulshiftAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SoulshiftAbility.java @@ -2,19 +2,15 @@ package mage.abilities.keyword; -import mage.constants.ComparisonType; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.constants.ComparisonType; import mage.constants.SubType; import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.ManaValuePredicate; -import mage.game.Game; -import mage.game.events.GameEvent; import mage.target.common.TargetCardInYourGraveyard; - -import java.util.UUID; +import mage.target.targetadjustment.ManaValueTargetAdjuster; /** * 702.45. Soulshift @@ -38,6 +34,10 @@ public class SoulshiftAbility extends DiesSourceTriggeredAbility { public SoulshiftAbility(DynamicValue amount) { super(new ReturnToHandTargetEffect()); this.amount = amount; + FilterCard filter = new FilterCard("Spirit card from your graveyard"); + filter.add(SubType.SPIRIT.getPredicate()); + this.addTarget(new TargetCardInYourGraveyard(filter)); + this.setTargetAdjuster(new ManaValueTargetAdjuster(amount, ComparisonType.OR_LESS)); } protected SoulshiftAbility(final SoulshiftAbility ability) { @@ -45,17 +45,6 @@ public class SoulshiftAbility extends DiesSourceTriggeredAbility { this.amount = ability.amount; } - @Override - public void trigger(Game game, UUID controllerId, GameEvent triggeringEvent) { - this.getTargets().clear(); - int intValue = amount.calculate(game, this, null); - FilterCard filter = new FilterCard("Spirit card with mana value " + intValue + " or less from your graveyard"); - filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, intValue + 1)); - filter.add(SubType.SPIRIT.getPredicate()); - this.addTarget(new TargetCardInYourGraveyard(filter)); - super.trigger(game, controllerId, triggeringEvent); - } - @Override public SoulshiftAbility copy() { return new SoulshiftAbility(this); diff --git a/Mage/src/main/java/mage/abilities/keyword/StationAbility.java b/Mage/src/main/java/mage/abilities/keyword/StationAbility.java new file mode 100644 index 00000000000..b824e0e6f9c --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/StationAbility.java @@ -0,0 +1,74 @@ +package mage.abilities.keyword; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.List; +import java.util.Optional; + +/** + * @author TheElk801 + */ +public class StationAbility extends SimpleActivatedAbility { + + public StationAbility() { + super(Zone.BATTLEFIELD, new StationAbilityEffect(), new TapTargetCost(StaticFilters.FILTER_OTHER_CONTROLLED_CREATURE)); + } + + private StationAbility(final StationAbility ability) { + super(ability); + } + + @Override + public StationAbility copy() { + return new StationAbility(this); + } + + @Override + public String getRule() { + return "station (Tap another creature you control: Put charge counters equal to its power on {this}. Station only as a sorcery.)"; + } +} + +class StationAbilityEffect extends OneShotEffect { + + StationAbilityEffect() { + super(Outcome.Benefit); + } + + private StationAbilityEffect(final StationAbilityEffect effect) { + super(effect); + } + + @Override + public StationAbilityEffect copy() { + return new StationAbilityEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null) { + return false; + } + int power = Optional + .ofNullable((List) getValue("tappedPermanents")) + .map(permanents -> permanents + .stream() + .map(MageObject::getPower) + .mapToInt(MageInt::getValue) + .sum()) + .orElse(0); + return power > 0 && permanent.addCounters(CounterType.CHARGE.createInstance(power), source, game); + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/StationLevelAbility.java b/Mage/src/main/java/mage/abilities/keyword/StationLevelAbility.java new file mode 100644 index 00000000000..69adb98abd0 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/StationLevelAbility.java @@ -0,0 +1,159 @@ +package mage.abilities.keyword; + +import mage.abilities.Ability; +import mage.abilities.StaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.constants.*; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.util.CardUtil; + +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public class StationLevelAbility extends StaticAbility { + + private final int level; + + public StationLevelAbility(int level) { + super(Zone.BATTLEFIELD, null); + this.level = level; + } + + private StationLevelAbility(final StationLevelAbility ability) { + super(ability); + this.level = ability.level; + } + + @Override + public StationLevelAbility copy() { + return new StationLevelAbility(this); + } + + public StationLevelAbility withLevelAbility(Ability ability) { + this.addEffect(new StationLevelAbilityEffect(ability, level)); + return this; + } + + public StationLevelAbility withPT(int power, int toughness) { + this.addEffect(new StationLevelCreatureEffect(power, toughness, level)); + return this; + } + + @Override + public String getRule() { + return "STATION " + level + "+" + this + .getEffects() + .stream() + .map(effect -> effect.getText(this.getModes().getMode())) + .map(CardUtil::getTextWithFirstCharUpperCase) + .collect(Collectors.joining("
")); + } + + public boolean hasPT() { + return this.getEffects().stream().anyMatch(StationLevelCreatureEffect.class::isInstance); + } +} + +class StationLevelAbilityEffect extends ContinuousEffectImpl { + + private final Ability ability; + private final int level; + + StationLevelAbilityEffect(Ability ability, int level) { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + this.ability = ability; + this.level = level; + this.ability.setRuleVisible(false); + this.staticText = ability.getRule(); + } + + private StationLevelAbilityEffect(final StationLevelAbilityEffect effect) { + super(effect); + this.ability = effect.ability; + this.level = effect.level; + } + + @Override + public StationLevelAbilityEffect copy() { + return new StationLevelAbilityEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null || permanent.getCounters(game).getCount(CounterType.CHARGE) < level) { + return false; + } + permanent.addAbility(ability, source.getSourceId(), game); + return true; + } +} + +class StationLevelCreatureEffect extends ContinuousEffectImpl { + + private final int power; + private final int toughness; + private final int level; + + StationLevelCreatureEffect(int power, int toughness, int level) { + super(Duration.WhileOnBattlefield, Outcome.BecomeCreature); + this.power = power; + this.toughness = toughness; + this.level = level; + staticText = power + "/" + toughness; + } + + private StationLevelCreatureEffect(final StationLevelCreatureEffect effect) { + super(effect); + this.power = effect.power; + this.toughness = effect.toughness; + this.level = effect.level; + } + + @Override + public StationLevelCreatureEffect copy() { + return new StationLevelCreatureEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null || permanent.getCounters(game).getCount(CounterType.CHARGE) < level) { + return false; + } + switch (layer) { + case TypeChangingEffects_4: + permanent.addCardType(game, CardType.ARTIFACT, CardType.CREATURE); + return true; + case PTChangingEffects_7: + if (sublayer != SubLayer.SetPT_7b) { + return false; + } + permanent.getPower().setModifiedBaseValue(power); + permanent.getToughness().setModifiedBaseValue(toughness); + return true; + default: + return false; + } + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + switch (layer) { + case TypeChangingEffects_4: + case PTChangingEffects_7: + return true; + default: + return false; + } + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/SupportAbility.java b/Mage/src/main/java/mage/abilities/keyword/SupportAbility.java index 79b84114d31..295c8477c83 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SupportAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SupportAbility.java @@ -1,12 +1,13 @@ - package mage.abilities.keyword; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.keyword.SupportEffect; import mage.cards.Card; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; /** * 701.32. Support @@ -19,19 +20,25 @@ import mage.target.common.TargetCreaturePermanent; */ public class SupportAbility extends EntersBattlefieldTriggeredAbility { + private static final FilterPermanent filter = new FilterCreaturePermanent("other target creatures"); + + static { + filter.add(AnotherPredicate.instance); + } + /* * For enchantments, the text should not include the word "other". * The otherPermanent choice removes the word "other" from rule text creation. */ public SupportAbility(Card card, int amount, boolean otherPermanent) { super(new SupportEffect(card, amount, otherPermanent)); - if (!card.isInstantOrSorcery()) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures"); - if (card.isCreature()) { - filter.add(AnotherPredicate.instance); - filter.setMessage("other target creatures"); - } - addTarget(new TargetCreaturePermanent(0, amount, filter, false)); + if (card.isInstantOrSorcery()) { + return; + } + if (!card.isCreature()) { + addTarget(new TargetPermanent(0, amount, StaticFilters.FILTER_PERMANENT_CREATURES)); + } else { + addTarget(new TargetPermanent(0, amount, filter)); } } diff --git a/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java b/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java index 86b584fddf3..f69518cf516 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java @@ -10,7 +10,6 @@ import mage.abilities.costs.VariableCostType; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.VariableManaCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; @@ -147,7 +146,7 @@ public class SuspendAbility extends SpecialAction { if (card.getManaCost().isEmpty()) { setRuleAtTheTop(true); } - addSubAbility(new SuspendBeginningOfUpkeepInterveningIfTriggeredAbility()); + addSubAbility(new SuspendUpkeepAbility()); addSubAbility(new SuspendPlayCardAbility()); } else { ruleText = "Suspend"; @@ -188,8 +187,7 @@ public class SuspendAbility extends SpecialAction { ability.setControllerId(card.getOwnerId()); game.getState().addOtherAbility(card, ability); - SuspendBeginningOfUpkeepInterveningIfTriggeredAbility ability1 - = new SuspendBeginningOfUpkeepInterveningIfTriggeredAbility(); + SuspendUpkeepAbility ability1 = new SuspendUpkeepAbility(); ability1.setSourceId(card.getId()); ability1.setControllerId(card.getOwnerId()); game.getState().addOtherAbility(card, ability1); @@ -434,23 +432,20 @@ class GainHasteEffect extends ContinuousEffectImpl { } -class SuspendBeginningOfUpkeepInterveningIfTriggeredAbility extends ConditionalInterveningIfTriggeredAbility { +class SuspendUpkeepAbility extends BeginningOfUpkeepTriggeredAbility { - SuspendBeginningOfUpkeepInterveningIfTriggeredAbility() { - super(new BeginningOfUpkeepTriggeredAbility(Zone.EXILED, TargetController.YOU, new RemoveCounterSourceEffect(CounterType.TIME.createInstance()), - false), - SuspendedCondition.instance, - "At the beginning of your upkeep, if {this} is suspended, remove a time counter from it."); + SuspendUpkeepAbility() { + super(Zone.EXILED, TargetController.YOU, new RemoveCounterSourceEffect(CounterType.TIME.createInstance()).setText("remove a time counter from it"), false); + this.withInterveningIf(SuspendedCondition.instance); this.setRuleVisible(false); - } - private SuspendBeginningOfUpkeepInterveningIfTriggeredAbility(final SuspendBeginningOfUpkeepInterveningIfTriggeredAbility effect) { + private SuspendUpkeepAbility(final SuspendUpkeepAbility effect) { super(effect); } @Override - public SuspendBeginningOfUpkeepInterveningIfTriggeredAbility copy() { - return new SuspendBeginningOfUpkeepInterveningIfTriggeredAbility(this); + public SuspendUpkeepAbility copy() { + return new SuspendUpkeepAbility(this); } } diff --git a/Mage/src/main/java/mage/abilities/keyword/VanishingAbility.java b/Mage/src/main/java/mage/abilities/keyword/VanishingAbility.java index d414fce5881..1a726422c35 100644 --- a/Mage/src/main/java/mage/abilities/keyword/VanishingAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/VanishingAbility.java @@ -1,14 +1,13 @@ package mage.abilities.keyword; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceHasCounterCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; @@ -27,12 +26,10 @@ public class VanishingAbility extends EntersBattlefieldAbility { public VanishingAbility(int amount) { super(new AddCountersSourceEffect(CounterType.TIME.createInstance(amount))); this.amount = amount; - this.addSubAbility(new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility( - new RemoveCounterSourceEffect(CounterType.TIME.createInstance()), false - ), condition, "At the beginning of your upkeep, if this permanent " + - "has a time counter on it, remove a time counter from it." - ).setRuleVisible(false)); + this.addSubAbility(new BeginningOfUpkeepTriggeredAbility( + new RemoveCounterSourceEffect(CounterType.TIME.createInstance()) + .setText("remove a time counter from it"), false + ).withInterveningIf(condition).setRuleVisible(false)); this.addSubAbility(new VanishingTriggeredAbility()); } diff --git a/Mage/src/main/java/mage/abilities/keyword/WardAbility.java b/Mage/src/main/java/mage/abilities/keyword/WardAbility.java index 01db3372ce5..1a064c0a65c 100644 --- a/Mage/src/main/java/mage/abilities/keyword/WardAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/WardAbility.java @@ -77,7 +77,7 @@ public class WardAbility extends TriggeredAbilityImpl { if (!getSourceId().equals(event.getTargetId())) { return false; } - StackObject targetingObject = CardUtil.findTargetingStackObject(this.getId().toString(), event, game); + StackObject targetingObject = game.findTargetingStackObject(this.getId().toString(), event); if (targetingObject == null || !game.getOpponents(getControllerId()).contains(targetingObject.getControllerId())) { return false; } diff --git a/Mage/src/main/java/mage/abilities/keyword/WarpAbility.java b/Mage/src/main/java/mage/abilities/keyword/WarpAbility.java new file mode 100644 index 00000000000..3e4cc681e0c --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/WarpAbility.java @@ -0,0 +1,51 @@ +package mage.abilities.keyword; + +import mage.abilities.SpellAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.cards.Card; +import mage.constants.SpellAbilityType; +import mage.constants.TimingRule; + +/** + * @author TheElk801 + */ +public class WarpAbility extends SpellAbility { + + public static final String WARP_ACTIVATION_VALUE_KEY = "warpActivation"; + + public WarpAbility(Card card, String manaString) { + super(new ManaCostsImpl<>(manaString), card.getName() + " with Warp"); + this.spellAbilityType = SpellAbilityType.BASE_ALTERNATE; + this.setAdditionalCostsRuleVisible(false); + this.timing = TimingRule.SORCERY; + } + + private WarpAbility(final WarpAbility ability) { + super(ability); + } + + @Override + public WarpAbility copy() { + return new WarpAbility(this); + } + + @Override + public String getRule() { + StringBuilder sb = new StringBuilder("Warp"); + if (getCosts().isEmpty()) { + sb.append(' '); + } else { + sb.append("—"); + } + sb.append(getManaCosts().getText()); + if (!getCosts().isEmpty()) { + sb.append(", "); + sb.append(getCosts().getText()); + sb.append('.'); + } + sb.append(" (You may cast this card from your hand for its warp cost. "); + sb.append("Exile this creature at the beginning of the next end step, "); + sb.append("then you may cast it from exile on a later turn.)"); + return sb.toString(); + } +} diff --git a/Mage/src/main/java/mage/cards/CardImpl.java b/Mage/src/main/java/mage/cards/CardImpl.java index 2edbf43c918..90acef7ccce 100644 --- a/Mage/src/main/java/mage/cards/CardImpl.java +++ b/Mage/src/main/java/mage/cards/CardImpl.java @@ -918,27 +918,41 @@ public abstract class CardImpl extends MageObjectImpl implements Card { @Override public boolean cantBeAttachedBy(MageObject attachment, Ability source, Game game, boolean silentMode) { + boolean canAttach = true; for (ProtectionAbility ability : this.getAbilities(game).getProtectionAbilities()) { if ((!attachment.hasSubtype(SubType.AURA, game) || ability.removesAuras()) && (!attachment.hasSubtype(SubType.EQUIPMENT, game) || ability.removesEquipment()) && !attachment.getId().equals(ability.getAuraIdNotToBeRemoved()) && !ability.canTarget(attachment, game)) { - return !ability.getDoesntRemoveControlled() || Objects.equals(getControllerOrOwnerId(), game.getControllerId(attachment.getId())); + canAttach &= ability.getDoesntRemoveControlled() && Objects.equals(getControllerOrOwnerId(), game.getControllerId(attachment.getId())); } } - boolean canAttach = true; - Permanent attachmentPermanent = game.getPermanent(attachment.getId()); // If attachment is an aura, ensures this permanent can still be legally enchanted, according to the enchantment's Enchant ability - if (attachment.hasSubtype(SubType.AURA, game) - && attachmentPermanent != null - && attachmentPermanent.getSpellAbility() != null - && !attachmentPermanent.getSpellAbility().getTargets().isEmpty()) { - // Line of code below functionally gets the target of the aura's Enchant ability, then compares to this permanent. Enchant improperly implemented in XMage, see #9583 - // Note: stillLegalTarget used exclusively to account for Dream Leash. Can be made canTarget in the event that that card is rewritten (and "stillLegalTarget" removed from TargetImpl). - canAttach = attachmentPermanent.getSpellAbility().getTargets().get(0).copy().withNotTarget(true).stillLegalTarget(attachmentPermanent.getControllerId(), this.getId(), source, game); + if (attachment.hasSubtype(SubType.AURA, game)) { + SpellAbility spellAbility = null; + UUID controller = null; + Permanent attachmentPermanent = game.getPermanent(attachment.getId()); + if (attachmentPermanent != null) { + spellAbility = attachmentPermanent.getSpellAbility(); // Permanent's SpellAbility might be modified, so if possible use that one + controller = attachmentPermanent.getControllerId(); + } else { // Used for checking if it can be attached from the graveyard, such as Unfinished Business + Card attachmentCard = game.getCard(attachment.getId()); + if (attachmentCard != null) { + spellAbility = attachmentCard.getSpellAbility(); + if (source != null) { + controller = source.getControllerId(); + } else { + controller = attachmentCard.getControllerOrOwnerId(); + } + } + } + if (controller != null && spellAbility != null && !spellAbility.getTargets().isEmpty()){ + // Line of code below functionally gets the target of the aura's Enchant ability, then compares to this permanent. Enchant improperly implemented in XMage, see #9583 + // Note: stillLegalTarget used exclusively to account for Dream Leash. Can be made canTarget in the event that that card is rewritten (and "stillLegalTarget" removed from TargetImpl). + canAttach &= spellAbility.getTargets().get(0).copy().withNotTarget(true).stillLegalTarget(controller, this.getId(), source, game); + } } - return !canAttach || game.getContinuousEffects().preventedByRuleModification(new StayAttachedEvent(this.getId(), attachment.getId(), source), null, game, silentMode); } diff --git a/Mage/src/main/java/mage/cards/CardWithSpellOption.java b/Mage/src/main/java/mage/cards/CardWithSpellOption.java index b1470f7dedc..ed177daa1ec 100644 --- a/Mage/src/main/java/mage/cards/CardWithSpellOption.java +++ b/Mage/src/main/java/mage/cards/CardWithSpellOption.java @@ -26,6 +26,7 @@ public abstract class CardWithSpellOption extends CardImpl { public CardWithSpellOption(CardWithSpellOption card) { super(card); + // make sure all parts created and parent ref added this.spellCard = card.getSpellCard().copy(); this.spellCard.setParentCard(this); } diff --git a/Mage/src/main/java/mage/cards/ModalDoubleFacedCard.java b/Mage/src/main/java/mage/cards/ModalDoubleFacedCard.java index eb8f3fcd19f..eccfab302f2 100644 --- a/Mage/src/main/java/mage/cards/ModalDoubleFacedCard.java +++ b/Mage/src/main/java/mage/cards/ModalDoubleFacedCard.java @@ -62,6 +62,7 @@ public abstract class ModalDoubleFacedCard extends CardImpl implements CardWithH public ModalDoubleFacedCard(ModalDoubleFacedCard card) { super(card); + // make sure all parts created and parent ref added this.leftHalfCard = card.getLeftHalfCard().copy(); ((ModalDoubleFacedCardHalf) leftHalfCard).setParentCard(this); this.rightHalfCard = card.rightHalfCard.copy(); diff --git a/Mage/src/main/java/mage/cards/SplitCard.java b/Mage/src/main/java/mage/cards/SplitCard.java index aafccf957b2..7595febd85b 100644 --- a/Mage/src/main/java/mage/cards/SplitCard.java +++ b/Mage/src/main/java/mage/cards/SplitCard.java @@ -38,6 +38,7 @@ public abstract class SplitCard extends CardImpl implements CardWithHalves { protected SplitCard(SplitCard card) { super(card); + // make sure all parts created and parent ref added this.leftHalfCard = card.getLeftHalfCard().copy(); ((SplitCardHalf) leftHalfCard).setParentCard(this); this.rightHalfCard = card.rightHalfCard.copy(); diff --git a/Mage/src/main/java/mage/cards/repository/TokenRepository.java b/Mage/src/main/java/mage/cards/repository/TokenRepository.java index a3a86c78c9e..75ff94d16bf 100644 --- a/Mage/src/main/java/mage/cards/repository/TokenRepository.java +++ b/Mage/src/main/java/mage/cards/repository/TokenRepository.java @@ -264,10 +264,19 @@ public enum TokenRepository { res.add(createXmageToken(XMAGE_IMAGE_NAME_COPY, 4, "https://api.scryfall.com/cards/tznr/12/en?format=image")); res.add(createXmageToken(XMAGE_IMAGE_NAME_COPY, 5, "https://api.scryfall.com/cards/twho/1/en?format=image")); res.add(createXmageToken(XMAGE_IMAGE_NAME_COPY, 6, "https://api.scryfall.com/cards/tlci/1/en?format=image")); + res.add(createXmageToken(XMAGE_IMAGE_NAME_COPY, 7, "https://api.scryfall.com/cards/tfin/1/en?format=image")); + res.add(createXmageToken(XMAGE_IMAGE_NAME_COPY, 8, "https://api.scryfall.com/cards/ttdm/1/en?format=image")); + res.add(createXmageToken(XMAGE_IMAGE_NAME_COPY, 9, "https://api.scryfall.com/cards/totj/1/en?format=image")); + res.add(createXmageToken(XMAGE_IMAGE_NAME_COPY, 10, "https://api.scryfall.com/cards/tdsk/1/en?format=image")); + res.add(createXmageToken(XMAGE_IMAGE_NAME_COPY, 11, "https://api.scryfall.com/cards/tacr/1/en?format=image")); + res.add(createXmageToken(XMAGE_IMAGE_NAME_COPY, 12, "https://api.scryfall.com/cards/tpip/1/en?format=image")); // City's Blessing // https://scryfall.com/search?q=type%3Atoken+include%3Aextras+unique%3Aprints+City%27s+Blessing+&unique=cards&as=grid&order=name + // https://scryfall.com/search?as=grid&order=released&q=oracleid%3A73d60ab9-1c38-4592-a5b5-ab84788bcc84+include%3Aextras&unique=prints res.add(createXmageToken(XMAGE_IMAGE_NAME_CITY_BLESSING, 1, "https://api.scryfall.com/cards/f18/2/en?format=image")); + res.add(createXmageToken(XMAGE_IMAGE_NAME_CITY_BLESSING, 2, "https://api.scryfall.com/cards/tlcc/17/en?format=image")); + res.add(createXmageToken(XMAGE_IMAGE_NAME_CITY_BLESSING, 3, "https://api.scryfall.com/cards/tmkc/28/en?format=image")); // Day // Night // https://scryfall.com/search?q=include%3Aextras+unique%3Aprints+%22Day+%2F%2F+Night%22&unique=cards&as=grid&order=name @@ -280,6 +289,7 @@ public enum TokenRepository { res.add(createXmageToken(XMAGE_IMAGE_NAME_FACE_DOWN_MANIFEST, 2, "https://api.scryfall.com/cards/tc18/1/en?format=image")); res.add(createXmageToken(XMAGE_IMAGE_NAME_FACE_DOWN_MANIFEST, 3, "https://api.scryfall.com/cards/tfrf/4/en?format=image")); res.add(createXmageToken(XMAGE_IMAGE_NAME_FACE_DOWN_MANIFEST, 4, "https://api.scryfall.com/cards/tncc/3/en?format=image")); + res.add(createXmageToken(XMAGE_IMAGE_NAME_FACE_DOWN_MANIFEST, 5, "https://api.scryfall.com/cards/tdsk/18/en?format=image")); // Morph and Megamorph // https://scryfall.com/search?q=Morph+unique%3Aprints+otag%3Aassistant-cards&unique=cards&as=grid&order=name @@ -298,12 +308,14 @@ public enum TokenRepository { // Foretell // https://scryfall.com/search?q=Foretell+unique%3Aprints+otag%3Aassistant-cards&unique=cards&as=grid&order=name res.add(createXmageToken(XMAGE_IMAGE_NAME_FACE_DOWN_FORETELL, 1, "https://api.scryfall.com/cards/tkhm/23/en?format=image")); + res.add(createXmageToken(XMAGE_IMAGE_NAME_FACE_DOWN_FORETELL, 2, "https://api.scryfall.com/cards/tfic/10/en?format=image")); // The Monarch // https://scryfall.com/search?q=Monarch+unique%3Aprints+otag%3Aassistant-cards&unique=cards&as=grid&order=name res.add(createXmageToken(XMAGE_IMAGE_NAME_THE_MONARCH, 1, "https://api.scryfall.com/cards/tonc/22/en?format=image")); res.add(createXmageToken(XMAGE_IMAGE_NAME_THE_MONARCH, 2, "https://api.scryfall.com/cards/tcn2/1/en?format=image")); res.add(createXmageToken(XMAGE_IMAGE_NAME_THE_MONARCH, 3, "https://api.scryfall.com/cards/tltc/15/en?format=image")); + res.add(createXmageToken(XMAGE_IMAGE_NAME_THE_MONARCH, 4, "https://api.scryfall.com/cards/tfic/11/en?format=image")); // Radiation (for trigger) res.add(createXmageToken(XMAGE_IMAGE_NAME_RADIATION, 1, "https://api.scryfall.com/cards/tpip/22/en?format=image")); diff --git a/Mage/src/main/java/mage/choices/Choice.java b/Mage/src/main/java/mage/choices/Choice.java index c99d11df9e6..e4538b198e6 100644 --- a/Mage/src/main/java/mage/choices/Choice.java +++ b/Mage/src/main/java/mage/choices/Choice.java @@ -44,6 +44,9 @@ public interface Choice extends Serializable, Copyable { ChoiceHintType getHintType(); + /** + * For AI, mana auto-payment from choose color dialogs + */ boolean isManaColorChoice(); Choice setManaColorChoice(boolean manaColorChoice); diff --git a/Mage/src/main/java/mage/collectors/DataCollector.java b/Mage/src/main/java/mage/collectors/DataCollector.java new file mode 100644 index 00000000000..db3471a4acd --- /dev/null +++ b/Mage/src/main/java/mage/collectors/DataCollector.java @@ -0,0 +1,68 @@ +package mage.collectors; + +import mage.game.Game; +import mage.game.Table; + +import java.util.UUID; + +/** + * Data collection for better debugging. Can collect server/table/game events and process related data. + *

+ * Supported features: + * - [x] collect and print game logs in server output, including unit tests + * - [x] collect and save full games history and decks + * - [ ] collect and print performance metrics like ApplyEffects calc time or inform players time (pings) + * - [ ] collect and send metrics to third party tools like prometheus + grafana + * - [ ] prepare "attachable" game data for bug reports + * - [ ] record game replays data (GameView history) + *

+ * How-to enable or disable: + * - use java params like -Dxmage.dataCollectors.saveGameHistory=true + *

+ * How-to add new service: + * - create new class and extends EmptyDataCollector + * - each service must use unique service code + * - override only needed events + * - modify DataCollectorServices.init with new class + * - make sure it's fast and never raise errors + * + * @author JayDi85 + */ +public interface DataCollector { + + /** + * Return unique service code to enable by command line + */ + String getServiceCode(); + + /** + * Show some hints on service enabled, e.g. root folder path + */ + String getInitInfo(); + + void onServerStart(); + + void onTableStart(Table table); + + void onTableEnd(Table table); + + void onGameStart(Game game); + + void onGameLog(Game game, String message); + + void onGameEnd(Game game); + + /** + * @param userName can be null for system messages + */ + void onChatRoom(UUID roomId, String userName, String message); + + void onChatTourney(UUID tourneyId, String userName, String message); + + void onChatTable(UUID tableId, String userName, String message); + + /** + * @param gameId chat sessings don't have full game access, so use onGameStart event to find game's ID before chat + */ + void onChatGame(UUID gameId, String userName, String message); +} diff --git a/Mage/src/main/java/mage/collectors/DataCollectorServices.java b/Mage/src/main/java/mage/collectors/DataCollectorServices.java new file mode 100644 index 00000000000..dc2740f078a --- /dev/null +++ b/Mage/src/main/java/mage/collectors/DataCollectorServices.java @@ -0,0 +1,143 @@ +package mage.collectors; + +import mage.collectors.services.PrintGameLogsDataCollector; +import mage.collectors.services.SaveGameHistoryDataCollector; +import mage.game.Game; +import mage.game.Table; +import org.apache.log4j.Logger; + +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.UUID; + +/** + * Not a real data collector. It's a global service to inject and collect data all around the code. + * + * @author JayDi85 + */ +final public class DataCollectorServices implements DataCollector { + + // usage example: -Dxmage.dataCollectors.saveGameHistory=true + private static final String COMMAND_LINE_DATA_COLLECTORS_PREFIX = "xmage.dataCollectors."; + + private static final Logger logger = Logger.getLogger(DataCollectorServices.class); + + private static DataCollectorServices instance = null; + + // fill on server startup, so it's thread safe + Set allServices = new LinkedHashSet<>(); + Set activeServices = new LinkedHashSet<>(); + + public static DataCollectorServices getInstance() { + if (instance == null) { + instance = new DataCollectorServices(); + } + return instance; + } + + /** + * Init data service on server's startup + * + * @param enablePrintGameLogs use for unit tests to enable additional logs for better debugging + * @param enableSaveGameHistory use to save full game history with logs, decks, etc + */ + public static void init(boolean enablePrintGameLogs, boolean enableSaveGameHistory) { + if (instance != null) { + // unit tests: init on first test run, all other will use same process + // real server: init on server startup + return; + } + + // fill all possible services + getInstance().allServices.add(new PrintGameLogsDataCollector()); + getInstance().allServices.add(new SaveGameHistoryDataCollector()); + logger.info(String.format("Data collectors: found %d services", getInstance().allServices.size())); + + // enable only needed + getInstance().allServices.forEach(service -> { + boolean isDefault = false; + isDefault |= enablePrintGameLogs && service.getServiceCode().equals(PrintGameLogsDataCollector.SERVICE_CODE); + isDefault |= enableSaveGameHistory && service.getServiceCode().equals(SaveGameHistoryDataCollector.SERVICE_CODE); + boolean isEnable = isServiceEnable(service.getServiceCode(), isDefault); + if (isEnable) { + getInstance().activeServices.add(service); + } + String info = isEnable ? String.format(" (%s)", service.getInitInfo()) : ""; + logger.info(String.format("Data collectors: %s - %s%s", service.getServiceCode(), isEnable ? "enabled" : "disabled", info)); + }); + } + + private static boolean isServiceEnable(String dataCollectorCode, boolean isEnableByDefault) { + String needCommand = COMMAND_LINE_DATA_COLLECTORS_PREFIX + dataCollectorCode; + boolean isEnable; + if (System.getProperty(needCommand) != null) { + isEnable = System.getProperty(needCommand, "false").equals("true"); + } else { + isEnable = isEnableByDefault; + } + return isEnable; + } + + @Override + public String getServiceCode() { + throw new IllegalStateException("Wrong code usage. Use it by static methods only"); + } + + @Override + public String getInitInfo() { + throw new IllegalStateException("Wrong code usage. Use it by static methods only"); + } + + @Override + public void onServerStart() { + activeServices.forEach(DataCollector::onServerStart); + } + + @Override + public void onTableStart(Table table) { + activeServices.forEach(c -> c.onTableStart(table)); + } + + @Override + public void onTableEnd(Table table) { + activeServices.forEach(c -> c.onTableEnd(table)); + } + + @Override + public void onGameStart(Game game) { + if (game.isSimulation()) return; + activeServices.forEach(c -> c.onGameStart(game)); + } + + @Override + public void onGameLog(Game game, String message) { + if (game.isSimulation()) return; + activeServices.forEach(c -> c.onGameLog(game, message)); + } + + @Override + public void onGameEnd(Game game) { + if (game.isSimulation()) return; + activeServices.forEach(c -> c.onGameEnd(game)); + } + + @Override + public void onChatRoom(UUID roomId, String userName, String message) { + activeServices.forEach(c -> c.onChatRoom(roomId, userName, message)); + } + + @Override + public void onChatTourney(UUID tourneyId, String userName, String message) { + activeServices.forEach(c -> c.onChatTourney(tourneyId, userName, message)); + } + + @Override + public void onChatTable(UUID tableId, String userName, String message) { + activeServices.forEach(c -> c.onChatTable(tableId, userName, message)); + } + + @Override + public void onChatGame(UUID gameId, String userName, String message) { + activeServices.forEach(c -> c.onChatGame(gameId, userName, message)); + } +} diff --git a/Mage/src/main/java/mage/collectors/services/EmptyDataCollector.java b/Mage/src/main/java/mage/collectors/services/EmptyDataCollector.java new file mode 100644 index 00000000000..2e5f1793e81 --- /dev/null +++ b/Mage/src/main/java/mage/collectors/services/EmptyDataCollector.java @@ -0,0 +1,70 @@ +package mage.collectors.services; + +import mage.collectors.DataCollector; +import mage.game.Game; +import mage.game.Table; + +import java.util.UUID; + +/** + * Base implementation of Data Collector, do nothing. Use it to implement own or simple collectors, e.g. chats only collectors + * + * @author JayDi85 + */ +public abstract class EmptyDataCollector implements DataCollector { + + @Override + public String getInitInfo() { + return ""; + } + + @Override + public void onServerStart() { + // nothing + } + + @Override + public void onTableStart(Table table) { + // nothing + } + + @Override + public void onTableEnd(Table table) { + // nothing + } + + @Override + public void onGameStart(Game game) { + // nothing + } + + @Override + public void onGameLog(Game game, String message) { + // nothing + } + + @Override + public void onGameEnd(Game game) { + // nothing + } + + @Override + public void onChatRoom(UUID roomId, String userName, String message) { + // nothing + } + + @Override + public void onChatTourney(UUID tourneyId, String userName, String message) { + // nothing + } + + @Override + public void onChatTable(UUID tableId, String userName, String message) { + // nothing + } + + @Override + public void onChatGame(UUID gameId, String userName, String message) { + // nothing + } +} diff --git a/Mage/src/main/java/mage/collectors/services/PrintGameLogsDataCollector.java b/Mage/src/main/java/mage/collectors/services/PrintGameLogsDataCollector.java new file mode 100644 index 00000000000..f8fc9a8966a --- /dev/null +++ b/Mage/src/main/java/mage/collectors/services/PrintGameLogsDataCollector.java @@ -0,0 +1,48 @@ +package mage.collectors.services; + +import mage.game.Game; +import mage.util.CardUtil; +import org.apache.log4j.Logger; +import org.jsoup.Jsoup; + +/** + * Data collector to print game logs in console output. Used for better unit tests debugging. + * + * @author JayDi85 + */ +public class PrintGameLogsDataCollector extends EmptyDataCollector { + + private static final Logger logger = Logger.getLogger(PrintGameLogsDataCollector.class); + public static final String SERVICE_CODE = "printGameLogs"; + + private void writeLog(String message) { + logger.info(message); + } + + private void writeLog(String category, String event, String details) { + writeLog(String.format("[%s][%s] %s", + category, + event, + details + )); + } + + @Override + public String getServiceCode() { + return SERVICE_CODE; + } + + @Override + public String getInitInfo() { + return "print game logs in server logs"; + } + + @Override + public void onGameLog(Game game, String message) { + String needMessage = Jsoup.parse(message).text(); + writeLog("GAME", "LOG", String.format("%s: %s", + CardUtil.getTurnInfo(game), + needMessage + )); + } +} diff --git a/Mage/src/main/java/mage/collectors/services/SaveGameHistoryDataCollector.java b/Mage/src/main/java/mage/collectors/services/SaveGameHistoryDataCollector.java new file mode 100644 index 00000000000..7d6212f0fbf --- /dev/null +++ b/Mage/src/main/java/mage/collectors/services/SaveGameHistoryDataCollector.java @@ -0,0 +1,383 @@ +package mage.collectors.services; + +import mage.cards.decks.DeckFormats; +import mage.constants.TableState; +import mage.game.Game; +import mage.game.Table; +import mage.game.match.MatchPlayer; +import mage.players.Player; +import mage.util.CardUtil; +import org.apache.log4j.Logger; +import org.jsoup.Jsoup; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Stream; + +/** + * Data collector that can collect and save whole games history and store it in disk system. + *

+ * WARNING, it's not production ready yet, use for load tests only (see todos below) + *

+ * Possible use cases: + * - load tests debugging to find freeze AI games; + * - public server debugging to find human freeze games; + * - AI learning data collection; + * - fast access to saved decks for public tourneys, e.g. after draft + * Tasks: + * - TODO: drafts - save picks history per player; + * - TODO: tourneys - fix chat logs + * - TODO: tourneys - fix miss end events on table or server quite (active table/game freeze bug) + *

+ * Data structure example: + * - gamesHistory + * - 2025-07-04 + * - tables_active + * - tables_done + * - table 1 - UUID + * - table_logs.txt + * - games_done + * - games_active + * - game 1 - UUID + * - game 2 - UUID + * - game_logs.html + * - chat_logs.html + * - deck_player_1.dck + * - deck_player_2.dck + * + * @author JayDi85 + */ +public class SaveGameHistoryDataCollector extends EmptyDataCollector { + + private static final Logger logger = Logger.getLogger(SaveGameHistoryDataCollector.class); + public static final String SERVICE_CODE = "saveGameHistory"; + + private static final String DIR_NAME_ROOT = "gamesHistory"; + private static final SimpleDateFormat DIR_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); + private static final String DIR_NAME_TABLES_ACTIVE = "tables_active"; + private static final String DIR_NAME_TABLES_DONE = "tables_done"; + private static final String DIR_NAME_GAMES_ACTIVE = "games_active"; + private static final String DIR_NAME_GAMES_DONE = "games_done"; + + private static final String TABLE_LOGS_FILE_NAME = "table_logs.txt"; + private static final String TABLE_CHAT_FILE_NAME = "table_chat.txt"; + private static final String DECK_FILE_NAME_FORMAT = "deck_player_%d.dck"; + private static final String GAME_LOGS_FILE_NAME = "game_logs.html"; + private static final String GAME_CHAT_FILE_NAME = "game_chat.txt"; + + private static final UUID NO_TABLE_ID = UUID.randomUUID(); + private static final String NO_TABLE_NAME = "SINGLE"; // need for unit tests + + // global switch + boolean enabled; + + // prepared dirs for each table or game - if it returns empty string then logs will be disabled, e.g. on too many data + Map tableDirs = new ConcurrentHashMap<>(); + Map gameDirs = new ConcurrentHashMap<>(); + + // all write operations must be done in single thread + // TODO: analyse load tests performance and split locks per table/game + // TODO: limit file sizes for possible game freeze? + ReentrantLock writeLock = new ReentrantLock(); + + public SaveGameHistoryDataCollector() { + // prepare + Path root = Paths.get(DIR_NAME_ROOT); + if (!Files.exists(root)) { + try { + Files.createDirectories(root); + } catch (IOException e) { + logger.error("Can't create root dir, games history data collector will be disabled - " + e, e); + this.enabled = false; + return; + } + } + + this.enabled = true; + } + + @Override + public String getServiceCode() { + return SERVICE_CODE; + } + + @Override + public String getInitInfo() { + return "save all game history to " + Paths.get(DIR_NAME_ROOT, DIR_DATE_FORMAT.format(new Date())).toAbsolutePath(); + } + + @Override + public void onTableStart(Table table) { + if (!this.enabled) return; + writeToTableLogsFile(table, new Date() + " [START] " + table.getId() + ", " + table); + } + + @Override + public void onTableEnd(Table table) { + if (!this.enabled) return; + writeToTableLogsFile(table, new Date() + " [END] " + table.getId() + ", " + table); + + // good end - move all files to done folder and change dir refs for possible game and other logs + writeLock.lock(); + try { + String oldFolder = getOrCreateTableDir(table.getId(), table.getParentTableId(), table.getTableIndex(), false); + if (oldFolder.contains(DIR_NAME_TABLES_ACTIVE)) { + // move files + String newFolder = oldFolder.replace(DIR_NAME_TABLES_ACTIVE, DIR_NAME_TABLES_DONE); + Files.createDirectories(Paths.get(newFolder)); + Files.move(Paths.get(oldFolder), Paths.get(newFolder), StandardCopyOption.REPLACE_EXISTING); + + // update all refs (table and games) + this.tableDirs.put(table.getId(), newFolder); + this.gameDirs.replaceAll((gameId, gameFolder) -> + gameFolder.startsWith(oldFolder) + ? gameFolder.replace(oldFolder, newFolder) + : gameFolder + ); + innerDirDeleteEmptyParent(oldFolder); + } + } catch (IOException e) { + logger.error("Can't move table files to done folder: " + e, e); + } finally { + writeLock.unlock(); + } + } + + @Override + public void onGameStart(Game game) { + if (!this.enabled) return; + writeToGameLogsFile(game, new Date() + " [START] " + game.getId() + ", " + game); + + // save deck files + writeLock.lock(); + try { + String gameDir = getOrCreateGameDir(game, isActive(game)); + if (gameDir.isEmpty()) { + return; + } + int playerNum = 0; + for (Player player : game.getPlayers().values()) { + playerNum++; + MatchPlayer matchPlayer = player.getMatchPlayer(); + if (matchPlayer != null && matchPlayer.getDeck() != null) { + String deckFile = Paths.get(gameDir, String.format(DECK_FILE_NAME_FORMAT, playerNum)).toString(); + DeckFormats.XMAGE.getExporter().writeDeck(deckFile, matchPlayer.getDeckForViewer().prepareCardsOnlyDeck()); + } + } + } catch (IOException e) { + logger.error("Can't write deck file for game " + game.getId() + ": " + e, e); + } finally { + writeLock.unlock(); + } + } + + @Override + public void onGameLog(Game game, String message) { + if (!this.enabled) return; + writeToGameLogsFile(game, new Date() + " [LOG] " + CardUtil.getTurnInfo(game) + ": " + message); + } + + @Override + public void onGameEnd(Game game) { + if (!this.enabled) return; + writeToGameLogsFile(game, new Date() + " [END] " + game.getId() + ", " + game); + + // good end - move game data to done folder + writeLock.lock(); + try { + String oldFolder = getOrCreateGameDir(game, false); + if (oldFolder.contains(DIR_NAME_GAMES_ACTIVE)) { + // move files + String newFolder = oldFolder.replace(DIR_NAME_GAMES_ACTIVE, DIR_NAME_GAMES_DONE); + Files.createDirectories(Paths.get(newFolder)); + Files.move(Paths.get(oldFolder), Paths.get(newFolder), StandardCopyOption.REPLACE_EXISTING); + + // update all refs + this.gameDirs.replaceAll((gameId, gameFolder) -> + gameFolder.startsWith(oldFolder) + ? gameFolder.replace(oldFolder, newFolder) + : gameFolder + ); + innerDirDeleteEmptyParent(oldFolder); + } + } catch (IOException e) { + logger.error("Can't move game files to done folder: " + e, e); + } finally { + writeLock.unlock(); + } + } + + @Override + public void onChatTourney(UUID tourneyId, String userName, String message) { + // TODO: implement? + } + + @Override + public void onChatTable(UUID tableId, String userName, String message) { + if (!this.enabled) return; + String needMessage = Jsoup.parse(message).text(); // convert html to txt format, so users can't break something + writeToTableChatFile(tableId, new Date() + " [CHAT] " + (userName == null ? "system" : userName) + ": " + needMessage); + } + + @Override + public void onChatGame(UUID gameId, String userName, String message) { + if (!this.enabled) return; + String needMessage = Jsoup.parse(message).text(); // convert html to txt format, so users can't break something + writeToGameChatFile(gameId, new Date() + " [CHAT] " + (userName == null ? "system" : userName) + ": " + needMessage); + } + + + private String getOrCreateTableDir(UUID tableId) { + return this.tableDirs.getOrDefault(tableId, ""); + } + + private String getOrCreateTableDir(UUID tableId, UUID parentTableId, Integer tableIndex, boolean isActive) { + // unit tests don't have tables, so write it to custom table + String needName; + UUID needId; + if (tableId == null) { + needId = NO_TABLE_ID; + needName = String.format("table %s", NO_TABLE_NAME); + } else { + needId = tableId; + if (parentTableId == null) { + needName = String.format("table %s - %s", tableIndex, tableId); + } else { + needName = String.format("table %s - %s_%s", tableIndex, parentTableId, tableId); + } + } + + String needDate = DIR_DATE_FORMAT.format(new Date()); + String needStatus = isActive ? DIR_NAME_TABLES_ACTIVE : DIR_NAME_TABLES_DONE; + + String tableDir = Paths.get( + DIR_NAME_ROOT, + needDate, + needStatus, + needName + ).toString(); + + return this.tableDirs.computeIfAbsent(needId, x -> innerDirCreate(tableDir)); + } + + private String getOrCreateGameDir(UUID gameId) { + // some events don't have full game info and must come after real game start + return this.gameDirs.getOrDefault(gameId, ""); + } + + private String getOrCreateGameDir(Game game, boolean isActive) { + AtomicBoolean isNewDir = new AtomicBoolean(false); + String res = this.gameDirs.computeIfAbsent(game.getId(), x -> { + isNewDir.set(true); + // if you find "table 0 - UUID" folders with real server then game logs come before table then + // it's almost impossible and nothing to do with it + String tableDir = getOrCreateTableDir(game.getTableId(), null, 0, true); + if (tableDir.isEmpty()) { + // disabled + return ""; + } + + String needStatus = isActive ? DIR_NAME_GAMES_ACTIVE : DIR_NAME_GAMES_DONE; + String needName = String.format("game %s - %s", game.getGameIndex(), game.getId()); + String gameDir = Paths.get( + tableDir, + needStatus, + needName + ).toString(); + + return innerDirCreate(gameDir); + }); + + // workaround for good background color in html logs + if (isNewDir.get()) { + writeToGameLogsFile(game, ""); + } + + return res; + } + + private String innerDirCreate(String destFileOrDir) { + Path dir = Paths.get(destFileOrDir); + if (!Files.exists(dir)) { + try { + Files.createDirectories(dir); + } catch (IOException ignore) { + return ""; + } + } + return dir.toString(); + } + + private void innerDirDeleteEmptyParent(String dir) throws IOException { + // delete empty parent folder, e.g. after move all games from active to done folder + Path parentPath = Paths.get(dir).getParent(); + if (Files.exists(parentPath) && Files.isDirectory(parentPath)) { + try (Stream entries = Files.list(parentPath)) { + if (!entries.findAny().isPresent()) { + Files.delete(parentPath); + } + } + } + } + + private void writeToTableLogsFile(Table table, String data) { + String tableDir = getOrCreateTableDir(table.getId(), table.getParentTableId(), table.getTableIndex(), isActive(table)); + if (tableDir.isEmpty()) { + return; + } + writeToFile(Paths.get(tableDir, TABLE_LOGS_FILE_NAME).toString(), data, "\n"); + } + + private void writeToTableChatFile(UUID tableId, String data) { + String gameDir = getOrCreateTableDir(tableId); + if (gameDir.isEmpty()) { + return; + } + writeToFile(Paths.get(gameDir, TABLE_CHAT_FILE_NAME).toString(), data, "\n"); + } + + private void writeToGameLogsFile(Game game, String data) { + String gameDir = getOrCreateGameDir(game, isActive(game)); + if (gameDir.isEmpty()) { + return; + } + writeToFile(Paths.get(gameDir, GAME_LOGS_FILE_NAME).toString(), data, "\n
\n"); + } + + private void writeToGameChatFile(UUID gameId, String data) { + String gameDir = getOrCreateGameDir(gameId); + if (gameDir.isEmpty()) { + return; + } + writeToFile(Paths.get(gameDir, GAME_CHAT_FILE_NAME).toString(), data, "\n"); + } + + private void writeToFile(String destFile, String data, String newLine) { + writeLock.lock(); + try { + try { + String newData = newLine + data; + Files.write(Paths.get(destFile), newData.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, StandardOpenOption.APPEND); + } catch (IOException ignore) { + } + } finally { + writeLock.unlock(); + } + } + + private boolean isActive(Table table) { + return !TableState.FINISHED.equals(table.getState()); + } + + private boolean isActive(Game game) { + return game.getState() == null || !game.getState().isGameOver(); + } +} diff --git a/Mage/src/main/java/mage/constants/AbilityWord.java b/Mage/src/main/java/mage/constants/AbilityWord.java index 6e79b03c841..c8044d3c38c 100644 --- a/Mage/src/main/java/mage/constants/AbilityWord.java +++ b/Mage/src/main/java/mage/constants/AbilityWord.java @@ -63,6 +63,7 @@ public enum AbilityWord { THRESHOLD("Threshold"), UNDERGROWTH("Undergrowth"), VALIANT("Valiant"), + VOID("Void"), WILL_OF_THE_COUNCIL("Will of the council"), WILL_OF_THE_PLANESWALKERS("Will of the planeswalkers"); diff --git a/Mage/src/main/java/mage/constants/AffinityType.java b/Mage/src/main/java/mage/constants/AffinityType.java index a49fe5f9bfc..de6fb741683 100644 --- a/Mage/src/main/java/mage/constants/AffinityType.java +++ b/Mage/src/main/java/mage/constants/AffinityType.java @@ -41,6 +41,7 @@ public enum AffinityType { LIZARDS(new FilterControlledPermanent(SubType.LIZARD, "Lizards")), BIRDS(new FilterControlledPermanent(SubType.BIRD, "Birds")), CITIZENS(new FilterControlledPermanent(SubType.CITIZEN, "Citizens")), + SLIVERS(new FilterControlledPermanent(SubType.SLIVER, "Slivers")), TOWNS(new FilterControlledPermanent(SubType.TOWN, "Towns")), GATES(new FilterControlledPermanent(SubType.GATE, "Gates"), GatesYouControlHint.instance), SNOW_LANDS(AffinityFilters.SNOW_LANDS), diff --git a/Mage/src/main/java/mage/constants/Outcome.java b/Mage/src/main/java/mage/constants/Outcome.java index 1f4e4681214..c6bdd119cd2 100644 --- a/Mage/src/main/java/mage/constants/Outcome.java +++ b/Mage/src/main/java/mage/constants/Outcome.java @@ -14,14 +14,14 @@ public enum Outcome { LoseLife(false), ExtraTurn(true), BecomeCreature(true), - PutCreatureInPlay(true), - PutCardInPlay(true), - PutLandInPlay(true), + PutCreatureInPlay(true, true), + PutCardInPlay(true, true), + PutLandInPlay(true, true), GainControl(false), DrawCard(true), Discard(false), Sacrifice(false), - PlayForFree(true), + PlayForFree(true, true), ReturnToHand(false), Exile(false), Protect(true), @@ -46,24 +46,24 @@ public enum Outcome { // AI sorting targets by priorities (own or opponents) and selects most valueable or weakest private final boolean good; - // no different between own or opponent targets (example: copy must choose from all permanents) - private boolean canTargetAll; + // no different between own or opponent targets (example: copy must choose from all permanents, free cast from selected cards, etc) + private boolean anyTargetHasSameValue; Outcome(boolean good) { this.good = good; } - Outcome(boolean good, boolean canTargetAll) { + Outcome(boolean good, boolean anyTargetHasSameValue) { this.good = good; - this.canTargetAll = canTargetAll; + this.anyTargetHasSameValue = anyTargetHasSameValue; } public boolean isGood() { return good; } - public boolean isCanTargetAll() { - return canTargetAll; + public boolean anyTargetHasSameValue() { + return anyTargetHasSameValue; } public static Outcome inverse(Outcome outcome) { diff --git a/Mage/src/main/java/mage/constants/SubType.java b/Mage/src/main/java/mage/constants/SubType.java index b8a14045d1d..fb6b95c5e2c 100644 --- a/Mage/src/main/java/mage/constants/SubType.java +++ b/Mage/src/main/java/mage/constants/SubType.java @@ -31,6 +31,7 @@ public enum SubType { GATE("Gate", SubTypeSet.NonBasicLandType), LAIR("Lair", SubTypeSet.NonBasicLandType), LOCUS("Locus", SubTypeSet.NonBasicLandType), + PLANET("Planet", SubTypeSet.NonBasicLandType), SPHERE("Sphere", SubTypeSet.NonBasicLandType), URZAS("Urza's", SubTypeSet.NonBasicLandType), MINE("Mine", SubTypeSet.NonBasicLandType), @@ -61,8 +62,10 @@ public enum SubType { GOLD("Gold", SubTypeSet.ArtifactType), INCUBATOR("Incubator", SubTypeSet.ArtifactType), JUNK("Junk", SubTypeSet.ArtifactType), + LANDER("Lander", SubTypeSet.ArtifactType), MAP("Map", SubTypeSet.ArtifactType), POWERSTONE("Powerstone", SubTypeSet.ArtifactType), + SPACECRAFT("Spacecraft", SubTypeSet.ArtifactType), TREASURE("Treasure", SubTypeSet.ArtifactType), VEHICLE("Vehicle", SubTypeSet.ArtifactType), // 205.3m : Creatures and kindreds share their lists of subtypes; these subtypes are called creature types. @@ -163,6 +166,7 @@ public enum SubType { DRYAD("Dryad", SubTypeSet.CreatureType), DWARF("Dwarf", SubTypeSet.CreatureType), // E + ECHIDNA("Echidna", SubTypeSet.CreatureType), EFREET("Efreet", SubTypeSet.CreatureType), EGG("Egg", SubTypeSet.CreatureType), ELDER("Elder", SubTypeSet.CreatureType), @@ -185,7 +189,7 @@ public enum SubType { FROG("Frog", SubTypeSet.CreatureType), FUNGUS("Fungus", SubTypeSet.CreatureType), // G - GAMER("Gamer", SubTypeSet.CreatureType, true), // Un-sets + GAMER("Gamer", SubTypeSet.CreatureType), GAMORREAN("Gamorrean", SubTypeSet.CreatureType, true), // Star Wars GAND("Gand", SubTypeSet.CreatureType, true), // Star Wars GARGOYLE("Gargoyle", SubTypeSet.CreatureType), @@ -210,6 +214,7 @@ public enum SubType { HALFLING("Halfling", SubTypeSet.CreatureType), HAMSTER("Hamster", SubTypeSet.CreatureType), HARPY("Harpy", SubTypeSet.CreatureType), + HEDGEHOG("Hedgehog", SubTypeSet.CreatureType), HELLION("Hellion", SubTypeSet.CreatureType), HERO("Hero", SubTypeSet.CreatureType), HIPPO("Hippo", SubTypeSet.CreatureType), @@ -353,7 +358,7 @@ public enum SubType { SAPROLING("Saproling", SubTypeSet.CreatureType), SATYR("Satyr", SubTypeSet.CreatureType), SCARECROW("Scarecrow", SubTypeSet.CreatureType), - SCIENTIST("Scientist", SubTypeSet.CreatureType, true), // Unstable + SCIENTIST("Scientist", SubTypeSet.CreatureType), SCION("Scion", SubTypeSet.CreatureType), SCORPION("Scorpion", SubTypeSet.CreatureType), SCOUT("Scout", SubTypeSet.CreatureType), @@ -424,7 +429,7 @@ public enum SubType { VAMPIRE("Vampire", SubTypeSet.CreatureType), VARMINT("Varmint", SubTypeSet.CreatureType), VEDALKEN("Vedalken", SubTypeSet.CreatureType), - VILLAIN("Villain", SubTypeSet.CreatureType, true), // Unstable + VILLAIN("Villain", SubTypeSet.CreatureType), VOLVER("Volver", SubTypeSet.CreatureType), // W WALL("Wall", SubTypeSet.CreatureType), diff --git a/Mage/src/main/java/mage/filter/StaticFilters.java b/Mage/src/main/java/mage/filter/StaticFilters.java index 201c60fc726..6680018c2fb 100644 --- a/Mage/src/main/java/mage/filter/StaticFilters.java +++ b/Mage/src/main/java/mage/filter/StaticFilters.java @@ -232,6 +232,12 @@ public final class StaticFilters { FILTER_CARD_INSTANT_AND_SORCERY.setLockedFilter(true); } + public static final FilterInstantOrSorceryCard FILTER_CARDS_INSTANT_AND_SORCERY = new FilterInstantOrSorceryCard("instant and sorcery cards"); + + static { + FILTER_CARDS_INSTANT_AND_SORCERY.setLockedFilter(true); + } + public static final FilterPermanentCard FILTER_CARD_PERMANENT = new FilterPermanentCard("permanent card"); static { diff --git a/Mage/src/main/java/mage/filter/common/FilterAnyTarget.java b/Mage/src/main/java/mage/filter/common/FilterAnyTarget.java index 0958607c370..45e16a5c591 100644 --- a/Mage/src/main/java/mage/filter/common/FilterAnyTarget.java +++ b/Mage/src/main/java/mage/filter/common/FilterAnyTarget.java @@ -4,6 +4,8 @@ import mage.constants.CardType; import mage.filter.predicate.Predicates; /** + * Warning, it's a filter for damage effects only (ignore lands, artifacts and other non-damageable objects) + * * @author TheElk801 */ public class FilterAnyTarget extends FilterPermanentOrPlayer { diff --git a/Mage/src/main/java/mage/filter/common/FilterPlaneswalkerPermanent.java b/Mage/src/main/java/mage/filter/common/FilterPlaneswalkerPermanent.java index eedc09a699b..638bf60a323 100644 --- a/Mage/src/main/java/mage/filter/common/FilterPlaneswalkerPermanent.java +++ b/Mage/src/main/java/mage/filter/common/FilterPlaneswalkerPermanent.java @@ -1,5 +1,3 @@ - - package mage.filter.common; import mage.constants.CardType; @@ -16,7 +14,11 @@ public class FilterPlaneswalkerPermanent extends FilterPermanent { } public FilterPlaneswalkerPermanent(SubType subType) { - this(subType.getDescription() + " planeswalker"); + this(subType, subType.getDescription() + " planeswalker"); + } + + public FilterPlaneswalkerPermanent(SubType subType, String name) { + this(name); this.add(subType.getPredicate()); } diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/AnotherPredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/AnotherPredicate.java index cca9260b1e7..6df56973dd5 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/AnotherPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/AnotherPredicate.java @@ -16,8 +16,7 @@ public enum AnotherPredicate implements ObjectSourcePlayerPredicate if (!input.getObject().getId().equals(input.getSourceId())) { return true; } - int zcc = input.getSource().getSourceObjectZoneChangeCounter(); - return zcc != 0 && zcc != input.getObject().getZoneChangeCounter(game); + return false; } @Override diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/PermanentIdPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/PermanentIdPredicate.java index c387ee3bcf3..9acd64939d1 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/PermanentIdPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/PermanentIdPredicate.java @@ -1,13 +1,12 @@ - package mage.filter.predicate.permanent; -import java.util.UUID; import mage.filter.predicate.Predicate; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public class PermanentIdPredicate implements Predicate { @@ -27,4 +26,5 @@ public class PermanentIdPredicate implements Predicate { public String toString() { return "PermanentId(" + permanentId + ')'; } + } diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/SaddledSourceThisTurnPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/SaddledSourceThisTurnPredicate.java index ed6593a8d91..f150d8244ea 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/SaddledSourceThisTurnPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/SaddledSourceThisTurnPredicate.java @@ -17,9 +17,9 @@ public enum SaddledSourceThisTurnPredicate implements ObjectSourcePlayerPredicat @Override public boolean apply(ObjectSourcePlayer input, Game game) { - return SaddledMountWatcher.checkIfSaddledThisTurn( - input.getObject(), new MageObjectReference(input.getSourceId(), input.getSource().getSourceObjectZoneChangeCounter(), game), game - ); + // for delayed triggers must use starting zcc (when delayed trigger created) + MageObjectReference startingMor = new MageObjectReference(input.getSourceId(), input.getSource().getSourceObjectZoneChangeCounter(), game); + return SaddledMountWatcher.checkIfSaddledThisTurn(input.getObject(), startingMor, game); } @Override diff --git a/Mage/src/main/java/mage/game/Game.java b/Mage/src/main/java/mage/game/Game.java index 2df39b9016d..ad0cd9232d4 100644 --- a/Mage/src/main/java/mage/game/Game.java +++ b/Mage/src/main/java/mage/game/Game.java @@ -30,6 +30,7 @@ import mage.game.permanent.Battlefield; import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.game.stack.SpellStack; +import mage.game.stack.StackObject; import mage.game.turn.Phase; import mage.game.turn.Step; import mage.game.turn.Turn; @@ -47,6 +48,11 @@ import java.util.stream.Collectors; public interface Game extends MageItem, Serializable, Copyable { + /** + * Return global game index (used for better logs and history) + */ + Integer getGameIndex(); + MatchType getGameType(); int getNumPlayers(); @@ -136,6 +142,7 @@ public interface Game extends MageItem, Serializable, Copyable { Map getPermanentsEntering(); Map> getLKI(); + Map> getPermanentCostsTags(); /** @@ -170,9 +177,9 @@ public interface Game extends MageItem, Serializable, Copyable { PlayerList getPlayerList(); /** - * Returns opponents list in range for the given playerId. Use it to interate by starting turn order. - * - * Warning, it will return leaved players until end of turn. For dialogs and one shot effects use excludeLeavedPlayers + * Returns opponents list in range for the given playerId. Use it to interate by starting turn order. + *

+ * Warning, it will return leaved players until end of turn. For dialogs and one shot effects use excludeLeavedPlayers */ // TODO: check usage of getOpponents in cards and replace with correct call of excludeLeavedPlayers, see #13289 default Set getOpponents(UUID playerId) { @@ -180,8 +187,8 @@ public interface Game extends MageItem, Serializable, Copyable { } /** - * Returns opponents list in range for the given playerId. Use it to interate by starting turn order. - * Warning, it will return dead players until end of turn. + * Returns opponents list in range for the given playerId. Use it to interate by starting turn order. + * Warning, it will return dead players until end of turn. * * @param excludeLeavedPlayers exclude dead player immediately without waiting range update on next turn */ @@ -244,7 +251,7 @@ public interface Game extends MageItem, Serializable, Copyable { /** * Id of the player the current turn it is. - * + *

* Player can be under control of another player, so search a real GUI's controller by Player->getTurnControlledBy * * @return @@ -310,6 +317,19 @@ public interface Game extends MageItem, Serializable, Copyable { void resetShortLivingLKI(); + /** + * For finding the spell or ability on the stack for "becomes the target" triggers. + * Also ensures that spells/abilities that target the same object twice only trigger each "becomes the target" ability once. + * If this is the first attempt at triggering for a given ability targeting a given object, + * this method temporarily records that in the game state for later checks by this same method, + * to not return the same object again (until short living LKI is cleared) + * + * @param checkingReference must be unique for each usage (this.getId().toString() of the TriggeredAbility, or this.getKey() of the watcher) + * @param event the GameEvent.EventType.TARGETED from checkTrigger() or watch() + * @return the StackObject which targeted the source, or null if already used or not found + */ + StackObject findTargetingStackObject(String checkingReference, GameEvent event); + void setLosingPlayer(Player player); Player getLosingPlayer(); @@ -549,14 +569,15 @@ public interface Game extends MageItem, Serializable, Copyable { */ void processAction(); - @Deprecated // TODO: must research usage and remove it from all non engine code (example: Bestow ability, ProcessActions must be used instead) + @Deprecated + // TODO: must research usage and remove it from all non engine code (example: Bestow ability, ProcessActions must be used instead) boolean checkStateAndTriggered(); /** * Play priority by all players * * @param activePlayerId starting priority player - * @param resuming false to reset passed priority and ask it again + * @param resuming false to reset passed priority and ask it again */ void playPriority(UUID activePlayerId, boolean resuming); @@ -586,6 +607,7 @@ public interface Game extends MageItem, Serializable, Copyable { /** * TODO: remove logic changed, must research each usage of removeBookmark and replace it with new code + * * @param bookmark */ void removeBookmark_v2(int bookmark); @@ -606,6 +628,7 @@ public interface Game extends MageItem, Serializable, Copyable { // game cheats (for tests only) void cheat(UUID ownerId, Map commands); + void cheat(UUID ownerId, List library, List hand, List battlefield, List graveyard, List command, List exiled); // controlling the behaviour of replacement effects while permanents entering the battlefield @@ -797,4 +820,8 @@ public interface Game extends MageItem, Serializable, Copyable { boolean isGameStopped(); boolean isTurnOrderReversed(); + + UUID getTableId(); + + void setTableId(UUID tableId); } diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 06932787520..e3f59becee3 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -27,6 +27,7 @@ import mage.cards.*; import mage.cards.decks.Deck; import mage.cards.decks.DeckCardInfo; import mage.choices.Choice; +import mage.collectors.DataCollectorServices; import mage.constants.*; import mage.counters.CounterType; import mage.counters.Counters; @@ -94,6 +95,8 @@ import java.util.stream.Collectors; */ public abstract class GameImpl implements Game { + private final static AtomicInteger GLOBAL_INDEX = new AtomicInteger(); + private static final int ROLLBACK_TURNS_MAX = 4; private static final String UNIT_TESTS_ERROR_TEXT = "Error in unit tests"; private static final Logger logger = Logger.getLogger(GameImpl.class); @@ -108,6 +111,8 @@ public abstract class GameImpl implements Game { protected AtomicInteger totalErrorsCount = new AtomicInteger(); // for debug only: error stats protected final UUID id; + protected final Integer gameIndex; // for better logs and history + protected UUID tableId = null; protected boolean ready; protected transient TableEventSource tableEventSource = new TableEventSource(); @@ -121,6 +126,8 @@ public abstract class GameImpl implements Game { protected Map> lkiExtended = new HashMap<>(); // Used to check if an object was moved by the current effect in resolution (so Wrath like effect can be handled correctly) protected Map> lkiShortLiving = new EnumMap<>(Zone.class); + // For checking "becomes the target" triggers accurately. Cleared on short living LKI reset + protected Map>> targetedMap = new HashMap<>(); // Permanents entering the Battlefield while handling replacement effects before they are added to the battlefield protected Map permanentsEntering = new HashMap<>(); @@ -169,6 +176,7 @@ public abstract class GameImpl implements Game { public GameImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int minimumDeckSize, int startingLife, int startingHandSize) { this.id = UUID.randomUUID(); + this.gameIndex = GLOBAL_INDEX.incrementAndGet(); this.range = range; this.mulligan = mulligan; this.attackOption = attackOption; @@ -189,6 +197,8 @@ public abstract class GameImpl implements Game { this.checkPlayableState = game.checkPlayableState; this.id = game.id; + this.gameIndex = game.gameIndex; + this.tableId = game.tableId; this.totalErrorsCount.set(game.totalErrorsCount.get()); this.ready = game.ready; @@ -202,6 +212,7 @@ public abstract class GameImpl implements Game { this.lkiCardState = CardUtil.deepCopyObject(game.lkiCardState); this.lkiExtended = CardUtil.deepCopyObject(game.lkiExtended); this.lkiShortLiving = CardUtil.deepCopyObject(game.lkiShortLiving); + this.targetedMap = CardUtil.deepCopyObject(game.targetedMap); this.permanentsEntering = CardUtil.deepCopyObject(game.permanentsEntering); this.enterWithCounters = CardUtil.deepCopyObject(game.enterWithCounters); @@ -247,6 +258,11 @@ public abstract class GameImpl implements Game { */ } + @Override + public Integer getGameIndex() { + return this.gameIndex; + } + @Override public boolean isSimulation() { return simulation; @@ -884,6 +900,12 @@ public abstract class GameImpl implements Game { if (state.isGameOver()) { return true; } + + // stop on game thread ended by third party tools or AI's timeout + if (Thread.currentThread().isInterrupted()) { + return true; + } + int remainingPlayers = 0; int numLosers = 0; for (Player player : state.getPlayers().values()) { @@ -894,7 +916,10 @@ public abstract class GameImpl implements Game { numLosers++; } } - if (remainingPlayers <= 1 || numLosers >= state.getPlayers().size() - 1) { + + // stop on no more active players + boolean noMorePlayers = remainingPlayers <= 1 || numLosers >= state.getPlayers().size() - 1; + if (noMorePlayers) { end(); if (remainingPlayers == 0 && logger.isDebugEnabled()) { logger.debug("DRAW for gameId: " + getId()); @@ -1035,6 +1060,7 @@ public abstract class GameImpl implements Game { @Override public void start(UUID choosingPlayerId) { startTime = new Date(); + DataCollectorServices.getInstance().onGameStart(this); if (state.getPlayers().values().iterator().hasNext()) { init(choosingPlayerId); play(startingPlayerId); @@ -1412,21 +1438,21 @@ public abstract class GameImpl implements Game { public void initGameDefaultWatchers() { List newWatchers = new ArrayList<>(); - newWatchers.add(new CastSpellLastTurnWatcher()); - newWatchers.add(new PlayerLostLifeWatcher()); + newWatchers.add(new CastSpellLastTurnWatcher()); // SPELL_CAST + newWatchers.add(new PlayerLostLifeWatcher()); // LOST_LIFE newWatchers.add(new FirstStrikeWatcher()); // required for combat code - newWatchers.add(new BlockedAttackerWatcher()); + newWatchers.add(new BlockedAttackerWatcher()); // BLOCKER_DECLARED newWatchers.add(new PlanarRollWatcher()); // needed for RollDiceTest (planechase code needs improves) - newWatchers.add(new AttackedThisTurnWatcher()); - newWatchers.add(new CardsDrawnThisTurnWatcher()); - newWatchers.add(new ManaSpentToCastWatcher()); - newWatchers.add(new ManaPaidSourceWatcher()); - newWatchers.add(new BlockingOrBlockedWatcher()); - newWatchers.add(new EndStepCountWatcher()); + newWatchers.add(new AttackedThisTurnWatcher()); // ATTACKER_DECLARED + newWatchers.add(new CardsDrawnThisTurnWatcher()); // DREW_CARD + newWatchers.add(new ManaSpentToCastWatcher()); // SPELL_CAST + newWatchers.add(new ManaPaidSourceWatcher()); // MANA_PAID + newWatchers.add(new BlockingOrBlockedWatcher()); // BLOCKER_DECLARED, END_COMBAT_STEP_POST, REMOVED_FROM_COMBAT + newWatchers.add(new EndStepCountWatcher()); // for continuous effects newWatchers.add(new CommanderPlaysCountWatcher()); // commander plays count uses in non commander games by some cards - newWatchers.add(new CreaturesDiedWatcher()); - newWatchers.add(new TemptedByTheRingWatcher()); - newWatchers.add(new SpellsCastWatcher()); + newWatchers.add(new CreaturesDiedWatcher()); // ZONE_CHANGE + newWatchers.add(new TemptedByTheRingWatcher()); // TEMPTED_BY_RING + newWatchers.add(new SpellsCastWatcher()); // SPELL_CAST newWatchers.add(new AttackedOrBlockedThisCombatWatcher()); // required for tests // runtime check - allows only GAME scope (one watcher per game) @@ -1550,6 +1576,11 @@ public abstract class GameImpl implements Game { endTime = new Date(); state.endGame(); + // cancel all player dialogs/feedbacks + for (Player player : state.getPlayers().values()) { + player.abort(); + } + // inform players about face down cards state.getBattlefield().getAllPermanents() .stream() @@ -1569,10 +1600,7 @@ public abstract class GameImpl implements Game { .sorted() .forEach(this::informPlayers); - // cancel all player dialogs/feedbacks - for (Player player : state.getPlayers().values()) { - player.abort(); - } + DataCollectorServices.getInstance().onGameEnd(this); } } @@ -1779,7 +1807,7 @@ public abstract class GameImpl implements Game { // count total errors Player activePlayer = this.getPlayer(getActivePlayerId()); - if (activePlayer != null && !activePlayer.isTestsMode()) { + if (activePlayer != null && !activePlayer.isTestMode() && !activePlayer.isFastFailInTestMode()) { // real game - try to continue priorityErrorsCount++; continue; @@ -2791,7 +2819,7 @@ public abstract class GameImpl implements Game { if (attachedTo != null) { for (Ability ability : perm.getAbilities(this)) { if (ability instanceof AttachableToRestrictedAbility) { - if (!((AttachableToRestrictedAbility) ability).canEquip(attachedTo, null, this)) { + if (!((AttachableToRestrictedAbility) ability).canEquip(attachedTo.getId(), null, this)) { attachedTo = null; break; } @@ -3161,6 +3189,8 @@ public abstract class GameImpl implements Game { @Override public void informPlayers(String message) { + DataCollectorServices.getInstance().onGameLog(this, message); + // Uncomment to print game messages // System.out.println(message.replaceAll("\\<.*?\\>", "")); if (simulation) { @@ -3687,6 +3717,39 @@ public abstract class GameImpl implements Game { @Override public void resetShortLivingLKI() { lkiShortLiving.clear(); + targetedMap.clear(); + } + + @Override + public StackObject findTargetingStackObject(String checkingReference, GameEvent event) { + // In case of multiple simultaneous triggered abilities from the same source, + // need to get the actual one that targeted, see #8026, #8378, rulings for Battle Mammoth + // In case of copied triggered abilities, need to trigger on each independently, see #13498 + // Also avoids triggering on cancelled selections, see #8802 + Map> targetMap = targetedMap.getOrDefault(checkingReference, null); + // targetMap: key - targetId; value - Set of stackObject Ids + if (targetMap == null) { + targetMap = new HashMap<>(); + } else { + targetMap = new HashMap<>(targetMap); // must have new object reference if saved back + } + Set targetingObjects = targetMap.computeIfAbsent(event.getTargetId(), k -> new HashSet<>()); + for (StackObject stackObject : getStack()) { + Ability stackAbility = stackObject.getStackAbility(); + if (stackAbility == null || !stackAbility.getSourceId().equals(event.getSourceId())) { + continue; + } + if (CardUtil.getAllSelectedTargets(stackAbility, this).contains(event.getTargetId())) { + if (!targetingObjects.add(stackObject.getId())) { + continue; // The trigger/watcher already recorded that target of the stack object, check for another + } + // Otherwise, store this combination of trigger/watcher + target + stack object + targetMap.put(event.getTargetId(), targetingObjects); + targetedMap.put(checkingReference, targetMap); + return stackObject; + } + } + return null; } @Override @@ -4203,4 +4266,14 @@ public abstract class GameImpl implements Game { .append(this.getState().isGameOver() ? "; FINISHED: " + this.getWinner() : ""); return sb.toString(); } + + @Override + public UUID getTableId() { + return this.tableId; + } + + @Override + public void setTableId(UUID tableId) { + this.tableId = tableId; + } } diff --git a/Mage/src/main/java/mage/game/Table.java b/Mage/src/main/java/mage/game/Table.java index a7c84529f82..1126d199058 100644 --- a/Mage/src/main/java/mage/game/Table.java +++ b/Mage/src/main/java/mage/game/Table.java @@ -3,7 +3,10 @@ package mage.game; import java.io.Serializable; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + import mage.cards.decks.DeckValidator; +import mage.collectors.DataCollectorServices; import mage.constants.TableState; import mage.game.draft.Draft; import mage.game.events.Listener; @@ -20,7 +23,10 @@ import mage.players.PlayerType; */ public class Table implements Serializable { + private final static AtomicInteger GLOBAL_INDEX = new AtomicInteger(); + private UUID tableId; + private Integer tableIndex; // for better logs and history private UUID roomId; private String name; private String controllerName; @@ -54,17 +60,23 @@ public class Table implements Serializable { this.tournament = tournament; this.isTournament = true; setState(TableState.WAITING); + + DataCollectorServices.getInstance().onTableStart(this); } public Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List playerTypes, TableRecorder recorder, Match match, Set bannedUsernames, boolean isPlaneChase) { this(roomId, gameType, name, controllerName, validator, playerTypes, recorder, bannedUsernames, isPlaneChase); this.match = match; + this.match.setTableId(this.getId()); this.isTournament = false; setState(TableState.WAITING); + + DataCollectorServices.getInstance().onTableStart(this); } protected Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List playerTypes, TableRecorder recorder, Set bannedUsernames, boolean isPlaneChase) { - tableId = UUID.randomUUID(); + this.tableId = UUID.randomUUID(); + this.tableIndex = GLOBAL_INDEX.incrementAndGet(); this.roomId = roomId; this.numSeats = playerTypes.size(); this.gameType = gameType; @@ -91,6 +103,10 @@ public class Table implements Serializable { return tableId; } + public Integer getTableIndex() { + return tableIndex; + } + public UUID getParentTableId() { return parentTableId; } @@ -132,6 +148,8 @@ public class Table implements Serializable { setState(TableState.FINISHED); // otherwise the table can be removed completely } this.validator = null; + + DataCollectorServices.getInstance().onTableEnd(this); } /** diff --git a/Mage/src/main/java/mage/game/ZonesHandler.java b/Mage/src/main/java/mage/game/ZonesHandler.java index 65d336cdf1a..809fc545a32 100644 --- a/Mage/src/main/java/mage/game/ZonesHandler.java +++ b/Mage/src/main/java/mage/game/ZonesHandler.java @@ -16,6 +16,7 @@ import mage.game.permanent.PermanentToken; import mage.game.stack.Spell; import mage.players.Player; import mage.target.TargetCard; +import mage.util.FuzzyTestsUtil; import java.util.*; @@ -416,6 +417,9 @@ public final class ZonesHandler { && card.removeFromZone(game, fromZone, source)) { success = true; event.setTarget(permanent); + + // tests only: inject fuzzy data with random phased out permanents + FuzzyTestsUtil.addRandomPhasedOutPermanent(permanent, source, game); } else { // revert controller to owner if permanent does not enter game.getContinuousEffects().setController(permanent.getId(), permanent.getOwnerId()); diff --git a/Mage/src/main/java/mage/game/combat/Combat.java b/Mage/src/main/java/mage/game/combat/Combat.java index 333e786b95a..1fa776ffc2f 100644 --- a/Mage/src/main/java/mage/game/combat/Combat.java +++ b/Mage/src/main/java/mage/game/combat/Combat.java @@ -695,7 +695,8 @@ public class Combat implements Serializable, Copyable { // real game: send warning // test: fast fail game.informPlayers(controller.getLogName() + ": WARNING - AI can't find good blocker combination and will skip it - report your battlefield to github - " + game.getCombat()); - if (controller.isTestsMode()) { + if (controller.isTestMode() && controller.isFastFailInTestMode()) { + // fast fail in tests // how-to fix: AI code must support failed abilities or use cases throw new IllegalArgumentException("AI can't find good blocker combination"); } diff --git a/Mage/src/main/java/mage/game/command/dungeons/TombOfAnnihilationDungeon.java b/Mage/src/main/java/mage/game/command/dungeons/TombOfAnnihilationDungeon.java index be2c988301b..af928e4acfb 100644 --- a/Mage/src/main/java/mage/game/command/dungeons/TombOfAnnihilationDungeon.java +++ b/Mage/src/main/java/mage/game/command/dungeons/TombOfAnnihilationDungeon.java @@ -209,7 +209,7 @@ class OublietteTarget extends TargetSacrifice { @Override public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); - possibleTargets.removeIf(uuid -> !this.canTarget(sourceControllerId, uuid, null, game)); + possibleTargets.removeIf(uuid -> !this.canTarget(sourceControllerId, uuid, source, game)); return possibleTargets; } diff --git a/Mage/src/main/java/mage/game/command/emblems/SephirothOneWingedAngelEmblem.java b/Mage/src/main/java/mage/game/command/emblems/SephirothOneWingedAngelEmblem.java index 3d30bdf66ce..50b64a0d6c7 100644 --- a/Mage/src/main/java/mage/game/command/emblems/SephirothOneWingedAngelEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/SephirothOneWingedAngelEmblem.java @@ -2,7 +2,7 @@ package mage.game.command.emblems; import mage.abilities.Ability; import mage.abilities.common.DiesCreatureTriggeredAbility; -import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.constants.Zone; import mage.filter.StaticFilters; @@ -21,7 +21,7 @@ public final class SephirothOneWingedAngelEmblem extends Emblem { Zone.COMMAND, new LoseLifeTargetEffect(1), false, StaticFilters.FILTER_PERMANENT_A_CREATURE, false ); - ability.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and")); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); ability.addTarget(new TargetOpponent()); this.getAbilities().add(ability); } diff --git a/Mage/src/main/java/mage/game/command/emblems/TezzeretCruelCaptainEmblem.java b/Mage/src/main/java/mage/game/command/emblems/TezzeretCruelCaptainEmblem.java new file mode 100644 index 00000000000..e2975727a58 --- /dev/null +++ b/Mage/src/main/java/mage/game/command/emblems/TezzeretCruelCaptainEmblem.java @@ -0,0 +1,79 @@ +package mage.game.command.emblems; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.AddCardSubTypeTargetEffect; +import mage.abilities.effects.common.continuous.AddCardTypeTargetEffect; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.command.Emblem; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * @author TheElk801 + */ +public final class TezzeretCruelCaptainEmblem extends Emblem { + + // -7: You get an emblem with "At the beginning of combat on your turn, put three +1/+1 counters on target artifact you control. If it's not a creature, it becomes a 0/0 Robot artifact creature." + public TezzeretCruelCaptainEmblem() { + super("Emblem Tezzeret"); + Ability ability = new BeginningOfCombatTriggeredAbility( + Zone.COMMAND, TargetController.YOU, + new AddCountersTargetEffect(CounterType.P1P1.createInstance(3)), false + ); + ability.addEffect(new TezzeretCruelCaptainEmblemEffect()); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT)); + this.getAbilities().add(ability); + } + + private TezzeretCruelCaptainEmblem(final TezzeretCruelCaptainEmblem card) { + super(card); + } + + @Override + public TezzeretCruelCaptainEmblem copy() { + return new TezzeretCruelCaptainEmblem(this); + } +} + +class TezzeretCruelCaptainEmblemEffect extends OneShotEffect { + + TezzeretCruelCaptainEmblemEffect() { + super(Outcome.Benefit); + staticText = "If it's not a creature, it becomes a 0/0 Robot artifact creature"; + } + + private TezzeretCruelCaptainEmblemEffect(final TezzeretCruelCaptainEmblemEffect effect) { + super(effect); + } + + @Override + public TezzeretCruelCaptainEmblemEffect copy() { + return new TezzeretCruelCaptainEmblemEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null || permanent.isCreature(game)) { + return false; + } + game.addEffect(new AddCardTypeTargetEffect( + Duration.Custom, CardType.ARTIFACT, CardType.CREATURE + ).setTargetPointer(new FixedTarget(permanent, game)), source); + game.addEffect(new AddCardSubTypeTargetEffect( + SubType.ROBOT, Duration.Custom + ).setTargetPointer(new FixedTarget(permanent, game)), source); + game.addEffect(new SetBasePowerToughnessTargetEffect( + 0, 0, Duration.Custom + ).setTargetPointer(new FixedTarget(permanent, game)), source); + return true; + } +} diff --git a/Mage/src/main/java/mage/game/command/planes/AkoumPlane.java b/Mage/src/main/java/mage/game/command/planes/AkoumPlane.java index bcf839a0580..a1892cf8a57 100644 --- a/Mage/src/main/java/mage/game/command/planes/AkoumPlane.java +++ b/Mage/src/main/java/mage/game/command/planes/AkoumPlane.java @@ -16,6 +16,7 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.EnchantedPredicate; import mage.game.command.Plane; import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.watchers.common.PlanarRollWatcher; @@ -44,7 +45,7 @@ public class AkoumPlane extends Plane { // Active player can roll the planar die: Whenever you roll {CHAOS}, destroy target creature that isn't enchanted Effect chaosEffect = new DestroyTargetEffect("destroy target creature that isn't enchanted"); - Target chaosTarget = new TargetCreaturePermanent(filter); + Target chaosTarget = new TargetPermanent(filter); List chaosEffects = new ArrayList(); chaosEffects.add(chaosEffect); diff --git a/Mage/src/main/java/mage/game/command/planes/BantPlane.java b/Mage/src/main/java/mage/game/command/planes/BantPlane.java index 0a8f555508e..4b5ec23f954 100644 --- a/Mage/src/main/java/mage/game/command/planes/BantPlane.java +++ b/Mage/src/main/java/mage/game/command/planes/BantPlane.java @@ -27,7 +27,7 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.command.Plane; import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import mage.watchers.common.PlanarRollWatcher; import java.util.ArrayList; @@ -62,7 +62,7 @@ public class BantPlane extends Plane { // Active player can roll the planar die: Whenever you roll {CHAOS}, put a divinity counter on target green, white, or blue creature. That creature gains indestructible for as long as it has a divinity counter on it. Effect chaosEffect = new ConditionalContinuousEffect(new GainAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.Custom), new TargetHasCounterCondition(CounterType.DIVINITY), rule); - Target chaosTarget = new TargetCreaturePermanent(1, 1, filter2, false); + Target chaosTarget = new TargetPermanent(filter2); Effect chaosEffect2 = new AddCountersTargetEffect(CounterType.DIVINITY.createInstance()); List chaosEffects = new ArrayList(); diff --git a/Mage/src/main/java/mage/game/command/planes/FeedingGroundsPlane.java b/Mage/src/main/java/mage/game/command/planes/FeedingGroundsPlane.java index 2cf165b8343..f10bdc9ca9e 100644 --- a/Mage/src/main/java/mage/game/command/planes/FeedingGroundsPlane.java +++ b/Mage/src/main/java/mage/game/command/planes/FeedingGroundsPlane.java @@ -25,7 +25,7 @@ import mage.game.Game; import mage.game.command.Plane; import mage.game.stack.Spell; import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import mage.util.CardUtil; import mage.watchers.common.PlanarRollWatcher; @@ -48,7 +48,7 @@ public class FeedingGroundsPlane extends Plane { // Active player can roll the planar die: Whenever you roll {CHAOS}, target red or green creature gets X +1/+1 counters Effect chaosEffect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(), TargetManaValue.instance); - Target chaosTarget = new TargetCreaturePermanent(1, 1, StaticFilters.FILTER_PERMANENT_A_CREATURE, false); + Target chaosTarget = new TargetPermanent(StaticFilters.FILTER_PERMANENT_A_CREATURE); List chaosEffects = new ArrayList<>(); chaosEffects.add(chaosEffect); diff --git a/Mage/src/main/java/mage/game/command/planes/NayaPlane.java b/Mage/src/main/java/mage/game/command/planes/NayaPlane.java index c622443917b..2704ed07911 100644 --- a/Mage/src/main/java/mage/game/command/planes/NayaPlane.java +++ b/Mage/src/main/java/mage/game/command/planes/NayaPlane.java @@ -23,7 +23,7 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.command.Plane; import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.TargetPermanent; import mage.watchers.common.PlanarRollWatcher; import java.util.ArrayList; @@ -50,7 +50,7 @@ public class NayaPlane extends Plane { // Active player can roll the planar die: Whenever you roll {CHAOS}, target red, green or white creature you control gets +1/+1 until end of turn for each land you control DynamicValue dynamicValue = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_PERMANENT_LANDS); Effect chaosEffect = new BoostTargetEffect(dynamicValue, dynamicValue, Duration.EndOfTurn); - Target chaosTarget = new TargetControlledCreaturePermanent(1, 1, filter, false); + Target chaosTarget = new TargetPermanent(filter); List chaosEffects = new ArrayList<>(); chaosEffects.add(chaosEffect); diff --git a/Mage/src/main/java/mage/game/events/MageEvent.java b/Mage/src/main/java/mage/game/events/MageEvent.java deleted file mode 100644 index 540890dc3e7..00000000000 --- a/Mage/src/main/java/mage/game/events/MageEvent.java +++ /dev/null @@ -1,13 +0,0 @@ - - -package mage.game.events; - -import java.io.Serializable; - -/** - * - * @author BetaSteward_at_googlemail.com - */ -public interface MageEvent extends Serializable { - -} diff --git a/Mage/src/main/java/mage/game/match/Match.java b/Mage/src/main/java/mage/game/match/Match.java index 76e74e71683..7f080674871 100644 --- a/Mage/src/main/java/mage/game/match/Match.java +++ b/Mage/src/main/java/mage/game/match/Match.java @@ -10,7 +10,7 @@ import mage.game.GameException; import mage.game.GameInfo; import mage.game.events.Listener; import mage.game.events.TableEvent; -import mage.game.result.ResultProtos.MatchProto; +import mage.game.result.ResultProtos.MatchProto; // on unknown package error must run and auto-generate proto classes by "mvn install -DskipTests" import mage.players.Player; /** diff --git a/Mage/src/main/java/mage/game/match/MatchImpl.java b/Mage/src/main/java/mage/game/match/MatchImpl.java index 3fb5def5119..0e0e2b1d119 100644 --- a/Mage/src/main/java/mage/game/match/MatchImpl.java +++ b/Mage/src/main/java/mage/game/match/MatchImpl.java @@ -192,6 +192,7 @@ public abstract class MatchImpl implements Match { } protected void initGame(Game game) throws GameException { + game.setTableId(this.tableId); addGame(); // raises only the number shufflePlayers(); for (MatchPlayer matchPlayer : this.players) { @@ -291,6 +292,9 @@ public abstract class MatchImpl implements Match { @Override public void setTableId(UUID tableId) { this.tableId = tableId; + + // sync tableId with all games (needs for data collectors) + this.games.forEach(game -> game.setTableId(tableId)); } @Override diff --git a/Mage/src/main/java/mage/game/permanent/token/EldraziSpawnToken.java b/Mage/src/main/java/mage/game/permanent/token/EldraziSpawnToken.java index 17e31578470..5b91322b813 100644 --- a/Mage/src/main/java/mage/game/permanent/token/EldraziSpawnToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/EldraziSpawnToken.java @@ -14,7 +14,7 @@ import mage.constants.Zone; public final class EldraziSpawnToken extends TokenImpl { public EldraziSpawnToken() { - super("Eldrazi Spawn Token", "0/1 colorless Eldrazi Spawn creature token with \"Sacrifice this creature: Add {C}.\""); + super("Eldrazi Spawn Token", "0/1 colorless Eldrazi Spawn creature token with \"Sacrifice this token: Add {C}.\""); cardType.add(CardType.CREATURE); subtype.add(SubType.ELDRAZI); subtype.add(SubType.SPAWN); diff --git a/Mage/src/main/java/mage/game/permanent/token/LandMineToken.java b/Mage/src/main/java/mage/game/permanent/token/LandMineToken.java index 7ca06d55e7c..f0da2b9fd4a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/LandMineToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/LandMineToken.java @@ -11,6 +11,7 @@ import mage.constants.Zone; import mage.filter.common.FilterAttackingCreature; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -29,7 +30,7 @@ public final class LandMineToken extends TokenImpl { cardType.add(CardType.ARTIFACT); Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2), new ManaCostsImpl<>("{R}")); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage/src/main/java/mage/game/permanent/token/LanderToken.java b/Mage/src/main/java/mage/game/permanent/token/LanderToken.java new file mode 100644 index 00000000000..5ed109a96cd --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/LanderToken.java @@ -0,0 +1,39 @@ +package mage.game.permanent.token; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInLibrary; + +/** + * @author TheElk801 + */ +public final class LanderToken extends TokenImpl { + + public LanderToken() { + super("Lander Token", "Lander token"); + cardType.add(CardType.ARTIFACT); + subtype.add(SubType.LANDER); + + Ability ability = new SimpleActivatedAbility(new SearchLibraryPutInPlayEffect( + new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND_A), true + ), new GenericManaCost(2)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private LanderToken(final LanderToken token) { + super(token); + } + + public LanderToken copy() { + return new LanderToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/QueenMarchesaAssassinToken.java b/Mage/src/main/java/mage/game/permanent/token/QueenMarchesaAssassinToken.java index a55a5821e01..da3427f80be 100644 --- a/Mage/src/main/java/mage/game/permanent/token/QueenMarchesaAssassinToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/QueenMarchesaAssassinToken.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class QueenMarchesaAssassinToken extends TokenImpl { public QueenMarchesaAssassinToken() { - super("Assassin Token", "1/1 black Assassin creature tokens with deathtouch and haste"); + super("Assassin Token", "1/1 black Assassin creature token with deathtouch and haste"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.ASSASSIN); diff --git a/Mage/src/main/java/mage/game/permanent/token/Robot33Token.java b/Mage/src/main/java/mage/game/permanent/token/Robot33Token.java new file mode 100644 index 00000000000..069d3aace94 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/Robot33Token.java @@ -0,0 +1,28 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class Robot33Token extends TokenImpl { + + public Robot33Token() { + super("Robot Token", "3/3 colorless Robot artifact creature token"); + cardType.add(CardType.ARTIFACT); + cardType.add(CardType.CREATURE); + subtype.add(SubType.ROBOT); + power = new MageInt(3); + toughness = new MageInt(3); + } + + private Robot33Token(final Robot33Token token) { + super(token); + } + + public Robot33Token copy() { + return new Robot33Token(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/RobotToken.java b/Mage/src/main/java/mage/game/permanent/token/RobotToken.java index 4829e4c853c..92164fd6074 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RobotToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RobotToken.java @@ -10,12 +10,12 @@ import mage.constants.SubType; public final class RobotToken extends TokenImpl { public RobotToken() { - super("Robot Token", "3/3 colorless Robot artifact creature token"); + super("Robot Token", "2/2 colorless Robot artifact creature token"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.ROBOT); - power = new MageInt(3); - toughness = new MageInt(3); + power = new MageInt(2); + toughness = new MageInt(2); } private RobotToken(final RobotToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/SandWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/SandWarriorToken.java index 609017a96cd..bdcbb823b95 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SandWarriorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SandWarriorToken.java @@ -10,7 +10,7 @@ import mage.constants.SubType; public final class SandWarriorToken extends TokenImpl { public SandWarriorToken() { - super("Sand Warrior Token", "1/1 red, green, and white Sand Warrior creature tokens"); + super("Sand Warrior Token", "1/1 red, green, and white Sand Warrior creature token"); cardType.add(CardType.CREATURE); color.setRed(true); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/Spirit31Token.java b/Mage/src/main/java/mage/game/permanent/token/Spirit31Token.java new file mode 100644 index 00000000000..75e905ac67a --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/Spirit31Token.java @@ -0,0 +1,32 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.keyword.FlyingAbility; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class Spirit31Token extends TokenImpl { + + public Spirit31Token() { + super("Spirit Token", "3/1 white Spirit creature token with flying"); + cardType.add(CardType.CREATURE); + color.setWhite(true); + subtype.add(SubType.SPIRIT); + power = new MageInt(3); + toughness = new MageInt(1); + + addAbility(FlyingAbility.getInstance()); + } + + private Spirit31Token(final Spirit31Token token) { + super(token); + } + + @Override + public Spirit31Token copy() { + return new Spirit31Token(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/ThePrydwenSteelFlagshipHumanKnightToken.java b/Mage/src/main/java/mage/game/permanent/token/ThePrydwenSteelFlagshipHumanKnightToken.java index 4e17cf36883..c6509c84863 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ThePrydwenSteelFlagshipHumanKnightToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ThePrydwenSteelFlagshipHumanKnightToken.java @@ -19,7 +19,7 @@ public class ThePrydwenSteelFlagshipHumanKnightToken extends TokenImpl { * /!\ You need to add ArtifactEnteredControllerWatcher to any card using this token */ public ThePrydwenSteelFlagshipHumanKnightToken() { - super("Human Knight Token", "2/2 white Human Knight creature token with \"This creature " + + super("Human Knight Token", "2/2 white Human Knight creature token with \"This token " + "gets +2/+2 as long as an artifact entered the battlefield under your control this turn.\""); cardType.add(CardType.CREATURE); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/tournament/MultiplayerRound.java b/Mage/src/main/java/mage/game/tournament/MultiplayerRound.java index 2f19c2c2d97..7fdc106b767 100644 --- a/Mage/src/main/java/mage/game/tournament/MultiplayerRound.java +++ b/Mage/src/main/java/mage/game/tournament/MultiplayerRound.java @@ -42,14 +42,11 @@ public class MultiplayerRound { return this.roundNum; } - public void setMatch (Match match) { + public void setMatchAndTable(Match match, UUID tableId) { this.match = match; - } - - public void setTableId (UUID tableId) { this.tableId = tableId; } - + public boolean isRoundOver() { boolean roundIsOver = true; if (this.match != null) { diff --git a/Mage/src/main/java/mage/game/tournament/TournamentPairing.java b/Mage/src/main/java/mage/game/tournament/TournamentPairing.java index 3939ce40f0c..986887c6711 100644 --- a/Mage/src/main/java/mage/game/tournament/TournamentPairing.java +++ b/Mage/src/main/java/mage/game/tournament/TournamentPairing.java @@ -42,8 +42,9 @@ public class TournamentPairing { return match; } - public void setMatch(Match match) { + public void setMatchAndTable(Match match, UUID tableId) { this.match = match; + this.tableId = tableId; } /** @@ -88,10 +89,6 @@ public class TournamentPairing { return tableId; } - public void setTableId(UUID tableId) { - this.tableId = tableId; - } - public boolean isAlreadyPublished() { return alreadyPublished; } diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index 1028d914a0c..5e3e89f8a8d 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -79,7 +79,13 @@ public interface Player extends MageItem, Copyable { */ boolean isHuman(); - boolean isTestsMode(); + boolean isTestMode(); + + void setTestMode(boolean value); + + boolean isFastFailInTestMode(); + + void setFastFailInTestMode(boolean value); /** * Current player is AI. Use it in card's code and all other places. @@ -398,8 +404,6 @@ public interface Player extends MageItem, Copyable { */ void setGameUnderYourControl(Game game, boolean value, boolean fullRestore); - void setTestMode(boolean value); - void setAllowBadMoves(boolean allowBadMoves); /** @@ -816,6 +820,9 @@ public interface Player extends MageItem, Copyable { void construct(Tournament tournament, Deck deck); + /** + * Draft related: pick next card from a booster + */ void pickCard(List cards, Deck deck, Draft draft); // TODO: add result, process it in AI code (if something put creature to attack then it can broke current AI logic) diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 33227e25d36..94d126e11f5 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -147,6 +147,7 @@ public abstract class PlayerImpl implements Player, Serializable { protected Set inRange = new HashSet<>(); // players list in current range of influence (updates each turn due rules) protected boolean isTestMode = false; + protected boolean isFastFailInTestMode = true; protected boolean canGainLife = true; protected boolean canLoseLife = true; protected PayLifeCostLevel payLifeCostLevel = PayLifeCostLevel.allAbilities; @@ -2833,8 +2834,10 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean canRespond() { // abort is checked here to get out of player requests (as example: after disconnect) - return isInGame() && !abort; + public boolean canRespond() { + // abort is checked here to get out of player requests (as example: after disconnect) + // thread is checked here to get out of AI game simulations or close by third party tools + return isInGame() && !abort && !Thread.currentThread().isInterrupted(); } @Override @@ -4602,7 +4605,7 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean isTestsMode() { + public boolean isTestMode() { return isTestMode; } @@ -4611,6 +4614,16 @@ public abstract class PlayerImpl implements Player, Serializable { this.isTestMode = value; } + @Override + public boolean isFastFailInTestMode() { + return isFastFailInTestMode; + } + + @Override + public void setFastFailInTestMode(boolean value) { + this.isFastFailInTestMode = value; + } + @Override public boolean isTopCardRevealed() { return topCardRevealed; @@ -5450,7 +5463,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public SurveilResult doSurveil(int value, Ability source, Game game) { GameEvent event = new GameEvent(GameEvent.EventType.SURVEIL, getId(), source, getId(), value, true); - if (game.replaceEvent(event)) { + if (game.replaceEvent(event) || event.getAmount() < 1) { return SurveilResult.noSurveil(); } game.informPlayers(getLogName() + " surveils " + event.getAmount() + CardUtil.getSourceLogName(game, source)); diff --git a/Mage/src/main/java/mage/target/Target.java b/Mage/src/main/java/mage/target/Target.java index e5268c1ea98..c04395b2cc5 100644 --- a/Mage/src/main/java/mage/target/Target.java +++ b/Mage/src/main/java/mage/target/Target.java @@ -14,6 +14,7 @@ import java.util.Collection; import java.util.List; import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; /** * @author BetaSteward_at_googlemail.com @@ -26,10 +27,9 @@ public interface Target extends Copyable, Serializable { * Warning, for "up to" targets it will return true all the time, so make sure your dialog * use do-while logic and call "choose" one time min or use isChoiceCompleted */ + @Deprecated // TODO: replace with UUID abilityControllerId, Ability source, Game game boolean isChosen(Game game); - boolean isChoiceCompleted(Game game); - boolean isChoiceCompleted(UUID abilityControllerId, Ability source, Game game); void clearChosen(); @@ -64,6 +64,13 @@ public interface Target extends Copyable, Serializable { */ Set possibleTargets(UUID sourceControllerId, Ability source, Game game); + default Set possibleTargets(UUID sourceControllerId, Ability source, Game game, Set cards) { + // do not override + return possibleTargets(sourceControllerId, source, game).stream() + .filter(id -> cards == null || cards.contains(id)) + .collect(Collectors.toSet()); + } + /** * Priority method to make a choice from cards and other places, not a player.chooseXXX */ @@ -84,7 +91,7 @@ public interface Target extends Copyable, Serializable { /** * @param id - * @param source WARNING, it can be null for AI or other calls from events (TODO: introduce normal source in AI ComputerPlayer) + * @param source WARNING, it can be null for AI or other calls from events * @param game * @return */ @@ -188,14 +195,22 @@ public interface Target extends Copyable, Serializable { Target copy(); // some targets are chosen from players that are not the controller of the ability (e.g. Pandemonium) + // TODO: research usage of setTargetController and setAbilityController - target adjusters must set it both, example: Necrotic Plague + // replace by shared method like setAbilityAndTargetControllers() + @Deprecated void setTargetController(UUID playerId); UUID getTargetController(); + // TODO: research usage of setTargetController and setAbilityController - target adjusters must set it both, example: Necrotic Plague + // replace by shared method like setAbilityAndTargetControllers() + @Deprecated void setAbilityController(UUID playerId); UUID getAbilityController(); + UUID getAffectedAbilityControllerId(UUID choosingPlayerId); + Player getTargetController(Game game, UUID playerId); int getTargetTag(); diff --git a/Mage/src/main/java/mage/target/TargetAmount.java b/Mage/src/main/java/mage/target/TargetAmount.java index ccbfde6d66a..d28b1852459 100644 --- a/Mage/src/main/java/mage/target/TargetAmount.java +++ b/Mage/src/main/java/mage/target/TargetAmount.java @@ -16,13 +16,15 @@ import java.util.*; import java.util.stream.Collectors; /** + * Distribute value between targets list (damage, counters, etc) + * * @author BetaSteward_at_googlemail.com */ public abstract class TargetAmount extends TargetImpl { boolean amountWasSet = false; DynamicValue amount; - int remainingAmount; + int remainingAmount; // before any change to it - make sure you call prepareAmount protected TargetAmount(DynamicValue amount, int minNumberOfTargets, int maxNumberOfTargets) { this.amount = amount; @@ -46,15 +48,42 @@ public abstract class TargetAmount extends TargetImpl { @Override public boolean isChosen(Game game) { - return isChoiceCompleted(game); + if (!super.isChosen(game)) { + return false; + } + + // selection not started + if (!amountWasSet) { + return false; + } + + // distribution + if (getMinNumberOfTargets() == 0 && this.targets.isEmpty()) { + // allow 0 distribution, e.g. for "up to" targets like Vivien, Arkbow Ranger + return true; + } else { + // need full distribution + return remainingAmount == 0; + } } @Override - public boolean isChoiceCompleted(Game game) { - return amountWasSet - && (remainingAmount == 0 - || (getMinNumberOfTargets() < getMaxNumberOfTargets() - && getTargets().size() >= getMinNumberOfTargets())); + public boolean isChoiceCompleted(UUID abilityControllerId, Ability source, Game game) { + // make sure target request called one time minimum (for "up to" targets) + // choice is selected after any addTarget call (by test, AI or human players) + if (!isChoiceSelected()) { + return false; + } + + // make sure selected targets are valid + if (!isChosen(game)) { + return false; + } + + // TODO: need auto-choose here? See super + + // all other use cases are fine + return true; } @Override @@ -68,9 +97,14 @@ public abstract class TargetAmount extends TargetImpl { this.amount = amount; } - public void setAmount(Ability source, Game game) { - remainingAmount = amount.calculate(game, source, null); - amountWasSet = true; + /** + * Prepare new targets for choosing + */ + public void prepareAmount(Ability source, Game game) { + if (!amountWasSet) { + remainingAmount = amount.calculate(game, source, null); + amountWasSet = true; + } } public DynamicValue getAmount() { @@ -83,12 +117,11 @@ public abstract class TargetAmount extends TargetImpl { @Override public void addTarget(UUID id, int amount, Ability source, Game game, boolean skipEvent) { - if (!amountWasSet) { - setAmount(source, game); - } + prepareAmount(source, game); + if (amount <= remainingAmount) { - super.addTarget(id, amount, source, game, skipEvent); remainingAmount -= amount; + super.addTarget(id, amount, source, game, skipEvent); } } @@ -100,37 +133,70 @@ public abstract class TargetAmount extends TargetImpl { } @Override + public boolean choose(Outcome outcome, UUID playerId, UUID sourceId, Ability source, Game game) { + throw new IllegalArgumentException("Wrong code usage. TargetAmount must be called by player.chooseTarget, not player.choose"); + } + + @Override + @Deprecated // TODO: replace by player.chooseTargetAmount call public boolean chooseTarget(Outcome outcome, UUID playerId, Ability source, Game game) { - Player player = game.getPlayer(playerId); - if (player == null) { + Player targetController = getTargetController(game, playerId); + if (targetController == null) { return false; } - if (!amountWasSet) { - setAmount(source, game); - } + prepareAmount(source, game); - while (remainingAmount > 0) { - chosen = false; - if (!player.canRespond()) { - chosen = isChosen(game); + chosen = false; + do { + int prevTargetsCount = this.getTargets().size(); + + // stop by disconnect + if (!targetController.canRespond()) { break; } - if (!getTargetController(game, playerId).chooseTargetAmount(outcome, this, source, game)) { - chosen = isChosen(game); - break; + + // MAKE A CHOICE + if (isRandom()) { + // random choice + throw new IllegalArgumentException("Wrong code usage. TargetAmount do not support random choices"); + } else { + // player's choice + + // TargetAmount do not support auto-choice + + // manual + + // stop by cancel/done + if (!targetController.chooseTargetAmount(outcome, this, source, game)) { + break; + } + + // continue to next target } + chosen = isChosen(game); - } - return isChosen(game); + // stop by full complete + if (isChoiceCompleted(targetController.getId(), source, game)) { + break; + } + + // stop by nothing to choose (actual for human and done button?) + if (prevTargetsCount == this.getTargets().size()) { + break; + } + + // can select next target + } while (true); + + chosen = isChosen(game); + return chosen && !this.getTargets().isEmpty(); } @Override final public List getTargetOptions(Ability source, Game game) { - if (!amountWasSet) { - setAmount(source, game); - } + prepareAmount(source, game); List options = new ArrayList<>(); Set possibleTargets = possibleTargets(source.getControllerId(), source, game); @@ -370,9 +436,8 @@ public abstract class TargetAmount extends TargetImpl { } public void setTargetAmount(UUID targetId, int amount, Ability source, Game game) { - if (!amountWasSet) { - setAmount(source, game); - } + prepareAmount(source, game); + remainingAmount -= (amount - this.getTargetAmount(targetId)); this.setTargetAmount(targetId, amount, game); } @@ -396,4 +461,13 @@ public abstract class TargetAmount extends TargetImpl { // Each of these targets must receive at least one of whatever is being divided. return amount instanceof StaticValue && max == ((StaticValue) amount).getValue(); } + + @Override + public String toString() { + if (amountWasSet) { + return super.toString() + String.format(" (remain amount %d of %s)", this.remainingAmount, this.amount.toString()); + } else { + return super.toString() + String.format(" (remain not prepared, %s)", this.amount.toString()); + } + } } diff --git a/Mage/src/main/java/mage/target/TargetCard.java b/Mage/src/main/java/mage/target/TargetCard.java index 118ca88ed9e..3abc11591dc 100644 --- a/Mage/src/main/java/mage/target/TargetCard.java +++ b/Mage/src/main/java/mage/target/TargetCard.java @@ -110,6 +110,12 @@ public class TargetCard extends TargetObject { possibleTargets += countPossibleTargetInCommandZone(game, player, sourceControllerId, source, filter, isNotTarget(), this.minNumberOfTargets - possibleTargets); break; + case ALL: + possibleTargets += countPossibleTargetInAnyZone(game, player, sourceControllerId, source, + filter, isNotTarget(), this.minNumberOfTargets - possibleTargets); + break; + default: + throw new IllegalArgumentException("Unsupported TargetCard zone: " + zone); } if (possibleTargets >= this.minNumberOfTargets) { return true; @@ -214,6 +220,25 @@ public class TargetCard extends TargetObject { return possibleTargets; } + /** + * count up to N possible target cards in ANY zone + */ + protected static int countPossibleTargetInAnyZone(Game game, Player player, UUID sourceControllerId, Ability source, FilterCard filter, boolean isNotTarget, int countUpTo) { + UUID sourceId = source != null ? source.getSourceId() : null; + int possibleTargets = 0; + for (Card card : game.getCards()) { + if (sourceId == null || isNotTarget || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) { + if (filter.match(card, game)) { + possibleTargets++; + if (possibleTargets >= countUpTo) { + return possibleTargets; // early return for faster computation. + } + } + } + } + return possibleTargets; + } + @Override public Set possibleTargets(UUID sourceControllerId, Game game) { return possibleTargets(sourceControllerId, null, game); @@ -245,6 +270,11 @@ public class TargetCard extends TargetObject { case COMMAND: possibleTargets.addAll(getAllPossibleTargetInCommandZone(game, player, sourceControllerId, source, filter, isNotTarget())); break; + case ALL: + possibleTargets.addAll(getAllPossibleTargetInAnyZone(game, player, sourceControllerId, source, filter, isNotTarget())); + break; + default: + throw new IllegalArgumentException("Unsupported TargetCard zone: " + zone); } } } @@ -332,6 +362,22 @@ public class TargetCard extends TargetObject { return possibleTargets; } + /** + * set of all matching target in ANY zone + */ + protected static Set getAllPossibleTargetInAnyZone(Game game, Player player, UUID sourceControllerId, Ability source, FilterCard filter, boolean isNotTarget) { + Set possibleTargets = new HashSet<>(); + UUID sourceId = source != null ? source.getSourceId() : null; + for (Card card : game.getCards()) { + if (sourceId == null || isNotTarget || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) { + if (filter.match(card, sourceControllerId, source, game)) { + possibleTargets.add(card.getId()); + } + } + } + return possibleTargets; + } + // TODO: check all class targets, if it override canTarget then make sure it override ALL 3 METHODS with canTarget and possibleTargets (method with cards doesn't need) @Override diff --git a/Mage/src/main/java/mage/target/TargetImpl.java b/Mage/src/main/java/mage/target/TargetImpl.java index 8c5f1f73ea2..48f6f4bf73f 100644 --- a/Mage/src/main/java/mage/target/TargetImpl.java +++ b/Mage/src/main/java/mage/target/TargetImpl.java @@ -111,7 +111,7 @@ public abstract class TargetImpl implements Target { if (min > 0 && max == Integer.MAX_VALUE) { sb.append(CardUtil.numberToText(min)); sb.append(" or more "); - } else if (!targetName.startsWith("X ") && (min != 1 || max != 1)) { + } else if (!targetName.startsWith("X ") && !targetName.startsWith("up to ") && (min != 1 || max != 1)) { targetName = targetName.replace("another", "other"); //If non-singular, use "other" instead of "another" if (getUseAnyNumber()) { @@ -260,12 +260,6 @@ public abstract class TargetImpl implements Target { return chosen || (targets.size() >= getMinNumberOfTargets() && targets.size() <= getMaxNumberOfTargets()); } - @Override - @Deprecated // TODO: replace usage in cards by full version from choose methods - public boolean isChoiceCompleted(Game game) { - return isChoiceCompleted(null, null, game); - } - @Override public boolean isChoiceCompleted(UUID abilityControllerId, Ability source, Game game) { // make sure target request called one time minimum (for "up to" targets) @@ -407,10 +401,7 @@ public abstract class TargetImpl implements Target { return false; } - UUID abilityControllerId = playerId; - if (this.getTargetController() != null && this.getAbilityController() != null) { - abilityControllerId = this.getAbilityController(); - } + UUID abilityControllerId = this.getAffectedAbilityControllerId(playerId); chosen = false; do { @@ -445,7 +436,7 @@ public abstract class TargetImpl implements Target { } while (true); chosen = isChosen(game); - return this.getTargets().size() > 0; + return chosen && !this.getTargets().isEmpty(); } @Override @@ -455,10 +446,7 @@ public abstract class TargetImpl implements Target { return false; } - UUID abilityControllerId = playerId; - if (this.getTargetController() != null && this.getAbilityController() != null) { - abilityControllerId = this.getAbilityController(); - } + UUID abilityControllerId = this.getAffectedAbilityControllerId(playerId); List randomPossibleTargets = new ArrayList<>(possibleTargets(playerId, source, game)); @@ -528,7 +516,7 @@ public abstract class TargetImpl implements Target { } while (true); chosen = isChosen(game); - return this.getTargets().size() > 0; + return chosen && !this.getTargets().isEmpty(); } @Override @@ -727,6 +715,20 @@ public abstract class TargetImpl implements Target { return abilityController; } + @Override + public UUID getAffectedAbilityControllerId(UUID choosingPlayerId) { + // controller hints: + // - target.getTargetController(), this.getId(), choosingPlayerId -- player that must makes choices (must be same with this.getId) + // - target.getAbilityController(), abilityControllerId -- affected player/controller for all actions/filters + // - affected controller can be different from target controller (another player makes choices for controller) + // sometimes a target selection can be made from a player that does not control the ability + UUID abilityControllerId = choosingPlayerId; + if (this.getAbilityController() != null) { + abilityControllerId = this.getAbilityController(); + } + return abilityControllerId; + } + @Override public Player getTargetController(Game game, UUID playerId) { if (getTargetController() != null) { diff --git a/Mage/src/main/java/mage/target/Targets.java b/Mage/src/main/java/mage/target/Targets.java index 3ae7326bcdc..cba1f867cef 100644 --- a/Mage/src/main/java/mage/target/Targets.java +++ b/Mage/src/main/java/mage/target/Targets.java @@ -63,8 +63,8 @@ public class Targets extends ArrayList implements Copyable { return unchosenIndex < res.size() ? res.get(unchosenIndex) : null; } - public boolean isChoiceCompleted(Game game) { - return stream().allMatch(t -> t.isChoiceCompleted(game)); + public boolean isChoiceCompleted(UUID abilityControllerId, Ability source, Game game) { + return stream().allMatch(t -> t.isChoiceCompleted(abilityControllerId, source, game)); } public void clearChosen() { @@ -101,9 +101,7 @@ public class Targets extends ArrayList implements Copyable { // stop on cancel/done if (!target.choose(outcome, playerId, sourceId, source, game)) { - if (!target.isChosen(game)) { - break; - } + break; } // target done, can take next one diff --git a/Mage/src/main/java/mage/target/common/TargetAnyTarget.java b/Mage/src/main/java/mage/target/common/TargetAnyTarget.java index 87de24a32ab..47ad600a4f2 100644 --- a/Mage/src/main/java/mage/target/common/TargetAnyTarget.java +++ b/Mage/src/main/java/mage/target/common/TargetAnyTarget.java @@ -3,6 +3,8 @@ package mage.target.common; import mage.filter.common.FilterAnyTarget; /** + * Warning, it's a target for damage effects only (ignore lands, artifacts and other non-damageable objects) + * * @author JRHerlehy Created on 4/8/18. */ public class TargetAnyTarget extends TargetPermanentOrPlayer { @@ -13,20 +15,12 @@ public class TargetAnyTarget extends TargetPermanentOrPlayer { this(1); } - public TargetAnyTarget(FilterAnyTarget filter) { - this(1, 1, filter); - } - public TargetAnyTarget(int numTargets) { this(numTargets, numTargets); } public TargetAnyTarget(int minNumTargets, int maxNumTargets) { - this(minNumTargets, maxNumTargets, defaultFilter); - } - - public TargetAnyTarget(int minNumTargets, int maxNumTargets, FilterAnyTarget filter) { - super(minNumTargets, maxNumTargets, filter, false); + super(minNumTargets, maxNumTargets, defaultFilter, false); } protected TargetAnyTarget(final TargetAnyTarget target) { diff --git a/Mage/src/main/java/mage/target/common/TargetCardInGraveyardBattlefieldOrStack.java b/Mage/src/main/java/mage/target/common/TargetCardInGraveyardBattlefieldOrStack.java index 7257e334805..b86014f5cac 100644 --- a/Mage/src/main/java/mage/target/common/TargetCardInGraveyardBattlefieldOrStack.java +++ b/Mage/src/main/java/mage/target/common/TargetCardInGraveyardBattlefieldOrStack.java @@ -18,6 +18,7 @@ import java.util.Set; import java.util.UUID; /** + * * @author LevelX2 */ public class TargetCardInGraveyardBattlefieldOrStack extends TargetCard { @@ -97,7 +98,7 @@ public class TargetCardInGraveyardBattlefieldOrStack extends TargetCard { @Override public boolean canTarget(UUID id, Game game) { - return this.canTarget(null, id, null, game); + return this.canTarget(null, id, null, game); // wtf } @Override diff --git a/Mage/src/main/java/mage/target/common/TargetCardInLibrary.java b/Mage/src/main/java/mage/target/common/TargetCardInLibrary.java index cfb91500bec..a6c111bca01 100644 --- a/Mage/src/main/java/mage/target/common/TargetCardInLibrary.java +++ b/Mage/src/main/java/mage/target/common/TargetCardInLibrary.java @@ -76,10 +76,7 @@ public class TargetCardInLibrary extends TargetCard { Cards cardsId = new CardsImpl(); cards.forEach(cardsId::add); - UUID abilityControllerId = playerId; - if (this.getTargetController() != null && this.getAbilityController() != null) { - abilityControllerId = this.getAbilityController(); - } + UUID abilityControllerId = this.getAffectedAbilityControllerId(playerId); chosen = false; do { diff --git a/Mage/src/main/java/mage/target/common/TargetControlledCreaturePermanent.java b/Mage/src/main/java/mage/target/common/TargetControlledCreaturePermanent.java index 784e5e3d2a0..caccb2487e2 100644 --- a/Mage/src/main/java/mage/target/common/TargetControlledCreaturePermanent.java +++ b/Mage/src/main/java/mage/target/common/TargetControlledCreaturePermanent.java @@ -1,7 +1,6 @@ package mage.target.common; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledCreaturePermanent; /** * @author BetaSteward_at_googlemail.com @@ -17,15 +16,7 @@ public class TargetControlledCreaturePermanent extends TargetControlledPermanent } public TargetControlledCreaturePermanent(int minNumTargets, int maxNumTargets) { - this(minNumTargets, maxNumTargets, maxNumTargets > 1 ? StaticFilters.FILTER_CONTROLLED_CREATURES : StaticFilters.FILTER_CONTROLLED_CREATURE, false); - } - - public TargetControlledCreaturePermanent(FilterControlledCreaturePermanent filter) { - this(1, 1, filter, false); - } - - public TargetControlledCreaturePermanent(int minNumTargets, int maxNumTargets, FilterControlledCreaturePermanent filter, boolean notTarget) { - super(minNumTargets, maxNumTargets, filter, notTarget); + super(minNumTargets, maxNumTargets, maxNumTargets > 1 ? StaticFilters.FILTER_CONTROLLED_CREATURES : StaticFilters.FILTER_CONTROLLED_CREATURE, false); } protected TargetControlledCreaturePermanent(final TargetControlledCreaturePermanent target) { diff --git a/Mage/src/main/java/mage/target/common/TargetCreatureOrPlaneswalker.java b/Mage/src/main/java/mage/target/common/TargetCreatureOrPlaneswalker.java index ffb62653343..a4a717529e9 100644 --- a/Mage/src/main/java/mage/target/common/TargetCreatureOrPlaneswalker.java +++ b/Mage/src/main/java/mage/target/common/TargetCreatureOrPlaneswalker.java @@ -1,14 +1,8 @@ - package mage.target.common; -import mage.abilities.Ability; -import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; -import mage.game.Game; -import mage.players.Player; +import mage.filter.StaticFilters; import mage.target.TargetPermanent; -import java.util.UUID; - /** * @author LevelX2 */ @@ -23,11 +17,7 @@ public class TargetCreatureOrPlaneswalker extends TargetPermanent { } public TargetCreatureOrPlaneswalker(int minNumTargets, int maxNumTargets) { - this(minNumTargets, maxNumTargets, new FilterCreatureOrPlaneswalkerPermanent(), false); - } - - public TargetCreatureOrPlaneswalker(int minNumTargets, int maxNumTargets, FilterCreatureOrPlaneswalkerPermanent filter, boolean notTarget) { - super(minNumTargets, maxNumTargets, filter, notTarget); + super(minNumTargets, maxNumTargets, StaticFilters.FILTER_PERMANENT_CREATURE_OR_PLANESWALKER, false); } protected TargetCreatureOrPlaneswalker(final TargetCreatureOrPlaneswalker target) { @@ -38,17 +28,4 @@ public class TargetCreatureOrPlaneswalker extends TargetPermanent { public TargetCreatureOrPlaneswalker copy() { return new TargetCreatureOrPlaneswalker(this); } - - @Override - public boolean isLegal(Ability source, Game game) { - for (UUID playerId : targets.keySet()) { - Player targetPlayer = game.getPlayer(playerId); - if (targetPlayer != null) { - // there seems to be no possibility to add more predicates for theplayer so return here true - return true; - } - } - return super.isLegal(source, game); - } - } diff --git a/Mage/src/main/java/mage/target/common/TargetCreatureOrPlayer.java b/Mage/src/main/java/mage/target/common/TargetCreatureOrPlayer.java index 838e9a95a41..13cf4cd72ec 100644 --- a/Mage/src/main/java/mage/target/common/TargetCreatureOrPlayer.java +++ b/Mage/src/main/java/mage/target/common/TargetCreatureOrPlayer.java @@ -1,22 +1,17 @@ package mage.target.common; import mage.filter.common.FilterCreatureOrPlayer; +import mage.filter.common.FilterPermanentOrPlayer; /** * @author BetaSteward_at_googlemail.com */ public class TargetCreatureOrPlayer extends TargetPermanentOrPlayer { + private static final FilterPermanentOrPlayer filter = new FilterCreatureOrPlayer(); + public TargetCreatureOrPlayer() { - this(1, 1, new FilterCreatureOrPlayer()); - } - - public TargetCreatureOrPlayer(FilterCreatureOrPlayer filter) { - this(1, 1, filter); - } - - public TargetCreatureOrPlayer(int minNumTargets, int maxNumTargets, FilterCreatureOrPlayer filter) { - super(minNumTargets, maxNumTargets, filter, false); + super(1, 1, filter, false); } protected TargetCreatureOrPlayer(final TargetCreatureOrPlayer target) { @@ -27,5 +22,4 @@ public class TargetCreatureOrPlayer extends TargetPermanentOrPlayer { public TargetCreatureOrPlayer copy() { return new TargetCreatureOrPlayer(this); } - } diff --git a/Mage/src/main/java/mage/target/common/TargetCreaturePermanent.java b/Mage/src/main/java/mage/target/common/TargetCreaturePermanent.java index c7028a67508..17efca5ae8d 100644 --- a/Mage/src/main/java/mage/target/common/TargetCreaturePermanent.java +++ b/Mage/src/main/java/mage/target/common/TargetCreaturePermanent.java @@ -1,8 +1,6 @@ - package mage.target.common; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; import mage.target.TargetPermanent; /** @@ -14,20 +12,12 @@ public class TargetCreaturePermanent extends TargetPermanent { this(1); } - public TargetCreaturePermanent(FilterCreaturePermanent filter) { - this(1, 1, filter, false); - } - public TargetCreaturePermanent(int numTargets) { this(numTargets, numTargets); } public TargetCreaturePermanent(int minNumTargets, int maxNumTargets) { - this(minNumTargets, maxNumTargets, maxNumTargets > 1 ? StaticFilters.FILTER_PERMANENT_CREATURES : StaticFilters.FILTER_PERMANENT_CREATURE, false); - } - - public TargetCreaturePermanent(int minNumTargets, int maxNumTargets, FilterCreaturePermanent filter, boolean notTarget) { - super(minNumTargets, maxNumTargets, filter, notTarget); + super(minNumTargets, maxNumTargets, maxNumTargets > 1 ? StaticFilters.FILTER_PERMANENT_CREATURES : StaticFilters.FILTER_PERMANENT_CREATURE, false); } protected TargetCreaturePermanent(final TargetCreaturePermanent target) { diff --git a/Mage/src/main/java/mage/target/common/TargetCreaturePermanentWithDifferentTypes.java b/Mage/src/main/java/mage/target/common/TargetCreaturePermanentWithDifferentTypes.java deleted file mode 100644 index 74013310160..00000000000 --- a/Mage/src/main/java/mage/target/common/TargetCreaturePermanentWithDifferentTypes.java +++ /dev/null @@ -1,49 +0,0 @@ - -package mage.target.common; - -import mage.abilities.Ability; -import mage.filter.common.FilterCreaturePermanent; -import mage.game.Game; -import mage.game.permanent.Permanent; - -import java.util.UUID; - -/** - * @author LevelX2 - */ -public class TargetCreaturePermanentWithDifferentTypes extends TargetCreaturePermanent { - - public TargetCreaturePermanentWithDifferentTypes(int minNumTargets, int maxNumTargets, FilterCreaturePermanent filter, boolean notTarget) { - super(minNumTargets, maxNumTargets, filter, notTarget); - } - - protected TargetCreaturePermanentWithDifferentTypes(final TargetCreaturePermanentWithDifferentTypes target) { - super(target); - } - - @Override - public TargetCreaturePermanentWithDifferentTypes copy() { - return new TargetCreaturePermanentWithDifferentTypes(this); - } - - @Override - public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (super.canTarget(controllerId, id, source, game)) { - Permanent creature = game.getPermanent(id); - if (creature != null) { - for (Object object : getTargets()) { - UUID targetId = (UUID) object; - Permanent selectedCreature = game.getPermanent(targetId); - if (selectedCreature != null - && !creature.getId().equals(selectedCreature.getId())) { - if (creature.shareCreatureTypes(game, selectedCreature)) { - return false; - } - } - } - return true; - } - } - return false; - } -} diff --git a/Mage/src/main/java/mage/target/common/TargetDiscard.java b/Mage/src/main/java/mage/target/common/TargetDiscard.java index 4e732d8ba09..299319b30c3 100644 --- a/Mage/src/main/java/mage/target/common/TargetDiscard.java +++ b/Mage/src/main/java/mage/target/common/TargetDiscard.java @@ -1,18 +1,16 @@ - package mage.target.common; -import mage.constants.Zone; import mage.abilities.Ability; import mage.cards.Card; +import mage.constants.Zone; import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.predicate.card.OwnerIdPredicate; import mage.game.Game; import mage.target.TargetCard; import java.util.UUID; -import mage.filter.StaticFilters; -import mage.filter.predicate.card.OwnerIdPredicate; - /** * @author BetaSteward_at_googlemail.com */ @@ -54,5 +52,4 @@ public class TargetDiscard extends TargetCard { public TargetDiscard copy() { return new TargetDiscard(this); } - } diff --git a/Mage/src/main/java/mage/target/common/TargetOpponentOrPlaneswalker.java b/Mage/src/main/java/mage/target/common/TargetOpponentOrPlaneswalker.java index d30b65d64e8..3fc95ab5fc9 100644 --- a/Mage/src/main/java/mage/target/common/TargetOpponentOrPlaneswalker.java +++ b/Mage/src/main/java/mage/target/common/TargetOpponentOrPlaneswalker.java @@ -1,25 +1,28 @@ package mage.target.common; import mage.filter.common.FilterOpponentOrPlaneswalker; +import mage.filter.common.FilterPermanentOrPlayer; /** * @author LevelX2 */ public class TargetOpponentOrPlaneswalker extends TargetPermanentOrPlayer { + private static final FilterPermanentOrPlayer filter = new FilterOpponentOrPlaneswalker(); + public TargetOpponentOrPlaneswalker() { this(1); } - public TargetOpponentOrPlaneswalker(FilterOpponentOrPlaneswalker filter) { - this(1, 1, filter, false); - } - public TargetOpponentOrPlaneswalker(int numTargets) { - this(numTargets, numTargets, new FilterOpponentOrPlaneswalker("opponent or planeswalker"), false); + this(numTargets, numTargets); } - public TargetOpponentOrPlaneswalker(int minNumTargets, int maxNumTargets, FilterOpponentOrPlaneswalker filter, boolean notTarget) { + public TargetOpponentOrPlaneswalker(int minNumTargets, int maxNumTargets) { + this(minNumTargets, maxNumTargets, false); + } + + public TargetOpponentOrPlaneswalker(int minNumTargets, int maxNumTargets, boolean notTarget) { super(minNumTargets, maxNumTargets, filter, notTarget); } diff --git a/Mage/src/main/java/mage/target/targetadjustment/DefineByTriggerTargetAdjuster.java b/Mage/src/main/java/mage/target/targetadjustment/DefineByTriggerTargetAdjuster.java new file mode 100644 index 00000000000..e0e9e741805 --- /dev/null +++ b/Mage/src/main/java/mage/target/targetadjustment/DefineByTriggerTargetAdjuster.java @@ -0,0 +1,19 @@ +package mage.target.targetadjustment; + +import mage.abilities.Ability; +import mage.game.Game; + +/** + * Use this to indicate that the targets are dynamically added via the Ability directly + * While still satisfying the Verify target check + * + * @author notgreat + */ +public enum DefineByTriggerTargetAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + //Do nothing + } +} diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index 8cd26e37641..abc4f0bbe53 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -44,7 +44,6 @@ import mage.game.permanent.PermanentMeld; import mage.game.permanent.PermanentToken; import mage.game.permanent.token.Token; import mage.game.stack.Spell; -import mage.game.stack.StackObject; import mage.players.Player; import mage.players.PlayerList; import mage.target.Target; @@ -85,7 +84,7 @@ public final class CardUtil { public static final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS"); private static final List costWords = Arrays.asList( - "put", "return", "exile", "discard", "sacrifice", "remove", "tap", "reveal", "pay", "collect", "forage" + "put", "return", "exile", "discard", "mill", "sacrifice", "remove", "tap", "reveal", "pay", "have", "collect", "forage" ); // search set code in commands like "set_code-card_name" @@ -1133,49 +1132,6 @@ public final class CardUtil { return res; } - /** - * For finding the spell or ability on the stack for "becomes the target" triggers. - * Also ensures that spells/abilities that target the same object twice only trigger each "becomes the target" ability once. - * If this is the first attempt at triggering for a given ability targeting a given object, - * this method records that in the game state for later checks by this same method, to not return the same object again. - * - * @param checkingReference must be unique for each usage (this.getId().toString() of the TriggeredAbility, or this.getKey() of the watcher) - * @param event the GameEvent.EventType.TARGETED from checkTrigger() or watch() - * @param game the Game from checkTrigger() or watch() - * @return the StackObject which targeted the source, or null if already used or not found - */ - public static StackObject findTargetingStackObject(String checkingReference, GameEvent event, Game game) { - // In case of multiple simultaneous triggered abilities from the same source, - // need to get the actual one that targeted, see #8026, #8378, rulings for Battle Mammoth - // In case of copied triggered abilities, need to trigger on each independently, see #13498 - // Also avoids triggering on cancelled selections, see #8802 - String stateKey = "targetedMap" + checkingReference; - Map> targetMap = (Map>) game.getState().getValue(stateKey); - // targetMap: key - targetId; value - Set of stackObject Ids - if (targetMap == null) { - targetMap = new HashMap<>(); - } else { - targetMap = new HashMap<>(targetMap); // must have new object reference if saved back to game state - } - Set targetingObjects = targetMap.computeIfAbsent(event.getTargetId(), k -> new HashSet<>()); - for (StackObject stackObject : game.getStack()) { - Ability stackAbility = stackObject.getStackAbility(); - if (stackAbility == null || !stackAbility.getSourceId().equals(event.getSourceId())) { - continue; - } - if (CardUtil.getAllSelectedTargets(stackAbility, game).contains(event.getTargetId())) { - if (!targetingObjects.add(stackObject.getId())) { - continue; // The trigger/watcher already recorded that target of the stack object, check for another - } - // Otherwise, store this combination of trigger/watcher + target + stack object - targetMap.put(event.getTargetId(), targetingObjects); - game.getState().setValue(stateKey, targetMap); - return stackObject; - } - } - return null; - } - /** * For overriding `canTarget()` with usages such as "any number of target cards with total mana value X or less". * Call this after super.canTarget() returns true. @@ -1600,7 +1556,7 @@ public final class CardUtil { return result; } - private static boolean checkForPlayable(Cards cards, FilterCard filter, Ability source, Player player, Game game, SpellCastTracker spellCastTracker, boolean playLand) { + private static boolean cardsHasCastableParts(Cards cards, FilterCard filter, Ability source, Player player, Game game, SpellCastTracker spellCastTracker, boolean playLand) { return cards .getCards(game) .stream() @@ -1624,19 +1580,40 @@ public final class CardUtil { CardUtil.castSpellWithAttributesForFree(player, source, game, cards, filter); return; } - int spellsCast = 0; + int castCount = 0; + int maxCastCount = Integer.min(cards.size(), maxSpells); cards.removeZone(Zone.STACK, game); - while (player.canRespond() && spellsCast < maxSpells && !cards.isEmpty()) { - if (CardUtil.castSpellWithAttributesForFree(player, source, game, cards, filter, spellCastTracker, playLand)) { - spellsCast++; - cards.removeZone(Zone.STACK, game); - } else if (!checkForPlayable( - cards, filter, source, player, game, spellCastTracker, playLand - ) || !player.chooseUse( - Outcome.PlayForFree, "Continue casting spells?", source, game - )) { + if (!cardsHasCastableParts(cards, filter, source, player, game, spellCastTracker, playLand)) { + return; + } + + while (player.canRespond()) { + boolean wasCast = CardUtil.castSpellWithAttributesForFree(player, source, game, cards, filter, spellCastTracker, playLand); + + // nothing to cast + cards.removeZone(Zone.STACK, game); + if (cards.isEmpty() || !cardsHasCastableParts(cards, filter, source, player, game, spellCastTracker, playLand)) { break; } + + if (wasCast) { + // no more tries to cast + castCount++; + if (castCount >= maxCastCount) { + break; + } + } else { + // player want to cancel + if (player.isComputer()) { + // AI can't choose good spell, so stop + break; + } else { + // Human can choose wrong spell part, so allow to continue + if (!player.chooseUse(Outcome.PlayForFree, "Continue casting spells?", source, game)) { + break; + } + } + } } } diff --git a/Mage/src/main/java/mage/util/DebugUtil.java b/Mage/src/main/java/mage/util/DebugUtil.java index 4c090a4557e..fcad86ea034 100644 --- a/Mage/src/main/java/mage/util/DebugUtil.java +++ b/Mage/src/main/java/mage/util/DebugUtil.java @@ -17,6 +17,12 @@ public class DebugUtil { public static boolean AI_ENABLE_DEBUG_MODE = false; public static boolean AI_SHOW_TARGET_OPTIMIZATION_LOGS = false; // works with target amount + // SERVER + // data collectors - enable additional logs and data collection for better AI and human games debugging + public static boolean TESTS_DATA_COLLECTORS_ENABLE_SAVE_GAME_HISTORY = false; // WARNING, for debug only, can generate too much files + public static boolean SERVER_DATA_COLLECTORS_ENABLE_PRINT_GAME_LOGS = false; + public static boolean SERVER_DATA_COLLECTORS_ENABLE_SAVE_GAME_HISTORY = false; + // GAME // print detail target info for activate/cast/trigger only, not a single choose dialog // can be useful to debug unit tests, auto-choose or AI @@ -68,16 +74,24 @@ public class DebugUtil { public static String NETWORK_PROFILE_REQUESTS_DUMP_FILE_NAME = "httpRequests.log"; /** - * Return method and source line number like "secondMethod - DebugUtilTest.java:21" + * Return source line number for better debugging like "secondMethod - DebugUtilTest.java:21" * - * @param skipMethodsAmount use 0 to return current method info, use 1 for prev method, use 2 for prev-prev method + * @param skipMethodsAmount use 0 to return current method info, use 1 for prev method, use 2 for prev-prev method, etc + * @param infoType use "class" for full class name and "method" for short method name */ - public static String getMethodNameWithSource(final int skipMethodsAmount) { + public static String getMethodNameWithSource(int skipMethodsAmount, String infoType) { // 3 is default methods amount to skip: // - getMethodNameWithSource // - TraceHelper.getMethodNameWithSource // - Thread.currentThread().getStackTrace() - return TraceHelper.getMethodNameWithSource(3 + skipMethodsAmount); + switch (infoType) { + case "class": + return TraceHelper.getClassNameWithSource(3 + skipMethodsAmount); + case "method": + return TraceHelper.getMethodNameWithSource(3 + skipMethodsAmount); + default: + throw new IllegalArgumentException("Unknown info type: " + infoType); + } } } @@ -88,6 +102,9 @@ public class DebugUtil { */ class TraceHelper { + /** + * Example: showDialog - ChooseTargetTestableDialog.java:72 + */ public static String getMethodNameWithSource(final int depth) { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); if (stackTrace.length == 0) { @@ -96,4 +113,17 @@ class TraceHelper { return String.format("%s - %s:%d", stackTrace[depth].getMethodName(), stackTrace[depth].getFileName(), stackTrace[depth].getLineNumber()); } } + + /** + * Compatible with IntelliJ IDEA's logs navigation (will be clickable) + * Example: mage.utils.testers.ChooseTargetTestableDialog(ChooseTargetTestableDialog.java:62) + */ + public static String getClassNameWithSource(final int depth) { + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + if (stackTrace.length == 0) { + return "[no access to stack]"; + } else { + return String.format("%s(%s:%d)", stackTrace[depth].getClassName(), stackTrace[depth].getFileName(), stackTrace[depth].getLineNumber()); + } + } } \ No newline at end of file diff --git a/Mage/src/main/java/mage/util/FuzzyTestsUtil.java b/Mage/src/main/java/mage/util/FuzzyTestsUtil.java new file mode 100644 index 00000000000..1c7f29a43b6 --- /dev/null +++ b/Mage/src/main/java/mage/util/FuzzyTestsUtil.java @@ -0,0 +1,90 @@ +package mage.util; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.EntersBattlefieldEffect; +import mage.abilities.keyword.PhasingAbility; +import mage.cards.Card; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.Map; +import java.util.UUID; + +/** + * Helper class for fuzzy testing + *

+ * Support: + * - [x] enable by command line; + * - [x] phased out permanents must be hidden + * - [ ] TODO: out of range players and permanents must be hidden + * - [ ] TODO: leave/disconnected players must be hidden + *

+ * How-to use: + * - enable here or by command line + * - run unit tests and research the fails + * + * @author JayDi85 + */ +public class FuzzyTestsUtil { + + /** + * Phased out permanents must be hidden + * Make sure other cards and effects do not see phased out permanents and ignore it + *

+ * Use case: + * - each permanent on battlefield will have copied phased out version with all abilities and effects + *

+ * How-to use: + * - set true or run with -Dxmage.tests.addRandomPhasedOutPermanents=true + */ + public static boolean ADD_RANDOM_PHASED_OUT_PERMANENTS = false; + + static { + String val = System.getProperty("xmage.tests.addRandomPhasedOutPermanents"); + if (val != null) { + ADD_RANDOM_PHASED_OUT_PERMANENTS = Boolean.parseBoolean(val); + } + } + + /** + * Create duplicated phased out permanent + */ + public static void addRandomPhasedOutPermanent(Permanent originalPermanent, Ability source, Game game) { + if (!ADD_RANDOM_PHASED_OUT_PERMANENTS) { + return; + } + Player samplePlayer = game.getPlayers().values().stream().findFirst().orElse(null); + if (samplePlayer == null || !samplePlayer.isTestMode()) { + return; + } + + // copy permanent and put it to battlefield as phased out (diff sides also supported here) + // TODO: add phased out tests support (must not fail on it) + Card originalCardSide = game.getCard(originalPermanent.getId()); + Card originalCardMain = originalCardSide.getMainCard(); + if (!originalCardMain.hasAbility(PhasingAbility.getInstance(), game)) { + boolean canCreate = true; + Card doppelgangerCardMain = game.copyCard(originalCardMain, source, originalPermanent.getControllerId()); + Map mapOldToNew = CardUtil.getOriginalToCopiedPartsMap(originalCardMain, doppelgangerCardMain); + Card doppelgangerCardSide = (Card) mapOldToNew.getOrDefault(originalCardSide.getId(), null); + doppelgangerCardSide.addAbility(PhasingAbility.getInstance()); + + // compatibility workaround: remove all etb abilities to skip any etb choices (e.g. copy effect) + doppelgangerCardSide.getAbilities().removeIf(a -> a.getEffects().stream().anyMatch(e -> e instanceof EntersBattlefieldEffect)); + // compatibility workaround: ignore aura to skip any etb choices (e.g. select new target) + if (doppelgangerCardSide.hasSubtype(SubType.AURA, game)) { + canCreate = false; + } + + if (canCreate) { + doppelgangerCardSide.putOntoBattlefield(game, Zone.BATTLEFIELD, source, originalPermanent.getControllerId()); + Permanent doppelgangerPerm = CardUtil.getPermanentFromCardPutToBattlefield(doppelgangerCardSide, game); + doppelgangerPerm.phaseOut(game, true); // use indirect, so no phase in on untap + } + } + } +} diff --git a/Mage/src/main/java/mage/watchers/WatcherUtils.java b/Mage/src/main/java/mage/watchers/WatcherUtils.java deleted file mode 100644 index b90425706c6..00000000000 --- a/Mage/src/main/java/mage/watchers/WatcherUtils.java +++ /dev/null @@ -1,20 +0,0 @@ - -package mage.watchers; - -import mage.MageObject; -import mage.abilities.Ability; -import mage.game.Game; -import org.apache.log4j.Logger; - -/** - * - * @author LevelX2 - */ -public final class WatcherUtils { - - public static void logMissingWatcher(Game game, Ability source, Class watcherClass, Class usingClass) { - MageObject sourceObject = source.getSourceObject(game); - Logger.getLogger(usingClass).error("Needed watcher is not started " + watcherClass.getSimpleName() - + " - " + (sourceObject == null ? " no source object" : sourceObject.getName())); - } -} diff --git a/Mage/src/main/java/mage/watchers/common/BlockedAttackerWatcher.java b/Mage/src/main/java/mage/watchers/common/BlockedAttackerWatcher.java index 1ceae3d0172..3b4beba4aca 100644 --- a/Mage/src/main/java/mage/watchers/common/BlockedAttackerWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/BlockedAttackerWatcher.java @@ -1,9 +1,8 @@ package mage.watchers.common; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; +import java.util.stream.Collectors; + import mage.MageObjectReference; import mage.constants.WatcherScope; import mage.game.Game; @@ -17,7 +16,9 @@ import mage.watchers.Watcher; */ public class BlockedAttackerWatcher extends Watcher { - private final Map> blockData = new HashMap<>(); + // key: blocking creatures + // value: set of creatures blocked + private final Map> blockerMap = new HashMap<>(); /** * Game default watcher @@ -29,31 +30,31 @@ public class BlockedAttackerWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.BLOCKER_DECLARED) { - MageObjectReference blocker = new MageObjectReference(event.getSourceId(), game); - Set blockedAttackers = blockData.get(blocker); - if (blockedAttackers != null) { - blockedAttackers.add(new MageObjectReference(event.getTargetId(), game)); - } else { - blockedAttackers = new HashSet<>(); - blockedAttackers.add(new MageObjectReference(event.getTargetId(), game)); - blockData.put(blocker, blockedAttackers); - } + blockerMap.computeIfAbsent(new MageObjectReference(event.getSourceId(), game), k -> new HashSet<>()) + .add(new MageObjectReference(event.getTargetId(), game)); } } @Override public void reset() { super.reset(); - blockData.clear(); + blockerMap.clear(); } public boolean creatureHasBlockedAttacker(Permanent attacker, Permanent blocker, Game game) { - Set blockedAttackers = blockData.get(new MageObjectReference(blocker, game)); - return blockedAttackers != null && blockedAttackers.contains(new MageObjectReference(attacker, game)); + return blockerMap.getOrDefault(new MageObjectReference(blocker, game), Collections.emptySet()) + .contains(new MageObjectReference(attacker, game)); } - public boolean creatureHasBlockedAttacker(MageObjectReference attacker, MageObjectReference blocker, Game game) { - Set blockedAttackers = blockData.get(blocker); - return blockedAttackers != null && blockedAttackers.contains(attacker); + public boolean creatureHasBlockedAttacker(MageObjectReference attacker, MageObjectReference blocker) { + return blockerMap.getOrDefault(blocker, Collections.emptySet()).contains(attacker); + } + + public Set getBlockedCreatures(MageObjectReference blocker, Game game) { + return blockerMap.getOrDefault(blocker, Collections.emptySet()) + .stream() + .map(m -> m.getPermanent(game)) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); } } diff --git a/Mage/src/main/java/mage/watchers/common/ManaPaidSourceWatcher.java b/Mage/src/main/java/mage/watchers/common/ManaPaidSourceWatcher.java index c3921737ceb..01fe3ba122b 100644 --- a/Mage/src/main/java/mage/watchers/common/ManaPaidSourceWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/ManaPaidSourceWatcher.java @@ -37,6 +37,7 @@ public class ManaPaidSourceWatcher extends Watcher { private int colorlessSnow = 0; private int treasure = 0; private int creature = 0; + private int artifact = 0; private ManaPaidTracker() { super(); @@ -52,6 +53,7 @@ public class ManaPaidSourceWatcher extends Watcher { this.colorlessSnow = tracker.colorlessSnow; this.treasure = tracker.treasure; this.creature = tracker.creature; + this.artifact = tracker.artifact; } @Override @@ -67,6 +69,9 @@ public class ManaPaidSourceWatcher extends Watcher { if (sourceObject != null && sourceObject.isCreature(game)) { creature++; } + if (sourceObject != null && sourceObject.isArtifact(game)) { + artifact++; + } if (sourceObject != null && !sourceObject.isSnow(game)) { return; } @@ -157,6 +162,11 @@ public class ManaPaidSourceWatcher extends Watcher { return watcher == null ? 0 : watcher.manaMap.getOrDefault(sourceId, emptyTracker).creature; } + public static int getArtifactPaid(UUID sourceId, Game game) { + ManaPaidSourceWatcher watcher = game.getState().getWatcher(ManaPaidSourceWatcher.class); + return watcher == null ? 0 : watcher.manaMap.getOrDefault(sourceId, emptyTracker).artifact; + } + public static int getSnowPaid(UUID sourceId, Game game) { ManaPaidSourceWatcher watcher = game.getState().getWatcher(ManaPaidSourceWatcher.class); return watcher == null ? 0 : watcher.manaMap.getOrDefault(sourceId, emptyTracker).getSnow(); diff --git a/Mage/src/main/java/mage/watchers/common/NumberOfTimesPermanentTargetedATurnWatcher.java b/Mage/src/main/java/mage/watchers/common/NumberOfTimesPermanentTargetedATurnWatcher.java index b8e031bca49..08e5276cac2 100644 --- a/Mage/src/main/java/mage/watchers/common/NumberOfTimesPermanentTargetedATurnWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/NumberOfTimesPermanentTargetedATurnWatcher.java @@ -6,7 +6,6 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.stack.StackObject; -import mage.util.CardUtil; import mage.watchers.Watcher; import java.util.HashMap; @@ -29,7 +28,7 @@ public class NumberOfTimesPermanentTargetedATurnWatcher extends Watcher { if (event.getType() != GameEvent.EventType.TARGETED) { return; } - StackObject targetingObject = CardUtil.findTargetingStackObject(this.getKey(), event, game); + StackObject targetingObject = game.findTargetingStackObject(this.getKey(), event); if (targetingObject == null) { return; } diff --git a/Mage/src/main/java/mage/watchers/common/PlayerAttackedWatcher.java b/Mage/src/main/java/mage/watchers/common/PlayerAttackedWatcher.java index c806e4d68cb..d0695883859 100644 --- a/Mage/src/main/java/mage/watchers/common/PlayerAttackedWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PlayerAttackedWatcher.java @@ -1,16 +1,14 @@ - - package mage.watchers.common; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - import mage.constants.WatcherScope; import mage.game.Game; import mage.game.events.GameEvent; import mage.watchers.Watcher; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** * @author LevelX2 */ diff --git a/Mage/src/main/java/mage/watchers/common/VoidWatcher.java b/Mage/src/main/java/mage/watchers/common/VoidWatcher.java new file mode 100644 index 00000000000..a355438a857 --- /dev/null +++ b/Mage/src/main/java/mage/watchers/common/VoidWatcher.java @@ -0,0 +1,56 @@ +package mage.watchers.common; + +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.watchers.Watcher; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * TODO: this doesn't handle warp yet + * + * @author TheElk801 + */ +public class VoidWatcher extends Watcher { + + // need to track separately for each player as it needs to be in range + private final Set players = new HashSet<>(); + + public VoidWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + switch (event.getType()) { + case SPELL_CAST: + return; + case ZONE_CHANGE: + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (Zone.BATTLEFIELD.match(zEvent.getFromZone()) + && zEvent.getTarget() != null + && !zEvent.getTarget().isLand(game)) { + players.addAll(game.getState().getPlayersInRange(zEvent.getTarget().getControllerId(), game)); + } + } + } + + @Override + public void reset() { + super.reset(); + players.clear(); + } + + public static boolean checkPlayer(UUID playerId, Game game) { + return game + .getState() + .getWatcher(VoidWatcher.class) + .players + .contains(playerId); + } +} diff --git a/Mage/src/main/resources/tokens-database.txt b/Mage/src/main/resources/tokens-database.txt index d7858933b16..8d2ac7f751d 100644 --- a/Mage/src/main/resources/tokens-database.txt +++ b/Mage/src/main/resources/tokens-database.txt @@ -145,6 +145,7 @@ |Generate|EMBLEM:INR|Emblem Tamiyo|||TamiyoFieldResearcherEmblem| |Generate|EMBLEM:INR|Emblem Wrenn|||WrennAndSevenEmblem| |Generate|EMBLEM:DFT|Emblem Chandra|||ChandraSparkHunterEmblem| +|Generate|EMBLEM:FIN|Emblem Sephiroth|||SephirothOneWingedAngelEmblem| # ALL PLANES @@ -530,6 +531,9 @@ # DGM |Generate|TOK:DGM|Elemental|||VoiceOfResurgenceToken| +# DIS +|Generate|TOK:DIS|Elemental|||ResearchDevelopmentToken| + # DKA |Generate|TOK:DKA|Human|||HumanToken| |Generate|TOK:DKA|Vampire|||SorinLordOfInnistradVampireToken| @@ -1136,6 +1140,9 @@ |Generate|TOK:ELD|Rat|||RatToken| |Generate|TOK:ELD|Wolf|||GarrukCursedHuntsmanToken| +# UND +|Generate|TOK:UND|Goblin|||GoblinToken| + # THB |Generate|TOK:THB|Elemental|||PurphorossInterventionToken| |Generate|TOK:THB|Goat|||GoatToken| @@ -1520,12 +1527,18 @@ |Generate|TOK:SLD|Food|3||FoodToken| |Generate|TOK:SLD|Food|4||FoodToken| |Generate|TOK:SLD|Food|5||FoodToken| +|Generate|TOK:SLD|Food|6||FoodToken| |Generate|TOK:SLD|Goblin|||GoblinToken| |Generate|TOK:SLD|Hydra|||ZaxaraTheExemplaryHydraToken| |Generate|TOK:SLD|Icingdeath, Frost Tongue|||IcingdeathFrostTongueToken| |Generate|TOK:SLD|Marit Lage|||MaritLageToken| |Generate|TOK:SLD|Mechtitan|||MechtitanToken| +|Generate|TOK:SLD|Myr|||MyrToken| |Generate|TOK:SLD|Saproling|||SaprolingToken| +|Generate|TOK:SLD|Shapeshifter|1||ShapeshifterBlueToken| +|Generate|TOK:SLD|Shapeshifter|2||ShapeshifterBlueToken| +|Generate|TOK:SLD|Shapeshifter|3||ShapeshifterBlueToken| +|Generate|TOK:SLD|Shapeshifter|4||ShapeshifterBlueToken| |Generate|TOK:SLD|Shrine|||ShrineToken| |Generate|TOK:SLD|Spirit|1||SpiritWhiteToken| |Generate|TOK:SLD|Spirit|2||SpiritToken| @@ -1534,6 +1547,8 @@ |Generate|TOK:SLD|Treasure|2||TreasureToken| |Generate|TOK:SLD|Treasure|3||TreasureToken| |Generate|TOK:SLD|Treasure|4||TreasureToken| +|Generate|TOK:SLD|Treasure|5||TreasureToken| +|Generate|TOK:SLD|Treasure|6||TreasureToken| |Generate|TOK:SLD|Walker|1||WalkerToken| |Generate|TOK:SLD|Walker|2||WalkerToken| |Generate|TOK:SLD|Walker|3||WalkerToken| @@ -1920,6 +1935,12 @@ |Generate|TOK:40K|Tyranid Gargoyle|||TyranidGargoyleToken| |Generate|TOK:40K|Tyranid Warrior|||TyranidWarriorToken| +# UNF +|Generate|TOK:UNF|Clown Robot|1||ClownRobotToken| +|Generate|TOK:UNF|Clown Robot|2||ClownRobotToken| +|Generate|TOK:UNF|Storm Crow|||StormCrowToken| +|Generate|TOK:UNF|Squirrel|||SquirrelToken| + # BRO |Generate|TOK:BRO|Bear|||BearToken| |Generate|TOK:BRO|Construct|1||KarnConstructToken| @@ -2214,26 +2235,20 @@ |Generate|TOK:WOE|Young Hero|||YoungHeroRoleToken| # WOC -|Generate|TOK:WOC|Cat|1||CatToken2| -|Generate|TOK:WOC|Cat|2||CatToken| -|Generate|TOK:WOC|Elephant|||ElephantToken| |Generate|TOK:WOC|Faerie|||FaerieToken| |Generate|TOK:WOC|Faerie Rogue|1||FaerieRogueToken| |Generate|TOK:WOC|Faerie Rogue|2||OonaQueenFaerieRogueToken| -|Generate|TOK:WOC|Human Monk|||HumanMonkToken| |Generate|TOK:WOC|Human Soldier|||HumanSoldierToken| |Generate|TOK:WOC|Monster|||MonsterRoleToken| -|Generate|TOK:WOC|Ox|||OxToken| |Generate|TOK:WOC|Pegasus|||PegasusToken2| |Generate|TOK:WOC|Pirate|||NettlingNuisancePirateToken| |Generate|TOK:WOC|Royal|||RoyalRoleToken| |Generate|TOK:WOC|Saproling|||SaprolingToken| -|Generate|TOK:WOC|Sorcerer|||SorcererRoleToken| -|Generate|TOK:WOC|Spirit|||WhiteBlackSpiritToken| |Generate|TOK:WOC|Virtuous|||VirtuousRoleToken| # WHO |Generate|TOK:WHO|Alien|||AlienToken| +|Generate|TOK:WHO|Alien Angel|||AlienAngelToken| |Generate|TOK:WHO|Alien Insect|||AlienInsectToken| |Generate|TOK:WHO|Alien Rhino|||AlienRhinoToken| |Generate|TOK:WHO|Alien Salamander|||AlienSalamanderToken| @@ -2270,7 +2285,7 @@ |Generate|TOK:PIP|Human Knight|||ThePrydwenSteelFlagshipHumanKnightToken| |Generate|TOK:PIP|Human Soldier|||HumanSoldierToken| |Generate|TOK:PIP|Junk|||JunkToken| -|Generate|TOK:PIP|Robot|||RobotToken| +|Generate|TOK:PIP|Robot|||Robot33Token| |Generate|TOK:PIP|Settlement|||SettlementToken| |Generate|TOK:PIP|Soldier|1||SoldierTokenWithHaste| |Generate|TOK:PIP|Soldier|2||SoldierToken| @@ -2736,7 +2751,8 @@ |Generate|TOK:TDC|Gold|||GoldToken| |Generate|TOK:TDC|Human|||HumanToken| |Generate|TOK:TDC|Inkling|||InklingToken| -|Generate|TOK:TDC|Insect|||InsectToken| +|Generate|TOK:TDC|Insect|1||InsectToken| +|Generate|TOK:TDC|Insect|2||InsectDeathToken| |Generate|TOK:TDC|Karox Bladewing|||KaroxBladewingToken| |Generate|TOK:TDC|Myr|||MyrToken| |Generate|TOK:TDC|Plant|||PlantToken| @@ -2748,6 +2764,7 @@ |Generate|TOK:TDC|Spider|||SpiderToken| |Generate|TOK:TDC|Spirit|||SpiritWhiteToken| |Generate|TOK:TDC|Thopter|||ThopterColorlessToken| +|Generate|TOK:TDC|Wall|||Wall13Token| # ACR |Generate|TOK:ACR|Assassin|||AssassinMenaceToken| @@ -2764,17 +2781,61 @@ |Generate|TOK:DSK|Everywhere|||EverywhereToken| |Generate|TOK:DSK|Glimmer|||GlimmerToken| |Generate|TOK:DSK|Gremlin|||Gremlin11Token| +|Generate|TOK:DSK|Horror|||HorrorEnchantmentCreatureToken| |Generate|TOK:DSK|Insect|1||InsectBlackGreenFlyingToken| |Generate|TOK:DSK|Insect|2||InsectWhiteToken| |Generate|TOK:DSK|Primo, the Indivisible|||PrimoTheIndivisibleToken| |Generate|TOK:DSK|Shard|||ShardToken| |Generate|TOK:DSK|Spider|||Spider22Token| -|Generate|TOK:DSK|Spirit|||SpiritBlueToken| +|Generate|TOK:DSK|Spirit|1||Spirit31Token| +|Generate|TOK:DSK|Spirit|2||SpiritBlueToken| |Generate|TOK:DSK|Treasure|||TreasureToken| # FIN |Generate|TOK:FIN|Food|||FoodToken| -|Generate|TOK:FIN|Hero|||HeroToken| +|Generate|TOK:FIN|Hero|1||HeroToken| +|Generate|TOK:FIN|Hero|2||HeroToken| +|Generate|TOK:FIN|Hero|3||HeroToken| +|Generate|TOK:FIN|Hero|4||HeroToken| +|Generate|TOK:FIN|Hero|5||HeroToken| +|Generate|TOK:FIN|Hero|6||HeroToken| +|Generate|TOK:FIN|Hero|7||HeroToken| +|Generate|TOK:FIN|Hero|8||HeroToken| +|Generate|TOK:FIN|Hero|9||HeroToken| +|Generate|TOK:FIN|Hero|10||HeroToken| +|Generate|TOK:FIN|Hero|11||HeroToken| +|Generate|TOK:FIN|Hero|12||HeroToken| +|Generate|TOK:FIN|Hero|13||HeroToken| +|Generate|TOK:FIN|Hero|14||HeroToken| +|Generate|TOK:FIN|Hero|15||HeroToken| +|Generate|TOK:FIN|Hero|16||HeroToken| +|Generate|TOK:FIN|Knight|||WaylayToken| +|Generate|TOK:FIN|Moogle|1||MoogleToken| +|Generate|TOK:FIN|Moogle|2||MoogleToken| +|Generate|TOK:FIN|Robot|||RobotBlueToken| +|Generate|TOK:FIN|Horror|||Horror3Token| +|Generate|TOK:FIN|Wizard|1||BlackWizardToken| +|Generate|TOK:FIN|Wizard|2||BlackWizardToken| +|Generate|TOK:FIN|Wizard|3||BlackWizardToken| +|Generate|TOK:FIN|Bird|1||ChocoboToken| +|Generate|TOK:FIN|Bird|2||ChocoboToken| +|Generate|TOK:FIN|Frog|||FrogGreenToken| +|Generate|TOK:FIN|Angelo|||AngeloToken| +|Generate|TOK:FIN|Darkstar|||DarkstarToken| +|Generate|TOK:FIN|Elemental|||ElementalAllColorsToken| +|Generate|TOK:FIN|Treasure|1||TreasureToken| +|Generate|TOK:FIN|Treasure|2||TreasureToken| + +# FIN +|Generate|TOK:FIC|Human Soldier|||HumanSoldierToken| +|Generate|TOK:FIC|Soldier|||SoldierToken| +|Generate|TOK:FIC|Spirit|||SpiritWhiteToken| +|Generate|TOK:FIC|Bird|||BirdVigilanceToken| +|Generate|TOK:FIC|Squid|||SquidToken| +|Generate|TOK:FIC|Zombie|||ZombieToken| +|Generate|TOK:FIC|Rebel|||RebelRedToken| +|Generate|TOK:FIC|The Blackjack|||TheBlackjackToken| +|Generate|TOK:FIC|Clue|||ClueArtifactToken| # JVC |Generate|TOK:JVC|Elemental Shaman|||ElementalShamanToken| @@ -2786,6 +2847,7 @@ # UGL |Generate|TOK:UGL|Goblin|||GoblinToken| |Generate|TOK:UGL|Pegasus|||PegasusToken| +|Generate|TOK:UGL|Rabid Sheep|||RabidSheepToken| |Generate|TOK:UGL|Soldier|||SoldierToken| |Generate|TOK:UGL|Squirrel|||SquirrelToken| |Generate|TOK:UGL|Zombie|||ZombieToken| diff --git a/Utils/keywords.txt b/Utils/keywords.txt index ea6b857b8ce..5dd4945cf5d 100644 --- a/Utils/keywords.txt +++ b/Utils/keywords.txt @@ -128,6 +128,7 @@ Spectacle|card, cost| Spree|card| Squad|cost| Start your engines!|new| +Station|new| Storm|new| Sunburst|new| Suspend|number, cost, card| @@ -147,4 +148,5 @@ Unleash|new| Vanishing|number| Vigilance|instance| Ward|cost| +Warp|card, manaString| Wither|instance| diff --git a/Utils/known-sets.txt b/Utils/known-sets.txt index 1a0b1a4d250..41e5637f9c5 100644 --- a/Utils/known-sets.txt +++ b/Utils/known-sets.txt @@ -18,6 +18,7 @@ Arena League|ArenaLeague| Asia Pacific Land Program|AsiaPacificLandProgram| Assassin's Creed|AssassinsCreed| Avacyn Restored|AvacynRestored| +Avatar: The Last Airbender|AvatarTheLastAirbender| Battlebond|Battlebond| Battle for Zendikar|BattleForZendikar| Betrayers of Kamigawa|BetrayersOfKamigawa| @@ -86,6 +87,8 @@ Duel Decks: Zendikar vs. Eldrazi|DuelDecksZendikarVsEldrazi| Duels of the Planeswalkers|DuelsOfThePlaneswalkers| Duskmourn: House of Horror|DuskmournHouseOfHorror| Duskmourn: House of Horror Commander|DuskmournHouseOfHorrorCommander| +Edge of Eternities|EdgeOfEternities| +Edge of Eternities Commander|EdgeOfEternitiesCommander| Eighth Edition|EighthEdition| Eldritch Moon|EldritchMoon| Eternal Masters|EternalMasters| diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 21675cca7f4..a9cbc8ae37d 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -59108,3 +59108,157 @@ Green Goblin, Nemesis|Marvel's Spider-Man Eternal|23|R|{2}{B}{R}|Legendary Creat Doc Ock, Evil Inventor|Marvel's Spider-Man Eternal|24|R|{5}{U}{B}|Legendary Creature - Human Scientist Villain|8|8|At the beginning of combat on your turn, target noncreature artifact you control becomes an 8/8 Robot Villain artifact creature in addition to its other types.| Sensational Spider-Man|Marvel's Spider-Man Eternal|25|R|{1}{W}{U}|Legendary Creature - Spider Human Hero|3|3|Whenever Sensational Spider-Man attacks, tap target creature defending player controls and put a stun counter on it. Then you may remove up to three stun counters from among all permanents. Draw cards equal to the number of stun counters removed this way.| Pumpkin Bombs|Marvel's Spider-Man Eternal|26|R|{1}{R}|Artifact|||{T}, Discard two cards: Draw three cards, then put a fuse counter on this artifact. It deals damage equal to the number of fuse counters on it to target opponent. They gain control of this artifact.| +Anticausal Vestige|Edge of Eternities|1|R|{6}|Creature - Eldrazi|7|5|When this creature leaves the battlefield, draw a card, then you may put a permanent card with mana value less than or equal to the number of lands you control from your hand onto the battlefield tapped.$Warp {4}| +Tezzeret, Cruel Captain|Edge of Eternities|2|M|{3}|Legendary Planeswalker - Tezzeret|4|Whenever an artifact you control enters, put a loyalty counter on Tezzeret.$0: Untap target artifact or creature. If it's an artifact creature, put a +1/+1 counter on it.$-3: Search your library for an artifact card with mana value 1 or less, reveal it, put it into your hand, then shuffle.$-7: You get an emblem with "At the beginning of combat on your turn, put three +1/+1 counters on target artifact you control. If it's not a creature, it becomes a 0/0 Robot artifact creature."| +Astelli Reclaimer|Edge of Eternities|4|R|{3}{W}{W}|Creature - Angel Warrior|5|4|Flying$When this creature enters, return target noncreature, nonland permanent card with mana value X or less from your graveyard to the battlefield, where X is the amount of mana spent to cast this creature.$Warp {2}{W}| +Banishing Light|Edge of Eternities|6|C|{2}{W}|Enchantment|||When this enchantment enters, exile target nonland permanent an opponent controls until this enchantment leaves the battlefield.| +Emergency Eject|Edge of Eternities|14|U|{2}{W}|Instant|||Destroy target nonland permanent. Its controller creates a Lander token.| +Exalted Sunborn|Edge of Eternities|15|M|{3}{W}{W}|Creature - Angel Wizard|4|5|Flying, lifelink$If one or more tokens would be created under your control, twice that many of those tokens are created instead.$Warp {1}{W}| +Haliya, Guided by Light|Edge of Eternities|19|R|{2}{W}|Legendary Creature - Human Soldier|3|3|Whenever Haliya or another creature or artifact you control enters, you gain 1 life.$At the beginning of your end step, draw a card if you've gained 3 or more life this turn.$Warp {W}| +The Seriema|Edge of Eternities|35|R|{1}{W}{W}|Legendary Artifact - Spacecraft|||When The Seriema enters, search your library for a legendary creature card, reveal it, put it into your hand, then shuffle.$Station$STATION 7+$Flying$Other tapped legendary creatures you control have indestructible.$5/5| +Starfield Shepherd|Edge of Eternities|37|U|{3}{W}{W}|Creature - Angel|3|2|Flying$When this creature enters, search your library for a basic Plains card or a creature card with mana value 1 or less, reveal it, put it into your hand, then shuffle.$Warp {1}{W}| +Starfighter Pilot|Edge of Eternities|38|C|{1}{W}|Creature - Human Pilot|2|2|Whenever this creature becomes tapped, surveil 1.| +Emissary Escort|Edge of Eternities|56|R|{1}{U}|Artifact Creature - Robot Soldier|0|4|This creature gets +X/+0 where X is the greatest mana value among other artifacts you control.| +Mechanozoa|Edge of Eternities|66|C|{4}{U}{U}|Artifact Creature - Robot Jellyfish|5|5|When this creature enters, tap target artifact or creature an opponent controls and put a stun counter on it.$Warp {2}{U}| +Quantum Riddler|Edge of Eternities|72|M|{3}{U}{U}|Creature - Sphinx|4|6|Flying$When this creature enters, draw a card.$As long as you have one or fewer cards in hand, if you would draw one or more cards, you draw that many cards plus one instead.$Warp {1}{U}| +Starbreach Whale|Edge of Eternities|77|C|{4}{U}|Creature - Whale|3|5|Flying$When this creature enters, surveil 2.$Warp {1}{U}| +Starfield Vocalist|Edge of Eternities|78|R|{3}{U}|Creature - Human Bard|3|4|If a permanent entering the battlefield causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.$Warp {1}{U}| +Archenemy's Charm|Edge of Eternities|88|R|{B}{B}{B}|Instant|||Choose one --$* Exile target creature or planeswalker.$* Return one or two target creature and/or planeswalker cards from your graveyard to your hand.$* Put two +1/+1 counters on target creature you control. It gains lifelink until end of turn.| +Decode Transmissions|Edge of Eternities|94|C|{2}{B}|Sorcery|||You draw two cards and lose 2 life. Void If a nonland permanent left the battlefield this turn or a spell was warped this turn, instead you draw two cards and each opponent loses 2 life.| +Elegy Acolyte|Edge of Eternities|97|R|{2}{B}{B}|Creature - Human Cleric|4|4|Lifelink$Whenever one or more creatures you control deal combat damage to a player, you draw a card and lose 1 life.$Void -- At the beginning of your end step, if a nonland permanent left the battlefield this turn or a spell was warped this turn, create a 2/2 colorless Robot artifact creature token.| +Embrace Oblivion|Edge of Eternities|98|C|{B}|Sorcery|||As an additional cost to cast this spell, sacrifice an artifact or creature.$Destroy target creature or Spacecraft.| +Insatiable Skittermaw|Edge of Eternities|108|C|{2}{B}|Creature - Insect Horror|2|2|Menace$Void -- At the beginning of your end step, if a nonland permanent left the battlefield this turn or a spell was warped this turn, put a +1/+1 counter on this creature.| +Sothera, the Supervoid|Edge of Eternities|115|M|{2}{B}{B}|Legendary Enchantment|||Whenever a creature you control dies, each opponent chooses a creature they control and exiles it.$At the beginning of your end step, if a player controls no creatures, sacrifice Sothera, then put a creature card exiled with it onto the battlefield under your control with two additional +1/+1 counters on it.| +Sunset Saboteur|Edge of Eternities|116|R|{1}{B}|Creature - Human Rogue|4|1|Menace$Ward--Discard a card.$Whenever this creature attacks, put a +1/+1 counter on target creature an opponent controls.| +Temporal Intervention|Edge of Eternities|120|C|{2}{B}|Sorcery|||Void -- This spell costs {2} less to cast if a nonland permanent left the battlefield this turn or a spell was warped this turn.$Target opponent reveals their hand. You choose a nonland card from it. That player discards that card.| +Timeline Culler|Edge of Eternities|121|U|{B}{B}|Creature - Drix Warlock|2|2|Haste$You may cast this card from your graveyard using its warp ability.$Warp--{B}, Pay 2 life.| +Tragic Trajectory|Edge of Eternities|122|U|{B}|Sorcery|||Target creature gets -2/-2 until end of turn.$Void -- That creature gets -10/-10 until end of turn instead if a nonland permanent left the battlefield this turn or a spell was warped this turn.| +Voidforged Titan|Edge of Eternities|125|U|{4}{B}|Artifact Creature - Robot Warrior|5|4|Void -- At the beginning of your end step, if a nonland permanent left the battlefield this turn or a spell was warped this turn, you draw a card and lose 1 life.| +Kav Landseeker|Edge of Eternities|138|C|{3}{R}|Creature - Kavu Soldier|4|3|Menace$When this creature enters, create a Lander token. At the beginning of the end step on your next turn, sacrifice that token.| +Nova Hellkite|Edge of Eternities|148|R|{3}{R}{R}|Creature - Dragon|4|5|Flying, haste$When this creature enters, it deals 1 damage to target creature an opponent controls.$Warp {2}{R}| +Red Tiger Mechan|Edge of Eternities|154|C|{3}{R}|Artifact Creature - Robot Cat|3|3|Haste$Warp {1}{R}| +Rust Harvester|Edge of Eternities|159|R|{R}|Artifact Creature - Robot|1|1|Menace 2${2},{T}, Exile an artifact card from your graveyard: Put a +1/+1 counter on this creature, then it deals damage equal to its power to any target.| +Weapons Manufacturing|Edge of Eternities|168|R|{1}{R}|Enchantment|||Whenever a nontoken artifact you control enters, create a colorless artifact token named Munitions with "When this token leaves the battlefield, it deals 2 damage to any target."| +Weftstalker Ardent|Edge of Eternities|169|U|{2}{R}|Creature - Drix Artificer|2|3|Whenever another creature or artifact you control enters, this creature deals 1 damage to each opponent.$Warp {R}| +Eusocial Engineering|Edge of Eternities|181|U|{3}{G}{G}|Enchantment|||Landfall -- Whenever a land you control enters, create a 2/2 colorless Robot artifact creature token.$Warp {1}{G}| +Frenzied Baloth|Edge of Eternities|183|R|{G}{G}|Creature - Beast|3|2|This spell can't be countered.$Trample, haste$Creature spells you control can't be countered.$Combat damage can't be prevented.| +Galactic Wayfarer|Edge of Eternities|185|C|{2}{G}|Creature - Human Scout|3|3|When this creature enters, create a Lander token.| +Harmonious Grovestrider|Edge of Eternities|189|U|{3}{G}{G}|Creature - Beast|*|*|Ward {2}$This creature's power and toughness are each equal to the number of lands you control.| +Ouroboroid|Edge of Eternities|201|M|{2}{G}{G}|Creature - Plant Wurm|1|3|At the beginning of combat on your turn, put X +1/+1 counters on each creature you control, where X is this creature's power.| +Seedship Impact|Edge of Eternities|205|U|{1}{G}|Instant|||Destroy target artifact or enchantment. If its mana value was 2 or less, create a Lander token.| +Shattered Wings|Edge of Eternities|206|C|{2}{G}|Sorcery|||Destroy target artifact, enchantment, or creature with flying. Surveil 1.| +Terrasymbiosis|Edge of Eternities|210|R|{2}{G}|Enchantment|||Whenever you put one or more +1/+1 counters on a creature you control, you may draw that many cards. Do this only once each turn.| +Alpharael, Dreaming Acolyte|Edge of Eternities|212|U|{1}{U}{B}|Legendary Creature - Human Cleric|2|3|When Alpharael enters, draw two cards. Then discard two cards unless you discard an artifact card.$During your turn, Alpharael has deathtouch.| +Biotech Specialist|Edge of Eternities|214|R|{R}{G}|Creature - Insect Scientist|1|3|When this creature enters, create a Lander token. (It's an artifact with "{2}, {T}, Sacrifice this token: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle."$ Whenever you sacrifice an artifact, this creature deals 2 damage to target opponent.| +Cosmogoyf|Edge of Eternities|215|R|{B}{G}|Creature - Elemental Lhurgoyf|*|1+*|This creature's power is equal to the number of cards you own in exile and its toughness is equal to that number plus 1.| +Genemorph Imago|Edge of Eternities|217|R|{G}{U}|Creature - Insect Druid|1|3|Flying$Landfall -- Whenever a land you control enters, target creature has base power and toughness 3/3 until end of turn. If you control six or more lands, that creature has base power and toughness 6/6 until end of turn instead.| +Infinite Guideline Station|Edge of Eternities|219|R|{W}{U}{B}{R}{G}|Legendary Artifact - Spacecraft|||When Infinite Guideline Station enters, create a tapped 2/2 colorless Robot artifact creature token for each multicolored permanent you control.$Station$STATION 12+$Flying$Whenever Infinite Guideline Station attacks, draw a card for each multicolored permanent you control.$7/15| +Mutinous Massacre|Edge of Eternities|222|R|{3}{B}{B}{R}{R}|Sorcery|||Choose odd or even. Destroy each creature with mana value of the chosen quality. Then gain control of all creatures until end of turn. Untap them. They gain haste until end of turn.| +Ragost, Deft Gastronaut|Edge of Eternities|224|R|{R}{W}|Legendary Creature - Lobster Citizen|2|2|Artifacts you control are Foods in addition to their other types and have "2, {T}, Sacrifice this artifact: You gain 3 life."${1}, {T}, Sacrifice a Food: Ragost deals 3 damage to each opponent.$At the beginning of each end step, if you gained life this turn, untap Ragost.| +Sami, Ship's Engineer|Edge of Eternities|225|U|{2}{R}{W}|Legendary Creature - Human Artificer|2|4|At the beginning of your end step, if you control two or more tapped creatures, create a tapped 2/2 colorless Robot artifact creature token.| +Sami, Wildcat Captain|Edge of Eternities|226|M|{4}{R}{W}|Legendary Creature - Human Artificer Rogue|4|4|Double strike, vigilance$Spells you cast have affinity for artifacts.| +Singularity Rupture|Edge of Eternities|228|R|{3}{U}{B}{B}|Sorcery|||Destroy all creatures, then any number of target players each mill half their library, rounded down.| +Syr Vondam, the Lucent|Edge of Eternities|232|U|{2}{W}{B}{B}|Legendary Creature - Human Knight|4|4|Deathtouch, lifelink$Whenever Syr Vondam enters or attacks, other creatures you control get +1/+0 and gain deathtouch until end of turn.| +Tannuk, Memorial Ensign|Edge of Eternities|233|U|{1}{R}{G}|Legendary Creature - Kavu Pilot|2|4|Landfall -- Whenever a land you control enters, Tannuk deals 1 damage to each opponent. If this is the second time this ability has resolved this turn, draw a card.| +Bygone Colossus|Edge of Eternities|235|U|{9}|Artifact Creature - Robot Giant|9|9|Warp {3}| +Chrome Companion|Edge of Eternities|236|C|{2}|Artifact Creature - Dog|2|1|Whenever this creature becomes tapped, you gain 1 life.${2},{T}: Put target card from a graveyard on the bottom of its owner's library.| +The Endstone|Edge of Eternities|240|M|{7}|Legendary Artifact|||Whenever you play a land or cast a spell, draw a card.$At the beginning of your end step, your life total becomes half your starting life total, rounded up.| +The Eternity Elevator|Edge of Eternities|241|R|{5}|Legendary Artifact - Spacecraft|||{T}: Add {C}{C}{C}$Station$STATION 20+${T}: Add X mana of any one color, where X is the number of charge counters on The Eternity Elevator.| +Extinguisher Battleship|Edge of Eternities|242|R|{8}|Artifact - Spacecraft|||When this Spacecraft enters, destroy target noncreature permanent. Then this Spacecraft deals 4 damage to each creature.$Station$STATION 5+$Flying, trample$10/10| +Thrumming Hivepool|Edge of Eternities|247|R|{6}|Artifact|||Affinity for Slivers$Slivers you control have double strike and haste.$At the beginning of your upkeep, create two 1/1 colorless Sliver creature tokens.| +Virulent Silencer|Edge of Eternities|248|U|{3}|Artifact Creature - Robot Assassin|2|3|Whenever a nontoken artifact creature you control deals combat damage to a player, that player gets two poison counters.| +Wurmwall Sweeper|Edge of Eternities|249|C|{2}|Artifact - Spacecraft|||When this Spacecraft enters, surveil 2.$Station$STATION 4+$Flying$2/2| +Breeding Pool|Edge of Eternities|251|R||Land - Forest Island|||({T}: Add {G} or {U}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Command Bridge|Edge of Eternities|252|C||Land|||This land enters tapped.$When this land enters, sacrifice it unless you tap an untapped permanent you control.${T}: Add one mana of any color.| +Godless Shrine|Edge of Eternities|254|R||Land - Plains Swamp|||({T}: Add {W} or {B}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Sacred Foundry|Edge of Eternities|256|R||Land - Mountain Plains|||({T}: Add {R} or {W}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Stomping Ground|Edge of Eternities|258|R||Land - Mountain Forest|||({T}: Add {R} or {G}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Susur Secundi, Void Altar|Edge of Eternities|259|M||Land - Planet|||This land enters tapped.${T}: Add {B}.$Station$STATION 12+${1}{B},{T}, Pay 2 life, Sacrifice a creature: Draw cards equal to the sacrificed creature's power. Activate only as a sorcery.| +Uthros, Titanic Godcore|Edge of Eternities|260|M||Land - Planet|||This land enters tapped.${T}: Add {U}.$Station$STATION 12+${U},{T}: Add {U} for each artifact you control.| +Watery Grave|Edge of Eternities|261|R||Land - Island Swamp|||({T}: Add {U} or {B}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Plains|Edge of Eternities|262|C||Basic Land - Plains|||({T}: Add {W}.)| +Island|Edge of Eternities|263|C||Basic Land - Island|||({T}: Add {U}.)| +Swamp|Edge of Eternities|264|C||Basic Land - Swamp|||({T}: Add {B}.)| +Mountain|Edge of Eternities|265|C||Basic Land - Mountain|||({T}: Add {R}.)| +Forest|Edge of Eternities|266|C||Basic Land - Forest|||({T}: Add {G}.)| +Plains|Edge of Eternities|267|C||Basic Land - Plains|||({T}: Add {W}.)| +Plains|Edge of Eternities|268|C||Basic Land - Plains|||({T}: Add {W}.)| +Island|Edge of Eternities|269|C||Basic Land - Island|||({T}: Add {U}.)| +Island|Edge of Eternities|270|C||Basic Land - Island|||({T}: Add {U}.)| +Swamp|Edge of Eternities|271|C||Basic Land - Swamp|||({T}: Add {B}.)| +Swamp|Edge of Eternities|272|C||Basic Land - Swamp|||({T}: Add {B}.)| +Mountain|Edge of Eternities|273|C||Basic Land - Mountain|||({T}: Add {R}.)| +Mountain|Edge of Eternities|274|C||Basic Land - Mountain|||({T}: Add {R}.)| +Forest|Edge of Eternities|275|C||Basic Land - Forest|||({T}: Add {G}.)| +Forest|Edge of Eternities|276|C||Basic Land - Forest|||({T}: Add {G}.)| +Breeding Pool|Edge of Eternities|278|R||Land - Forest Island|||({T}: Add {G} or {U}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Godless Shrine|Edge of Eternities|280|R||Land - Plains Swamp|||({T}: Add {W} or {B}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Sacred Foundry|Edge of Eternities|282|R||Land - Mountain Plains|||({T}: Add {R} or {W}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Stomping Ground|Edge of Eternities|283|R||Land - Mountain Forest|||({T}: Add {R} or {G}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Susur Secundi, Void Altar|Edge of Eternities|284|M||Land - Planet|||This land enters tapped.${T}: Add {B}.$Station$STATION 12+${1}{B},{T}, Pay 2 life, Sacrifice a creature: Draw cards equal to the sacrificed creature's power. Activate only as a sorcery.| +Uthros, Titanic Godcore|Edge of Eternities|285|M||Land - Planet|||This land enters tapped.${T}: Add {U}.$Station$STATION 12+${U},{T}: Add {U} for each artifact you control.| +Watery Grave|Edge of Eternities|286|R||Land - Island Swamp|||({T}: Add {U} or {B}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Tezzeret, Cruel Captain|Edge of Eternities|287|M|{3}|Legendary Planeswalker - Tezzeret|4|Whenever an artifact you control enters, put a loyalty counter on Tezzeret.$0: Untap target artifact or creature. If it's an artifact creature, put a +1/+1 counter on it.$-3: Search your library for an artifact card with mana value 1 or less, reveal it, put it into your hand, then shuffle.$-7: You get an emblem with "At the beginning of combat on your turn, put three +1/+1 counters on target artifact you control. If it's not a creature, it becomes a 0/0 Robot artifact creature."| +Astelli Reclaimer|Edge of Eternities|288|R|{3}{W}{W}|Creature - Angel Warrior|5|4|Flying$When this creature enters, return target noncreature, nonland permanent card with mana value X or less from your graveyard to the battlefield, where X is the amount of mana spent to cast this creature.$Warp {2}{W}| +Haliya, Guided by Light|Edge of Eternities|289|R|{2}{W}|Legendary Creature - Human Soldier|3|3|Whenever Haliya or another creature or artifact you control enters, you gain 1 life.$At the beginning of your end step, draw a card if you've gained 3 or more life this turn.$Warp {W}| +Elegy Acolyte|Edge of Eternities|293|R|{2}{B}{B}|Creature - Human Cleric|4|4|Lifelink$Whenever one or more creatures you control deal combat damage to a player, you draw a card and lose 1 life.$Void -- At the beginning of your end step, if a nonland permanent left the battlefield this turn or a spell was warped this turn, create a 2/2 colorless Robot artifact creature token.| +Genemorph Imago|Edge of Eternities|299|R|{G}{U}|Creature - Insect Druid|1|3|Flying$Landfall -- Whenever a land you control enters, target creature has base power and toughness 3/3 until end of turn. If you control six or more lands, that creature has base power and toughness 6/6 until end of turn instead.| +Ragost, Deft Gastronaut|Edge of Eternities|300|R|{R}{W}|Legendary Creature - Lobster Citizen|2|2|Artifacts you control are Foods in addition to their other types and have "2, {T}, Sacrifice this artifact: You gain 3 life."${1}, {T}, Sacrifice a Food: Ragost deals 3 damage to each opponent.$At the beginning of each end step, if you gained life this turn, untap Ragost.| +Sami, Wildcat Captain|Edge of Eternities|301|M|{4}{R}{W}|Legendary Creature - Human Artificer Rogue|4|4|Double strike, vigilance$Spells you cast have affinity for artifacts.| +Quantum Riddler|Edge of Eternities|305|M|{3}{U}{U}|Creature - Sphinx|4|6|Flying$When this creature enters, draw a card.$As long as you have one or fewer cards in hand, if you would draw one or more cards, you draw that many cards plus one instead.$Warp {1}{U}| +Archenemy's Charm|Edge of Eternities|307|R|{B}{B}{B}|Instant|||Choose one --$* Exile target creature or planeswalker.$* Return one or two target creature and/or planeswalker cards from your graveyard to your hand.$* Put two +1/+1 counters on target creature you control. It gains lifelink until end of turn.| +Nova Hellkite|Edge of Eternities|309|R|{3}{R}{R}|Creature - Dragon|4|5|Flying, haste$When this creature enters, it deals 1 damage to target creature an opponent controls.$Warp {2}{R}| +Rust Harvester|Edge of Eternities|310|R|{R}|Artifact Creature - Robot|1|1|Menace 2${2},{T}, Exile an artifact card from your graveyard: Put a +1/+1 counter on this creature, then it deals damage equal to its power to any target.| +Weapons Manufacturing|Edge of Eternities|311|R|{1}{R}|Enchantment|||Whenever a nontoken artifact you control enters, create a colorless artifact token named Munitions with "When this token leaves the battlefield, it deals 2 damage to any target."| +Terrasymbiosis|Edge of Eternities|312|R|{2}{G}|Enchantment|||Whenever you put one or more +1/+1 counters on a creature you control, you may draw that many cards. Do this only once each turn.| +Cosmogoyf|Edge of Eternities|313|R|{B}{G}|Creature - Elemental Lhurgoyf|*|1+*|This creature's power is equal to the number of cards you own in exile and its toughness is equal to that number plus 1.| +Mutinous Massacre|Edge of Eternities|314|R|{3}{B}{B}{R}{R}|Sorcery|||Choose odd or even. Destroy each creature with mana value of the chosen quality. Then gain control of all creatures until end of turn. Untap them. They gain haste until end of turn.| +Anticausal Vestige|Edge of Eternities|317|R|{6}|Creature - Eldrazi|7|5|When this creature leaves the battlefield, draw a card, then you may put a permanent card with mana value less than or equal to the number of lands you control from your hand onto the battlefield tapped.$Warp {4}| +Exalted Sunborn|Edge of Eternities|318|M|{3}{W}{W}|Creature - Angel Wizard|4|5|Flying, lifelink$If one or more tokens would be created under your control, twice that many of those tokens are created instead.$Warp {1}{W}| +The Seriema|Edge of Eternities|323|R|{1}{W}{W}|Legendary Artifact - Spacecraft|||When The Seriema enters, search your library for a legendary creature card, reveal it, put it into your hand, then shuffle.$Station$STATION 7+$Flying$Other tapped legendary creatures you control have indestructible.$5/5| +Emissary Escort|Edge of Eternities|326|R|{1}{U}|Artifact Creature - Robot Soldier|0|4|This creature gets +X/+0 where X is the greatest mana value among other artifacts you control.| +Starfield Vocalist|Edge of Eternities|328|R|{3}{U}|Creature - Human Bard|3|4|If a permanent entering the battlefield causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.$Warp {1}{U}| +Sunset Saboteur|Edge of Eternities|334|R|{1}{B}|Creature - Human Rogue|4|1|Menace$Ward--Discard a card.$Whenever this creature attacks, put a +1/+1 counter on target creature an opponent controls.| +Terminal Velocity|Edge of Eternities|338|R|{4}{R}{R}|Sorcery|||You may put an artifact or creature card from your hand onto the battlefield. That permanent gains haste, "When this permanent leaves the battlefield, it deals damage equal to its mana value to each creature," and "At the beginning of your end step, sacrifice this permanent."| +Frenzied Baloth|Edge of Eternities|342|R|{G}{G}|Creature - Beast|3|2|This spell can't be countered.$Trample, haste$Creature spells you control can't be countered.$Combat damage can't be prevented.| +Ouroboroid|Edge of Eternities|345|M|{2}{G}{G}|Creature - Plant Wurm|1|3|At the beginning of combat on your turn, put X +1/+1 counters on each creature you control, where X is this creature's power.| +Biotech Specialist|Edge of Eternities|347|R|{R}{G}|Creature - Insect Scientist|1|3|When this creature enters, create a Lander token. (It's an artifact with "{2}, {T}, Sacrifice this token: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle."$ Whenever you sacrifice an artifact, this creature deals 2 damage to target opponent.| +Infinite Guideline Station|Edge of Eternities|348|R|{W}{U}{B}{R}{G}|Legendary Artifact - Spacecraft|||When Infinite Guideline Station enters, create a tapped 2/2 colorless Robot artifact creature token for each multicolored permanent you control.$Station$STATION 12+$Flying$Whenever Infinite Guideline Station attacks, draw a card for each multicolored permanent you control.$7/15| +Singularity Rupture|Edge of Eternities|350|R|{3}{U}{B}{B}|Sorcery|||Destroy all creatures, then any number of target players each mill half their library, rounded down.| +The Endstone|Edge of Eternities|353|M|{7}|Legendary Artifact|||Whenever you play a land or cast a spell, draw a card.$At the beginning of your end step, your life total becomes half your starting life total, rounded up.| +The Eternity Elevator|Edge of Eternities|354|R|{5}|Legendary Artifact - Spacecraft|||{T}: Add {C}{C}{C}$Station$STATION 20+${T}: Add X mana of any one color, where X is the number of charge counters on The Eternity Elevator.| +Extinguisher Battleship|Edge of Eternities|355|R|{8}|Artifact - Spacecraft|||When this Spacecraft enters, destroy target noncreature permanent. Then this Spacecraft deals 4 damage to each creature.$Station$STATION 5+$Flying, trample$10/10| +Thrumming Hivepool|Edge of Eternities|356|R|{6}|Artifact|||Affinity for Slivers$Slivers you control have double strike and haste.$At the beginning of your upkeep, create two 1/1 colorless Sliver creature tokens.| +Anticausal Vestige|Edge of Eternities|357|M|{6}|Creature - Eldrazi|7|5|When this creature leaves the battlefield, draw a card, then you may put a permanent card with mana value less than or equal to the number of lands you control from your hand onto the battlefield tapped.$Warp {4}| +Exalted Sunborn|Edge of Eternities|358|M|{3}{W}{W}|Creature - Angel Wizard|4|5|Flying, lifelink$If one or more tokens would be created under your control, twice that many of those tokens are created instead.$Warp {1}{W}| +Starfield Vocalist|Edge of Eternities|359|M|{3}{U}|Creature - Human Bard|3|4|If a permanent entering the battlefield causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.$Warp {1}{U}| +Sothera, the Supervoid|Edge of Eternities|360|M|{2}{B}{B}|Legendary Enchantment|||Whenever a creature you control dies, each opponent chooses a creature they control and exiles it.$At the beginning of your end step, if a player controls no creatures, sacrifice Sothera, then put a creature card exiled with it onto the battlefield under your control with two additional +1/+1 counters on it.| +Mutinous Massacre|Edge of Eternities|363|M|{3}{B}{B}{R}{R}|Sorcery|||Choose odd or even. Destroy each creature with mana value of the chosen quality. Then gain control of all creatures until end of turn. Untap them. They gain haste until end of turn.| +The Endstone|Edge of Eternities|365|M|{7}|Legendary Artifact|||Whenever you play a land or cast a spell, draw a card.$At the beginning of your end step, your life total becomes half your starting life total, rounded up.| +Plains|Edge of Eternities|367|C||Basic Land - Plains|||({T}: Add {W}.)| +Island|Edge of Eternities|368|C||Basic Land - Island|||({T}: Add {U}.)| +Swamp|Edge of Eternities|369|C||Basic Land - Swamp|||({T}: Add {B}.)| +Mountain|Edge of Eternities|370|C||Basic Land - Mountain|||({T}: Add {R}.)| +Forest|Edge of Eternities|371|C||Basic Land - Forest|||({T}: Add {G}.)| +Breeding Pool|Edge of Eternities|373|R||Land - Forest Island|||({T}: Add {G} or {U}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Godless Shrine|Edge of Eternities|375|R||Land - Plains Swamp|||({T}: Add {W} or {B}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Sacred Foundry|Edge of Eternities|377|R||Land - Mountain Plains|||({T}: Add {R} or {W}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Stomping Ground|Edge of Eternities|378|R||Land - Mountain Forest|||({T}: Add {R} or {G}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Susur Secundi, Void Altar|Edge of Eternities|379|M||Land - Planet|||This land enters tapped.${T}: Add {B}.$Station$STATION 12+${1}{B},{T}, Pay 2 life, Sacrifice a creature: Draw cards equal to the sacrificed creature's power. Activate only as a sorcery.| +Uthros, Titanic Godcore|Edge of Eternities|380|M||Land - Planet|||This land enters tapped.${T}: Add {U}.$Station$STATION 12+${U},{T}: Add {U} for each artifact you control.| +Watery Grave|Edge of Eternities|381|R||Land - Island Swamp|||({T}: Add {U} or {B}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Sothera, the Supervoid|Edge of Eternities|382|M|{2}{B}{B}|Legendary Enchantment|||Whenever a creature you control dies, each opponent chooses a creature they control and exiles it.$At the beginning of your end step, if a player controls no creatures, sacrifice Sothera, then put a creature card exiled with it onto the battlefield under your control with two additional +1/+1 counters on it.| +Anticausal Vestige|Edge of Eternities|383|R|{6}|Creature - Eldrazi|7|5|When this creature leaves the battlefield, draw a card, then you may put a permanent card with mana value less than or equal to the number of lands you control from your hand onto the battlefield tapped.$Warp {4}| +Exalted Sunborn|Edge of Eternities|384|M|{3}{W}{W}|Creature - Angel Wizard|4|5|Flying, lifelink$If one or more tokens would be created under your control, twice that many of those tokens are created instead.$Warp {1}{W}| +Starfield Vocalist|Edge of Eternities|385|R|{3}{U}|Creature - Human Bard|3|4|If a permanent entering the battlefield causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.$Warp {1}{U}| +Sothera, the Supervoid|Edge of Eternities|386|M|{2}{B}{B}|Legendary Enchantment|||Whenever a creature you control dies, each opponent chooses a creature they control and exiles it.$At the beginning of your end step, if a player controls no creatures, sacrifice Sothera, then put a creature card exiled with it onto the battlefield under your control with two additional +1/+1 counters on it.| +Mutinous Massacre|Edge of Eternities|389|M|{3}{B}{B}{R}{R}|Sorcery|||Choose odd or even. Destroy each creature with mana value of the chosen quality. Then gain control of all creatures until end of turn. Untap them. They gain haste until end of turn.| +The Endstone|Edge of Eternities|391|M|{7}|Legendary Artifact|||Whenever you play a land or cast a spell, draw a card.$At the beginning of your end step, your life total becomes half your starting life total, rounded up.| +Singularity Rupture|Edge of Eternities|398|R|{3}{U}{B}{B}|Sorcery|||Destroy all creatures, then any number of target players each mill half their library, rounded down.| +Emissary Escort|Edge of Eternities|399|R|{1}{U}|Artifact Creature - Robot Soldier|0|4|This creature gets +X/+0 where X is the greatest mana value among other artifacts you control.| +Hearthhull, the Worldseed|Edge of Eternities Commander|1|M|{1}{B}{R}{G}|Legendary Artifact - Spacecraft|||Station$STATION 2+${1}, {T}, Sacrifice a land: Draw two cards. You may play an additional land this turn.$STATION 8+$Flying, vigilance, haste$Whenever you sacrifice a land, each opponent loses 2 life.$6/7| +Inspirit, Flagship Vessel|Edge of Eternities Commander|2|M|{U}{R}{W}|Legendary Artifact - Spacecraft|||Station$STATION 1+$At the beginning of combat on your turn, put your choice of a +1/+1 counter or two charge counters on up to one other target artifact.$STATION 8+$Flying$Other artifacts you control have hexproof and indestructible.$5/5| +Kilo, Apogee Mind|Edge of Eternities Commander|3|M|{U}{R}{W}|Legendary Artifact Creature - Robot Artificer|3|3|Haste$Whenever Kilo becomes tapped, proliferate.| +Szarel, Genesis Shepherd|Edge of Eternities Commander|4|M|{2}{B}{R}{G}|Legendary Creature - Insect Druid|2|5|Flying$You may play lands from your graveyard.$Whenever you sacrifice another nontoken permanent during your turn, put a number of +1/+1 counters equal to Szarel's power on up to one other target creature.| +Avatar Aang|Avatar: The Last Airbender|363|M|{R}{G}{W}{U}|Legendary Creature - Human Avatar Ally|4|4|Flying, firebending 2$Whenever you waterbend, earthbend, firebend, or airbend, draw a card. Then if you've done all four this turn, transform Avatar Aang.| +Aang, Master of Elements|Avatar: The Last Airbender|363|M||Legendary Creature - Avatar Ally|6|6|Flying$Spelsl you cast cost {W}{U}{B}{R}{G} less to cast.$At the beginning of each upkeep, you may transform Aang, Master of Elements. If you do, you gain 4 life, draw four cards, put four +1/+1 counters on him, and he deals 4 damage to each opponent.| diff --git a/Utils/mtg-sets-data.txt b/Utils/mtg-sets-data.txt index af90b04b5b6..2a0c35d220e 100644 --- a/Utils/mtg-sets-data.txt +++ b/Utils/mtg-sets-data.txt @@ -29,6 +29,7 @@ Anthologies|ATH| Antiquities|ATQ| Assassin's Creed|ACR| Avacyn Restored|AVR| +Avatar: The Last Airbender|TLA| Battle for Zendikar|BFZ| Battlebond|BBD| Born of the Gods|BNG| @@ -100,6 +101,8 @@ Darksteel|DST| Dragons of Tarkir|DTK| Archenemy: Nicol Bolas|E01| Explorers of Ixalan|E02| +Edge of Eternities|EOE| +Edge of Eternities Commander|EOC| Eternal Masters|EMA| Eldritch Moon|EMN| European Land Program|EURO| diff --git a/pom.xml b/pom.xml index 54f614ad154..a630bfc265d 100644 --- a/pom.xml +++ b/pom.xml @@ -270,8 +270,8 @@ org.slf4j - slf4j-log4j12 - 1.7.32 + slf4j-reload4j + 2.0.17 @@ -349,7 +349,7 @@ com.google.guava guava - 30.1.1-jre + 33.4.8-jre @@ -373,7 +373,7 @@ org.jsoup jsoup - 1.14.3 + 1.21.1