From e768c375dcf35b1a0163b677a13a9de12907caf5 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 14 Jan 2020 12:55:21 +0400 Subject: [PATCH 1/7] * Yorvo, Lord of Garenbrig - fixed that it doesn't add +1 counter is green creature dies before resolve; --- .../mage/cards/y/YorvoLordOfGarenbrig.java | 3 +- .../YorvoLordOfGarenbrigOnCommandersTest.java | 82 +++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/commander/duel/YorvoLordOfGarenbrigOnCommandersTest.java diff --git a/Mage.Sets/src/mage/cards/y/YorvoLordOfGarenbrig.java b/Mage.Sets/src/mage/cards/y/YorvoLordOfGarenbrig.java index d9cdc571ff..580cbdc595 100644 --- a/Mage.Sets/src/mage/cards/y/YorvoLordOfGarenbrig.java +++ b/Mage.Sets/src/mage/cards/y/YorvoLordOfGarenbrig.java @@ -17,6 +17,7 @@ import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.permanent.AnotherPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; import java.util.UUID; @@ -88,7 +89,7 @@ class YorvoLordOfGarenbrigEffect extends OneShotEffect { return false; } sourcePerm.addCounters(CounterType.P1P1.createInstance(), source, game); - Permanent permanent = game.getPermanentOrLKIBattlefield(targetPointer.getFirst(game, source)); + Permanent permanent = ((FixedTarget) targetPointer).getTargetedPermanentOrLKIBattlefield(game); if (permanent == null) { return true; } diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/duel/YorvoLordOfGarenbrigOnCommandersTest.java b/Mage.Tests/src/test/java/org/mage/test/commander/duel/YorvoLordOfGarenbrigOnCommandersTest.java new file mode 100644 index 0000000000..a9e7e1ed57 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/commander/duel/YorvoLordOfGarenbrigOnCommandersTest.java @@ -0,0 +1,82 @@ +package org.mage.test.commander.duel; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestCommanderDuelBase; + +/** + * @author JayDi85 + */ +public class YorvoLordOfGarenbrigOnCommandersTest extends CardTestCommanderDuelBase { + + @Test + public void test_TriggerOnSimpleCommander() { + // Yorvo, Lord of Garenbrig enters the battlefield with four +1/+1 counters on it. + // Whenever another green creature enters the battlefield under your control, put a +1/+1 counter on Yorvo. Then if that creature’s power is greater than Yorvo’s power, put another +1/+1 counter on Yorvo. + addCard(Zone.HAND, playerA, "Yorvo, Lord of Garenbrig", 5); // {G}{G}{G} + addCard(Zone.BATTLEFIELD, playerA, "Forest", 3); + // + addCard(Zone.COMMAND, playerA, "Aggressive Mammoth"); // {3}{G}{G}{G} + addCard(Zone.BATTLEFIELD, playerA, "Forest", 6); + + // prepare yorvo + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Yorvo, Lord of Garenbrig"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // cast commander + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Aggressive Mammoth"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkPermanentCounters("must get +2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Yorvo, Lord of Garenbrig", CounterType.P1P1, 4 + 2); + checkPermanentCount("must play commander", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Aggressive Mammoth", 1); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + @Test + public void test_TriggerOnUroTitalOfNaturesWrath() { + // Yorvo, Lord of Garenbrig enters the battlefield with four +1/+1 counters on it. + // Whenever another green creature enters the battlefield under your control, put a +1/+1 counter on Yorvo. Then if that creature’s power is greater than Yorvo’s power, put another +1/+1 counter on Yorvo. + addCard(Zone.HAND, playerA, "Yorvo, Lord of Garenbrig", 5); // {G}{G}{G} + addCard(Zone.BATTLEFIELD, playerA, "Forest", 3); + // + // When Uro enters the battlefield, sacrifice it unless it escaped. + // Whenever Uro enters the battlefield or attacks, you gain 3 life and draw a card, then you may put a land card from your hand onto the battlefield. + // Escape-{G}{G}{U}{U}, Exile five other cards from your graveyard. (You may cast this card from your graveyard for its escape cost.) + addCard(Zone.COMMAND, playerA, "Uro, Titan of Nature's Wrath"); // {1}{G}{U} + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + + // prepare yorvo + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Yorvo, Lord of Garenbrig"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // cast commander + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Uro, Titan of Nature's Wrath"); + + // If the entering green creature dies before Yorvo’s triggered ability resolves, use its power as it last + // existed on the battlefield to determine whether Yorvo gets a second +1/+1 counter. + // (2019-10-04) + + // order triggers to remove commander first + setChoice(playerA, "Whenever {this} enters the battlefield or attacks"); // draw trigger + setChoice(playerA, "Whenever another green creature enters the battlefield"); // get counters trigger + //setChoice(playerA, "When {this} enters the battlefield, sacrifice it"); // sacrifice trigger must be on top + + setChoice(playerA, "Yes"); // return commander to command zone + setChoice(playerA, "No"); // do not put land to battlefield + + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkPermanentCounters("must get +2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Yorvo, Lord of Garenbrig", CounterType.P1P1, 4 + 2); + checkCommandCardCount("return commander", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Uro, Titan of Nature's Wrath", 1); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } +} From 4c55fe701ef4c7c82f0f8de43f920e160fb05760 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 14 Jan 2020 18:21:45 +0400 Subject: [PATCH 2/7] UI: fixed rare error with game end dialog; --- .../mage/client/dialog/GameEndDialog.java | 553 +++++++++--------- 1 file changed, 276 insertions(+), 277 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/dialog/GameEndDialog.java b/Mage.Client/src/main/java/mage/client/dialog/GameEndDialog.java index 09c969b77d..94920b36ef 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/GameEndDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/GameEndDialog.java @@ -1,326 +1,325 @@ /* - * GameEndDialog.java - * - * Created on Jul 31, 2013, 9:41:00 AM - */ -package mage.client.dialog; + * GameEndDialog.java + * + * Created on Jul 31, 2013, 9:41:00 AM + */ + package mage.client.dialog; -import java.awt.Color; -import java.awt.Image; -import java.awt.Rectangle; -import java.awt.image.BufferedImage; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.PrintWriter; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import javax.swing.ImageIcon; -import javax.swing.JOptionPane; -import mage.client.MageFrame; -import mage.client.game.GamePanel; -import mage.client.util.Format; -import mage.client.util.ImageHelper; -import mage.client.util.audio.AudioManager; -import mage.client.util.gui.BufferedImageBuilder; -import mage.view.GameEndView; -import mage.view.PlayerView; + import mage.client.MageFrame; + import mage.client.game.GamePanel; + import mage.client.util.Format; + import mage.client.util.ImageHelper; + import mage.client.util.audio.AudioManager; + import mage.client.util.gui.BufferedImageBuilder; + import mage.view.GameEndView; + import mage.view.PlayerView; -/** - * - * @author LevelX2 - */ -public class GameEndDialog extends MageDialog { + import javax.swing.*; + import java.awt.*; + import java.awt.image.BufferedImage; + import java.io.File; + import java.io.FileNotFoundException; + import java.io.PrintWriter; + import java.text.DateFormat; + import java.text.SimpleDateFormat; + import java.util.Calendar; - private final DateFormat df = DateFormat.getDateTimeInstance(); + /** + * @author LevelX2 + */ + public class GameEndDialog extends MageDialog { - /** - * Creates new form GameEndDialog - * - * @param gameEndView - */ - public GameEndDialog(GameEndView gameEndView) { + private final DateFormat df = DateFormat.getDateTimeInstance(); - initComponents(); - this.modal = true; + /** + * Creates new form GameEndDialog + * + * @param gameEndView + */ + public GameEndDialog(GameEndView gameEndView) { - pnlText.setOpaque(true); - pnlText.setBackground(new Color(240, 240, 240, 140)); + initComponents(); + this.modal = true; - Rectangle r = new Rectangle(610, 250); - Image image = ImageHelper.getImageFromResources(gameEndView.hasWon() ? "/game_won.jpg" : "/game_lost.jpg"); - BufferedImage imageResult = ImageHelper.getResizedImage(BufferedImageBuilder.bufferImage(image, BufferedImage.TYPE_INT_ARGB), r); - ImageIcon icon = new ImageIcon(imageResult); - lblResultImage.setIcon(icon); + pnlText.setOpaque(true); + pnlText.setBackground(new Color(240, 240, 240, 140)); - this.lblGameInfo.setText(gameEndView.getGameInfo()); - this.lblMatchInfo.setText(gameEndView.getMatchInfo()); - this.lblAdditionalInfo.setText(gameEndView.getAdditionalInfo()); + Rectangle r = new Rectangle(610, 250); + Image image = ImageHelper.getImageFromResources(gameEndView.hasWon() ? "/game_won.jpg" : "/game_lost.jpg"); + BufferedImage imageResult = ImageHelper.getResizedImage(BufferedImageBuilder.bufferImage(image, BufferedImage.TYPE_INT_ARGB), r); + ImageIcon icon = new ImageIcon(imageResult); + lblResultImage.setIcon(icon); - String autoSave = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_LOG_AUTO_SAVE, "true"); - if (autoSave.equals("true")) { - this.saveGameLog(gameEndView); - } + this.lblGameInfo.setText(gameEndView.getGameInfo()); + this.lblMatchInfo.setText(gameEndView.getMatchInfo()); + this.lblAdditionalInfo.setText(gameEndView.getAdditionalInfo()); - // game duration - txtDurationGame.setText(" " + Format.getDuration(gameEndView.getStartTime(), gameEndView.getEndTime())); - txtDurationGame.setToolTipText(new StringBuilder(df.format(gameEndView.getStartTime())).append(" - ").append(df.format(gameEndView.getEndTime())).toString()); + String autoSave = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_LOG_AUTO_SAVE, "true"); + if (autoSave.equals("true")) { + this.saveGameLog(gameEndView); + } - // match duration - Calendar cal = Calendar.getInstance(); - txtDurationMatch.setText(" " + Format.getDuration(gameEndView.getMatchView().getStartTime(), cal.getTime())); - txtDurationMatch.setToolTipText(new StringBuilder(df.format(gameEndView.getMatchView().getStartTime())).append(" - ").append(df.format(cal.getTime())).toString()); + // game duration + txtDurationGame.setText(" " + Format.getDuration(gameEndView.getStartTime(), gameEndView.getEndTime())); + txtDurationGame.setToolTipText(new StringBuilder(df.format(gameEndView.getStartTime())).append(" - ").append(df.format(gameEndView.getEndTime())).toString()); - StringBuilder sb = new StringBuilder(" "); - for (PlayerView player : gameEndView.getPlayers()) { - sb.append(player.getName()).append(" Life: ").append(player.getLife()).append(' '); - } - this.txtLife.setText(sb.toString()); + // match duration + Calendar cal = Calendar.getInstance(); + txtDurationMatch.setText(" " + Format.getDuration(gameEndView.getMatchView().getStartTime(), cal.getTime())); + txtDurationMatch.setToolTipText(new StringBuilder(df.format(gameEndView.getMatchView().getStartTime())).append(" - ").append(df.format(cal.getTime())).toString()); - if (gameEndView.hasWon()) { - AudioManager.playPlayerWon(); - } else { - AudioManager.playPlayerLost(); - } + StringBuilder sb = new StringBuilder(" "); + for (PlayerView player : gameEndView.getPlayers()) { + sb.append(player.getName()).append(" Life: ").append(player.getLife()).append(' '); + } + this.txtLife.setText(sb.toString()); - txtMatchScore.setText(gameEndView.getMatchView().getResult()); - } + if (gameEndView.hasWon()) { + AudioManager.playPlayerWon(); + } else { + AudioManager.playPlayerLost(); + } - private void saveGameLog(GameEndView gameEndView) { - String dir = "gamelogs"; - File saveDir = new File(dir); - //Here comes the existence check - if (!saveDir.exists()) { - saveDir.mkdirs(); - } - // get game log - try { - GamePanel gamePanel = MageFrame.getGame(gameEndView.getMatchView().getGames().get(gameEndView.getMatchView().getGames().size() - 1)); - if (gamePanel != null) { - SimpleDateFormat sdf = new SimpleDateFormat(); - sdf.applyPattern("yyyyMMdd_HHmmss"); - String fileName = new StringBuilder(dir).append(File.separator) - .append(sdf.format(gameEndView.getStartTime())) - .append('_').append(gameEndView.getMatchView().getGameType()) - .append('_').append(gameEndView.getMatchView().getGames().size()) - .append(".txt").toString(); - PrintWriter out = new PrintWriter(fileName); - out.print(gamePanel.getGameLog()); - out.close(); - } - } catch (FileNotFoundException ex) { - JOptionPane.showMessageDialog(this, "Error while writing game log to file\n\n" + ex, "Error writing gamelog", JOptionPane.ERROR_MESSAGE); - } + txtMatchScore.setText(gameEndView.getMatchView().getResult()); + } - } + private void saveGameLog(GameEndView gameEndView) { + String dir = "gamelogs"; + File saveDir = new File(dir); + //Here comes the existence check + if (!saveDir.exists()) { + saveDir.mkdirs(); + } + // get game log + try { + if (gameEndView.getMatchView().getGames().size() > 0) { + GamePanel gamePanel = MageFrame.getGame(gameEndView.getMatchView().getGames().get(gameEndView.getMatchView().getGames().size() - 1)); + if (gamePanel != null) { + SimpleDateFormat sdf = new SimpleDateFormat(); + sdf.applyPattern("yyyyMMdd_HHmmss"); + String fileName = new StringBuilder(dir).append(File.separator) + .append(sdf.format(gameEndView.getStartTime())) + .append('_').append(gameEndView.getMatchView().getGameType()) + .append('_').append(gameEndView.getMatchView().getGames().size()) + .append(".txt").toString(); + PrintWriter out = new PrintWriter(fileName); + out.print(gamePanel.getGameLog()); + out.close(); + } + } + } catch (FileNotFoundException ex) { + JOptionPane.showMessageDialog(this, "Error while writing game log to file\n\n" + ex, "Error writing gamelog", JOptionPane.ERROR_MESSAGE); + } - public void showDialog() { - this.setLocation(100, 100); - this.setVisible(true); - } + } - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { + public void showDialog() { + this.setLocation(100, 100); + this.setVisible(true); + } - jPanel2 = new javax.swing.JPanel(); - tabPane = new javax.swing.JTabbedPane(); - tabResult = new javax.swing.JLayeredPane(); - pnlText = new javax.swing.JLayeredPane(); - lblGameInfo = new javax.swing.JLabel(); - lblMatchInfo = new javax.swing.JLabel(); - lblAdditionalInfo = new javax.swing.JLabel(); - lblResultImage = new javax.swing.JLabel(); - tabStatistics = new javax.swing.JPanel(); - lblDurationGame = new javax.swing.JLabel(); - txtDurationGame = new javax.swing.JLabel(); - lblLife = new javax.swing.JLabel(); - txtLife = new javax.swing.JLabel(); - lblDurationMatch = new javax.swing.JLabel(); - txtDurationMatch = new javax.swing.JLabel(); - lblMatchScore = new javax.swing.JLabel(); - txtMatchScore = new javax.swing.JLabel(); - lblPlayerInfo = new javax.swing.JLabel(); - txtPlayerInfo = new javax.swing.JLabel(); - btnOk = new javax.swing.JButton(); + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { - javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); - jPanel2.setLayout(jPanel2Layout); - jPanel2Layout.setHorizontalGroup( - jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 100, Short.MAX_VALUE) - ); - jPanel2Layout.setVerticalGroup( - jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 100, Short.MAX_VALUE) - ); + jPanel2 = new javax.swing.JPanel(); + tabPane = new javax.swing.JTabbedPane(); + tabResult = new javax.swing.JLayeredPane(); + pnlText = new javax.swing.JLayeredPane(); + lblGameInfo = new javax.swing.JLabel(); + lblMatchInfo = new javax.swing.JLabel(); + lblAdditionalInfo = new javax.swing.JLabel(); + lblResultImage = new javax.swing.JLabel(); + tabStatistics = new javax.swing.JPanel(); + lblDurationGame = new javax.swing.JLabel(); + txtDurationGame = new javax.swing.JLabel(); + lblLife = new javax.swing.JLabel(); + txtLife = new javax.swing.JLabel(); + lblDurationMatch = new javax.swing.JLabel(); + txtDurationMatch = new javax.swing.JLabel(); + lblMatchScore = new javax.swing.JLabel(); + txtMatchScore = new javax.swing.JLabel(); + lblPlayerInfo = new javax.swing.JLabel(); + txtPlayerInfo = new javax.swing.JLabel(); + btnOk = new javax.swing.JButton(); - setTitle("Game end information"); + javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 100, Short.MAX_VALUE) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 100, Short.MAX_VALUE) + ); - pnlText.setBackground(new java.awt.Color(200, 100, 100)); - pnlText.setBorder(javax.swing.BorderFactory.createEtchedBorder()); - pnlText.setOpaque(true); + setTitle("Game end information"); - lblGameInfo.setFont(new java.awt.Font("Tahoma", 3, 18)); // NOI18N - lblGameInfo.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); - lblGameInfo.setText("gameInfo"); - pnlText.add(lblGameInfo); - lblGameInfo.setBounds(11, 1, 550, 25); + pnlText.setBackground(new java.awt.Color(200, 100, 100)); + pnlText.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + pnlText.setOpaque(true); - lblMatchInfo.setFont(new java.awt.Font("Tahoma", 3, 18)); // NOI18N - lblMatchInfo.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); - lblMatchInfo.setText("matchInfo"); - pnlText.add(lblMatchInfo); - lblMatchInfo.setBounds(10, 30, 550, 25); + lblGameInfo.setFont(new java.awt.Font("Tahoma", 3, 18)); // NOI18N + lblGameInfo.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + lblGameInfo.setText("gameInfo"); + pnlText.add(lblGameInfo); + lblGameInfo.setBounds(11, 1, 550, 25); - lblAdditionalInfo.setFont(new java.awt.Font("Tahoma", 3, 18)); // NOI18N - lblAdditionalInfo.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); - lblAdditionalInfo.setText("additionalInfo"); - pnlText.add(lblAdditionalInfo); - lblAdditionalInfo.setBounds(10, 60, 550, 25); + lblMatchInfo.setFont(new java.awt.Font("Tahoma", 3, 18)); // NOI18N + lblMatchInfo.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + lblMatchInfo.setText("matchInfo"); + pnlText.add(lblMatchInfo); + lblMatchInfo.setBounds(10, 30, 550, 25); - tabResult.add(pnlText); - pnlText.setBounds(20, 150, 570, 90); + lblAdditionalInfo.setFont(new java.awt.Font("Tahoma", 3, 18)); // NOI18N + lblAdditionalInfo.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + lblAdditionalInfo.setText("additionalInfo"); + pnlText.add(lblAdditionalInfo); + lblAdditionalInfo.setBounds(10, 60, 550, 25); - lblResultImage.setFont(new java.awt.Font("Tahoma", 1, 24)); // NOI18N - lblResultImage.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); - tabResult.add(lblResultImage); - lblResultImage.setBounds(0, 0, 610, 250); + tabResult.add(pnlText); + pnlText.setBounds(20, 150, 570, 90); - tabPane.addTab("Result", tabResult); + lblResultImage.setFont(new java.awt.Font("Tahoma", 1, 24)); // NOI18N + lblResultImage.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + tabResult.add(lblResultImage); + lblResultImage.setBounds(0, 0, 610, 250); - lblDurationGame.setText("Duration game:"); + tabPane.addTab("Result", tabResult); - txtDurationGame.setText("Duration Game"); - txtDurationGame.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + lblDurationGame.setText("Duration game:"); - lblLife.setText("Life at end:"); + txtDurationGame.setText("Duration Game"); + txtDurationGame.setBorder(javax.swing.BorderFactory.createEtchedBorder()); - txtLife.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + lblLife.setText("Life at end:"); - lblDurationMatch.setText("Duration match:"); + txtLife.setBorder(javax.swing.BorderFactory.createEtchedBorder()); - txtDurationMatch.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + lblDurationMatch.setText("Duration match:"); - lblMatchScore.setText("Match score:"); + txtDurationMatch.setBorder(javax.swing.BorderFactory.createEtchedBorder()); - txtMatchScore.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + lblMatchScore.setText("Match score:"); - lblPlayerInfo.setText("Player info:"); + txtMatchScore.setBorder(javax.swing.BorderFactory.createEtchedBorder()); - txtPlayerInfo.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + lblPlayerInfo.setText("Player info:"); - javax.swing.GroupLayout tabStatisticsLayout = new javax.swing.GroupLayout(tabStatistics); - tabStatistics.setLayout(tabStatisticsLayout); - tabStatisticsLayout.setHorizontalGroup( - tabStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(tabStatisticsLayout.createSequentialGroup() - .addContainerGap() - .addGroup(tabStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblPlayerInfo, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblDurationMatch, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblMatchScore, javax.swing.GroupLayout.PREFERRED_SIZE, 86, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblDurationGame, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblLife, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(tabStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(txtPlayerInfo, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(txtDurationGame, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 494, Short.MAX_VALUE) - .addComponent(txtLife, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 489, Short.MAX_VALUE) - .addComponent(txtDurationMatch, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 489, Short.MAX_VALUE) - .addComponent(txtMatchScore, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 489, Short.MAX_VALUE)) - .addContainerGap()) - ); - tabStatisticsLayout.setVerticalGroup( - tabStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(tabStatisticsLayout.createSequentialGroup() - .addGroup(tabStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblDurationGame, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(txtDurationGame, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(tabStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lblLife, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(txtLife, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(tabStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lblDurationMatch, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(txtDurationMatch, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(tabStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lblMatchScore, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(txtMatchScore, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(tabStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblPlayerInfo, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(txtPlayerInfo, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(105, Short.MAX_VALUE)) - ); + txtPlayerInfo.setBorder(javax.swing.BorderFactory.createEtchedBorder()); - tabPane.addTab("Statistics", tabStatistics); + javax.swing.GroupLayout tabStatisticsLayout = new javax.swing.GroupLayout(tabStatistics); + tabStatistics.setLayout(tabStatisticsLayout); + tabStatisticsLayout.setHorizontalGroup( + tabStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(tabStatisticsLayout.createSequentialGroup() + .addContainerGap() + .addGroup(tabStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblPlayerInfo, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblDurationMatch, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblMatchScore, javax.swing.GroupLayout.PREFERRED_SIZE, 86, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblDurationGame, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblLife, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(tabStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(txtPlayerInfo, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(txtDurationGame, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 494, Short.MAX_VALUE) + .addComponent(txtLife, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 489, Short.MAX_VALUE) + .addComponent(txtDurationMatch, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 489, Short.MAX_VALUE) + .addComponent(txtMatchScore, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 489, Short.MAX_VALUE)) + .addContainerGap()) + ); + tabStatisticsLayout.setVerticalGroup( + tabStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(tabStatisticsLayout.createSequentialGroup() + .addGroup(tabStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblDurationGame, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtDurationGame, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(tabStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblLife, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtLife, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(tabStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblDurationMatch, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtDurationMatch, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(tabStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblMatchScore, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtMatchScore, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(tabStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblPlayerInfo, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtPlayerInfo, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(105, Short.MAX_VALUE)) + ); - btnOk.setText("OK"); - btnOk.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - btnOkActionPerformed(evt); - } - }); + tabPane.addTab("Statistics", tabStatistics); - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); - getContentPane().setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btnOk) - .addContainerGap()) - .addGroup(layout.createSequentialGroup() - .addComponent(tabPane, javax.swing.GroupLayout.PREFERRED_SIZE, 626, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE)) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(tabPane, javax.swing.GroupLayout.PREFERRED_SIZE, 277, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnOk) - .addGap(0, 8, Short.MAX_VALUE)) - ); + btnOk.setText("OK"); + btnOk.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnOkActionPerformed(evt); + } + }); - pack(); - }// //GEN-END:initComponents + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnOk) + .addContainerGap()) + .addGroup(layout.createSequentialGroup() + .addComponent(tabPane, javax.swing.GroupLayout.PREFERRED_SIZE, 626, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(tabPane, javax.swing.GroupLayout.PREFERRED_SIZE, 277, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnOk) + .addGap(0, 8, Short.MAX_VALUE)) + ); - private void btnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOkActionPerformed - this.removeDialog(); - }//GEN-LAST:event_btnOkActionPerformed + pack(); + }// //GEN-END:initComponents - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton btnOk; - private javax.swing.JPanel jPanel2; - private javax.swing.JLabel lblAdditionalInfo; - private javax.swing.JLabel lblDurationGame; - private javax.swing.JLabel lblDurationMatch; - private javax.swing.JLabel lblGameInfo; - private javax.swing.JLabel lblLife; - private javax.swing.JLabel lblMatchInfo; - private javax.swing.JLabel lblMatchScore; - private javax.swing.JLabel lblPlayerInfo; - private javax.swing.JLabel lblResultImage; - private javax.swing.JLayeredPane pnlText; - private javax.swing.JTabbedPane tabPane; - private javax.swing.JLayeredPane tabResult; - private javax.swing.JPanel tabStatistics; - private javax.swing.JLabel txtDurationGame; - private javax.swing.JLabel txtDurationMatch; - private javax.swing.JLabel txtLife; - private javax.swing.JLabel txtMatchScore; - private javax.swing.JLabel txtPlayerInfo; - // End of variables declaration//GEN-END:variables + private void btnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOkActionPerformed + this.removeDialog(); + }//GEN-LAST:event_btnOkActionPerformed -} + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton btnOk; + private javax.swing.JPanel jPanel2; + private javax.swing.JLabel lblAdditionalInfo; + private javax.swing.JLabel lblDurationGame; + private javax.swing.JLabel lblDurationMatch; + private javax.swing.JLabel lblGameInfo; + private javax.swing.JLabel lblLife; + private javax.swing.JLabel lblMatchInfo; + private javax.swing.JLabel lblMatchScore; + private javax.swing.JLabel lblPlayerInfo; + private javax.swing.JLabel lblResultImage; + private javax.swing.JLayeredPane pnlText; + private javax.swing.JTabbedPane tabPane; + private javax.swing.JLayeredPane tabResult; + private javax.swing.JPanel tabStatistics; + private javax.swing.JLabel txtDurationGame; + private javax.swing.JLabel txtDurationMatch; + private javax.swing.JLabel txtLife; + private javax.swing.JLabel txtMatchScore; + private javax.swing.JLabel txtPlayerInfo; + // End of variables declaration//GEN-END:variables + + } From 748d14e55e96db21784ab261f23bd39154b393a9 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 14 Jan 2020 18:53:47 +0400 Subject: [PATCH 3/7] * Thassa, Deep-Dwelling - fixed text; --- .../src/mage/cards/t/ThassaDeepDwelling.java | 19 ++++++++------- .../YorvoLordOfGarenbrigOnCommandersTest.java | 2 +- .../common/ExileTargetForSourceEffect.java | 24 ++++++++++++------- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/Mage.Sets/src/mage/cards/t/ThassaDeepDwelling.java b/Mage.Sets/src/mage/cards/t/ThassaDeepDwelling.java index 902a8cb64f..43ef9c402e 100644 --- a/Mage.Sets/src/mage/cards/t/ThassaDeepDwelling.java +++ b/Mage.Sets/src/mage/cards/t/ThassaDeepDwelling.java @@ -1,6 +1,5 @@ package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; @@ -20,20 +19,24 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.TargetController; import mage.filter.FilterPermanent; -import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AnotherPredicate; import mage.target.TargetPermanent; +import java.util.UUID; + /** * @author TheElk801 */ public final class ThassaDeepDwelling extends CardImpl { - private static final FilterPermanent filter = new FilterCreaturePermanent("another target creature"); + private static final FilterPermanent filterAnother = new FilterCreaturePermanent("another target creature"); + private static final FilterPermanent filterOther = new FilterControlledCreaturePermanent("other target creature you control"); static { - filter.add(AnotherPredicate.instance); + filterAnother.add(AnotherPredicate.instance); + filterOther.add(AnotherPredicate.instance); } public ThassaDeepDwelling(UUID ownerId, CardSetInfo setInfo) { @@ -53,12 +56,12 @@ public final class ThassaDeepDwelling extends CardImpl { // At the beginning of your end step, exile up to one other target creature you control, then return that card to the battlefield under your control. Ability ability = new BeginningOfEndStepTriggeredAbility( - new ExileTargetForSourceEffect().setText("exile up to one other target creature you control, then "), + new ExileTargetForSourceEffect()/*.setText("exile up to one other target creature you control")*/, TargetController.YOU, false ); - ability.addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect(true)); + ability.addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect(true).concatBy(", then")); ability.addTarget(new TargetPermanent( - 0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, false + 0, 1, filterOther, false )); this.addAbility(ability); @@ -66,7 +69,7 @@ public final class ThassaDeepDwelling extends CardImpl { ability = new SimpleActivatedAbility( new TapTargetEffect("another target creature"), new ManaCostsImpl("{3}{U}") ); - ability.addTarget(new TargetPermanent(filter)); + ability.addTarget(new TargetPermanent(filterAnother)); this.addAbility(ability); } diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/duel/YorvoLordOfGarenbrigOnCommandersTest.java b/Mage.Tests/src/test/java/org/mage/test/commander/duel/YorvoLordOfGarenbrigOnCommandersTest.java index a9e7e1ed57..9fb0832ab5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/commander/duel/YorvoLordOfGarenbrigOnCommandersTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/commander/duel/YorvoLordOfGarenbrigOnCommandersTest.java @@ -38,7 +38,7 @@ public class YorvoLordOfGarenbrigOnCommandersTest extends CardTestCommanderDuelB } @Test - public void test_TriggerOnUroTitalOfNaturesWrath() { + public void test_TriggerOnUroTitanOfNaturesWrath() { // Yorvo, Lord of Garenbrig enters the battlefield with four +1/+1 counters on it. // Whenever another green creature enters the battlefield under your control, put a +1/+1 counter on Yorvo. Then if that creature’s power is greater than Yorvo’s power, put another +1/+1 counter on Yorvo. addCard(Zone.HAND, playerA, "Yorvo, Lord of Garenbrig", 5); // {G}{G}{G} diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileTargetForSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileTargetForSourceEffect.java index d6fd043a15..1ded5be2d4 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileTargetForSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileTargetForSourceEffect.java @@ -1,9 +1,5 @@ - package mage.abilities.effects.common; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; @@ -16,8 +12,11 @@ import mage.target.Target; import mage.target.targetpointer.FirstTargetPointer; import mage.util.CardUtil; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class ExileTargetForSourceEffect extends OneShotEffect { @@ -70,12 +69,21 @@ public class ExileTargetForSourceEffect extends OneShotEffect { return staticText; } + String upToText = ""; + if (mode.getTargets().get(0).getMinNumberOfTargets() < mode.getTargets().get(0).getMaxNumberOfTargets()) { + upToText = "up to " + CardUtil.numberToText(mode.getTargets().get(0).getMaxNumberOfTargets()) + " "; + } + String targetText = ""; + if (mode.getTargets().get(0).getTargetName().contains("target ")) { + targetText = ""; + } else { + targetText = "target "; + } + if (mode.getTargets().isEmpty()) { return "exile it"; - } else if (mode.getTargets().get(0).getTargetName().startsWith("another")) { - return "exile " + mode.getTargets().get(0).getTargetName(); } else { - return "exile target " + mode.getTargets().get(0).getTargetName(); + return "exile " + upToText + targetText + mode.getTargets().get(0).getTargetName(); } } } From 3a681d565aed10140a52d74d320d9017595384c5 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 14 Jan 2020 19:15:42 +0400 Subject: [PATCH 4/7] * Displace - fixed that it return cards under your control instead owner; --- Mage.Sets/src/mage/cards/d/Displace.java | 14 ++++----- ...tlefieldUnderOwnerControlTargetEffect.java | 30 +++++++++++++++---- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/Mage.Sets/src/mage/cards/d/Displace.java b/Mage.Sets/src/mage/cards/d/Displace.java index 966ed93159..e7cfe8012d 100644 --- a/Mage.Sets/src/mage/cards/d/Displace.java +++ b/Mage.Sets/src/mage/cards/d/Displace.java @@ -1,32 +1,30 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.effects.Effect; import mage.abilities.effects.common.ExileTargetForSourceEffect; -import mage.abilities.effects.common.ReturnToBattlefieldUnderYourControlTargetEffect; +import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Displace extends CardImpl { public Displace(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{U}"); + 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, new FilterControlledCreaturePermanent("creatures you control"), false)); Effect effect = new ExileTargetForSourceEffect(); - effect.setText("Exile up to two target creatures you control"); this.getSpellAbility().addEffect(effect); - effect = new ReturnToBattlefieldUnderYourControlTargetEffect(true); - effect.setText(", then return those cards to the battlefield under their owner's control"); + effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect() + .withReturnNames("those cards", "their owner's").concatBy(", then"); this.getSpellAbility().addEffect(effect); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlTargetEffect.java index 657a347d2b..24963b1ee0 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlTargetEffect.java @@ -1,7 +1,5 @@ - package mage.abilities.effects.common; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -15,14 +13,17 @@ import mage.game.Game; import mage.players.Player; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author LevelX2 */ public class ReturnToBattlefieldUnderOwnerControlTargetEffect extends OneShotEffect { private boolean tapped; protected boolean fromExileZone; + private String returnName = "that card"; + private String returnUnderControlName = "its owner's"; public ReturnToBattlefieldUnderOwnerControlTargetEffect() { this(false); @@ -34,15 +35,26 @@ public class ReturnToBattlefieldUnderOwnerControlTargetEffect extends OneShotEff public ReturnToBattlefieldUnderOwnerControlTargetEffect(boolean tapped, boolean fromExileZone) { super(Outcome.Benefit); - staticText = "return that card to the battlefield under its owner's control"; this.tapped = tapped; this.fromExileZone = fromExileZone; + + updateText(); } public ReturnToBattlefieldUnderOwnerControlTargetEffect(final ReturnToBattlefieldUnderOwnerControlTargetEffect effect) { super(effect); this.tapped = effect.tapped; this.fromExileZone = effect.fromExileZone; + this.returnName = effect.returnName; + this.returnUnderControlName = effect.returnUnderControlName; + + updateText(); + } + + private void updateText() { + this.staticText = "return " + this.returnName + + " to the battlefield under " + this.returnUnderControlName + " control" + + (tapped ? " tapped" : ""); } @Override @@ -63,8 +75,7 @@ public class ReturnToBattlefieldUnderOwnerControlTargetEffect extends OneShotEff for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { if (exileZone.contains(targetId)) { cardsToBattlefield.add(targetId); - } - else { + } else { Card card = game.getCard(targetId); if (card instanceof MeldCard) { MeldCard meldCard = (MeldCard) card; @@ -91,4 +102,11 @@ public class ReturnToBattlefieldUnderOwnerControlTargetEffect extends OneShotEff } return false; } + + public ReturnToBattlefieldUnderOwnerControlTargetEffect withReturnNames(String returnName, String returnUnderControlName) { + this.returnName = returnName; + this.returnUnderControlName = returnUnderControlName; + updateText(); + return this; + } } From 26bdd8c0e8883ce361b30339b8e325ae705153f2 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 14 Jan 2020 10:59:39 -0500 Subject: [PATCH 5/7] fixed Dream Trawler activated ability not being available --- Mage.Sets/src/mage/cards/d/DreamTrawler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Mage.Sets/src/mage/cards/d/DreamTrawler.java b/Mage.Sets/src/mage/cards/d/DreamTrawler.java index c8c8e8cb8b..6384bc97cd 100644 --- a/Mage.Sets/src/mage/cards/d/DreamTrawler.java +++ b/Mage.Sets/src/mage/cards/d/DreamTrawler.java @@ -52,6 +52,7 @@ public final class DreamTrawler extends CardImpl { HexproofAbility.getInstance(), Duration.EndOfTurn ), new DiscardCardCost()); ability.addEffect(new TapSourceEffect().setText("Tap it")); + this.addAbility(ability); } private DreamTrawler(final DreamTrawler card) { From ce3f6d8e4196f2de8aafe732165243c724617a75 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 14 Jan 2020 20:34:52 +0400 Subject: [PATCH 6/7] Fixed wrong ends symbols in combined effects rules like IfDoCost; --- .../main/java/mage/abilities/effects/Effects.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Mage/src/main/java/mage/abilities/effects/Effects.java b/Mage/src/main/java/mage/abilities/effects/Effects.java index 97f2675244..3eaf378be5 100644 --- a/Mage/src/main/java/mage/abilities/effects/Effects.java +++ b/Mage/src/main/java/mage/abilities/effects/Effects.java @@ -71,7 +71,18 @@ public class Effects extends ArrayList { nextRule = Character.toUpperCase(nextRule.charAt(0)) + nextRule.substring(1); } } - sbText.append(endString).append(nextRule); + + String currentRule = endString + nextRule; + // fix dot in the combined effect like IfDoCost + if (sbText.length() > 0 && currentRule.length() > 0) { + boolean prevTextEndsWithDot = sbText.charAt(sbText.length() - 1) == '.'; + boolean currentTextStartsWithDot = currentRule.startsWith(",") || currentRule.startsWith("."); + if (prevTextEndsWithDot && currentTextStartsWithDot) { + sbText.delete(sbText.length() - 1, sbText.length()); + } + } + + sbText.append(currentRule); } lastRule = nextRule; } From b1b6bd600e497ab3063cd848deb83bd82d4f2264 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 14 Jan 2020 20:38:45 +0400 Subject: [PATCH 7/7] Improved rules text generation and removed static texts for some cards with effects: * ExileTargetForSourceEffect * ReturnFromExileForSourceEffect * ReturnToBattlefieldUnderOwnerControlTargetEffect * ReturnToBattlefieldUnderYourControlTargetEffect --- .../src/mage/cards/e/EldraziDisplacer.java | 10 ++--- .../src/mage/cards/f/FacelessButcher.java | 15 +++---- .../src/mage/cards/f/FacelessDevourer.java | 15 +++---- Mage.Sets/src/mage/cards/g/Gravegouger.java | 9 ++-- Mage.Sets/src/mage/cards/h/Helvault.java | 13 +++--- .../mage/cards/i/IllusionistsStratagem.java | 18 ++++---- Mage.Sets/src/mage/cards/n/N1Starfighter.java | 20 ++++----- Mage.Sets/src/mage/cards/p/ParallaxTide.java | 9 ++-- Mage.Sets/src/mage/cards/p/Petradon.java | 22 +++++----- Mage.Sets/src/mage/cards/p/Petravark.java | 8 ++-- Mage.Sets/src/mage/cards/r/RuinGhost.java | 9 ++-- .../src/mage/cards/t/ThassaDeepDwelling.java | 2 +- .../common/ExileTargetForSourceEffect.java | 9 ++-- .../ReturnFromExileForSourceEffect.java | 41 ++++++++++++++----- ...tlefieldUnderOwnerControlTargetEffect.java | 4 +- ...ttlefieldUnderYourControlTargetEffect.java | 13 +++++- 16 files changed, 120 insertions(+), 97 deletions(-) diff --git a/Mage.Sets/src/mage/cards/e/EldraziDisplacer.java b/Mage.Sets/src/mage/cards/e/EldraziDisplacer.java index 8618e6afb6..1ccfa5e162 100644 --- a/Mage.Sets/src/mage/cards/e/EldraziDisplacer.java +++ b/Mage.Sets/src/mage/cards/e/EldraziDisplacer.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -19,8 +17,9 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AnotherPredicate; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class EldraziDisplacer extends CardImpl { @@ -42,10 +41,9 @@ public final class EldraziDisplacer extends CardImpl { // {2}{C}: Exile another target creature, then return it to the battlefield tapped under its owner's control. Effect effect = new ExileTargetForSourceEffect(); - effect.setText("Exile another target creature"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{2}{C}")); - effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(true); - effect.setText(", then return it to the battlefield tapped under its owner's control"); + effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(true) + .withReturnNames("it", "its owner's").concatBy(", then"); ability.addEffect(effect); ability.addTarget(new TargetCreaturePermanent(FILTER)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/f/FacelessButcher.java b/Mage.Sets/src/mage/cards/f/FacelessButcher.java index 42bc86ffe6..feb68515f4 100644 --- a/Mage.Sets/src/mage/cards/f/FacelessButcher.java +++ b/Mage.Sets/src/mage/cards/f/FacelessButcher.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -19,32 +17,29 @@ import mage.filter.predicate.permanent.AnotherPredicate; import mage.target.Target; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author Temba21 */ public final class FacelessButcher extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature other than Faceless Butcher"); static { - filter.add(AnotherPredicate.instance); + filter.add(AnotherPredicate.instance); } - public FacelessButcher(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.NIGHTMARE); this.subtype.add(SubType.HORROR); this.power = new MageInt(2); this.toughness = new MageInt(3); - // When Faceless Butcher enters the battlefield, exile target creature other than Faceless Butcher. Effect effect = new ExileTargetForSourceEffect(); - effect.setText("exile target creature other than {this}"); Ability ability1 = new EntersBattlefieldTriggeredAbility(effect, false); Target target = new TargetPermanent(filter); ability1.addTarget(target); diff --git a/Mage.Sets/src/mage/cards/f/FacelessDevourer.java b/Mage.Sets/src/mage/cards/f/FacelessDevourer.java index 4148034851..143d5ee6df 100644 --- a/Mage.Sets/src/mage/cards/f/FacelessDevourer.java +++ b/Mage.Sets/src/mage/cards/f/FacelessDevourer.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -21,13 +19,14 @@ import mage.filter.predicate.permanent.AnotherPredicate; import mage.target.Target; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author LoneFox */ public final class FacelessDevourer extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature with shadow"); static { filter.add(AnotherPredicate.instance); @@ -35,7 +34,7 @@ public final class FacelessDevourer extends CardImpl { } public FacelessDevourer(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.NIGHTMARE); this.subtype.add(SubType.HORROR); this.power = new MageInt(2); @@ -43,15 +42,17 @@ public final class FacelessDevourer extends CardImpl { // Shadow this.addAbility(ShadowAbility.getInstance()); + // When Faceless Devourer enters the battlefield, exile another target creature with shadow. Effect effect = new ExileTargetForSourceEffect(); - effect.setText("exile another target creature with shadow"); Ability ability = new EntersBattlefieldTriggeredAbility(effect, false); Target target = new TargetPermanent(filter); ability.addTarget(target); this.addAbility(ability); + // When Faceless Devourer leaves the battlefield, return the exiled card to the battlefield under its owner's control. - ability = new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD), false); + ability = new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD) + .withReturnName("card", "its owner's"), false); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/Gravegouger.java b/Mage.Sets/src/mage/cards/g/Gravegouger.java index 970aee44a1..57f99373d0 100644 --- a/Mage.Sets/src/mage/cards/g/Gravegouger.java +++ b/Mage.Sets/src/mage/cards/g/Gravegouger.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; @@ -17,14 +15,15 @@ import mage.constants.Zone; import mage.filter.FilterCard; import mage.target.common.TargetCardInASingleGraveyard; +import java.util.UUID; + /** - * * @author LoneFox */ public final class Gravegouger extends CardImpl { public Gravegouger(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.NIGHTMARE); this.subtype.add(SubType.HORROR); this.power = new MageInt(2); @@ -32,10 +31,10 @@ public final class Gravegouger extends CardImpl { // When Gravegouger enters the battlefield, exile up to two target cards from a single graveyard. Effect effect = new ExileTargetForSourceEffect(); - effect.setText("exile up to two target cards from a single graveyard"); Ability ability = new EntersBattlefieldTriggeredAbility(effect, false); ability.addTarget(new TargetCardInASingleGraveyard(0, 2, new FilterCard("cards from a single graveyard"))); this.addAbility(ability); + // When Gravegouger leaves the battlefield, return the exiled cards to their owner's graveyard. this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.GRAVEYARD), false)); } diff --git a/Mage.Sets/src/mage/cards/h/Helvault.java b/Mage.Sets/src/mage/cards/h/Helvault.java index b361d5a7c8..894ac8b4cf 100644 --- a/Mage.Sets/src/mage/cards/h/Helvault.java +++ b/Mage.Sets/src/mage/cards/h/Helvault.java @@ -1,7 +1,5 @@ - package mage.cards.h; -import java.util.UUID; import mage.abilities.common.DiesTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; @@ -18,8 +16,9 @@ import mage.filter.common.FilterCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class Helvault extends CardImpl { @@ -31,19 +30,21 @@ public final class Helvault extends CardImpl { } public Helvault(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); addSuperType(SuperType.LEGENDARY); - // {1}, {tap}: Exile target creature you control. + // {1}, {T}: Exile target creature you control. SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect(), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); - // {7}, {tap}: Exile target creature you don't control. + + // {7}, {T}: Exile target creature you don't control. ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect(), new GenericManaCost(7)); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent(filter)); 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. this.addAbility(new DiesTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD))); } diff --git a/Mage.Sets/src/mage/cards/i/IllusionistsStratagem.java b/Mage.Sets/src/mage/cards/i/IllusionistsStratagem.java index db99519400..cac0578a60 100644 --- a/Mage.Sets/src/mage/cards/i/IllusionistsStratagem.java +++ b/Mage.Sets/src/mage/cards/i/IllusionistsStratagem.java @@ -1,8 +1,5 @@ - package mage.cards.i; -import java.util.UUID; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ExileTargetForSourceEffect; import mage.abilities.effects.common.ReturnToBattlefieldUnderYourControlTargetEffect; @@ -12,8 +9,9 @@ import mage.constants.CardType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author Styxo */ public final class IllusionistsStratagem extends CardImpl { @@ -22,13 +20,11 @@ public final class IllusionistsStratagem extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{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, new FilterControlledCreaturePermanent("creatures you control"), false)); - Effect effect = new ExileTargetForSourceEffect(); - effect.setText("Exile up to two target creatures you control"); - this.getSpellAbility().addEffect(effect); - effect = new ReturnToBattlefieldUnderYourControlTargetEffect(true); - effect.setText(", then return those cards to the battlefield under their owner's control"); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(new ExileTargetForSourceEffect()); + this.getSpellAbility().addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect(true) + .withReturnNames("those cards", "their owner's").concatBy(", then")); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, 2, + new FilterControlledCreaturePermanent("creatures you control"), false)); // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); diff --git a/Mage.Sets/src/mage/cards/n/N1Starfighter.java b/Mage.Sets/src/mage/cards/n/N1Starfighter.java index bd50c4d84f..8455074bbe 100644 --- a/Mage.Sets/src/mage/cards/n/N1Starfighter.java +++ b/Mage.Sets/src/mage/cards/n/N1Starfighter.java @@ -1,12 +1,9 @@ - package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.ExileTargetForSourceEffect; import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; @@ -19,13 +16,14 @@ import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.AnotherPredicate; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author Styxo */ public final class N1Starfighter extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another creature you control"); + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature you control"); static { filter.add(AnotherPredicate.instance); @@ -40,12 +38,14 @@ public final class N1Starfighter extends CardImpl { // Spaceflight this.addAbility(SpaceflightAbility.getInstance()); - // Whenever N-1 Starfighter deals combat damage to a player, you may pay {1}{W/U}. If you do, exile another creature you control, then return that card to the battlefield under its owner's control. - Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DoIfCostPaid(new ExileTargetForSourceEffect(), new ManaCostsImpl("{1}{W/U}")), false); - Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, true); - effect.setText(", then return the card to the battlefield under their owner's control"); - ability.addEffect(effect); + // Whenever N-1 Starfighter deals combat damage to a player, you may pay {1}{W/U}. If you do, + // exile another target creature you control, then return that card to the battlefield under its owner's control. + // P.S. original card have error with missing target word (another target creature) + Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DoIfCostPaid( + new ExileTargetForSourceEffect(), new ManaCostsImpl("{1}{W/U}")), false); + ability.addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, true).concatBy(", then")); ability.addTarget(new TargetControlledCreaturePermanent(filter)); + ability.getRule(); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/ParallaxTide.java b/Mage.Sets/src/mage/cards/p/ParallaxTide.java index 3798ec60ab..fe86166b11 100644 --- a/Mage.Sets/src/mage/cards/p/ParallaxTide.java +++ b/Mage.Sets/src/mage/cards/p/ParallaxTide.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -16,22 +14,25 @@ import mage.constants.Zone; import mage.counters.CounterType; import mage.target.common.TargetLandPermanent; +import java.util.UUID; + /** - * * @author Plopman */ public final class ParallaxTide extends CardImpl { public ParallaxTide(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}"); // Fading 5 this.addAbility(new FadingAbility(5, this)); + // Remove a fade counter from Parallax Tide: Exile target land. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect(), new RemoveCountersSourceCost(CounterType.FADE.createInstance())); ability.addTarget(new TargetLandPermanent()); this.addAbility(ability); + // When Parallax Tide leaves the battlefield, each player returns to the battlefield all cards they own exiled with Parallax Tide. this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD), splitCard)); } diff --git a/Mage.Sets/src/mage/cards/p/Petradon.java b/Mage.Sets/src/mage/cards/p/Petradon.java index ee73e5681b..6aa2f595dc 100644 --- a/Mage.Sets/src/mage/cards/p/Petradon.java +++ b/Mage.Sets/src/mage/cards/p/Petradon.java @@ -1,46 +1,46 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.ExileTargetForSourceEffect; import mage.abilities.effects.common.ReturnFromExileForSourceEffect; 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.SubType; import mage.constants.Zone; +import mage.filter.common.FilterLandPermanent; import mage.target.common.TargetLandPermanent; +import java.util.UUID; + /** - * * @author LoneFox */ public final class Petradon extends CardImpl { public Petradon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{6}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{R}{R}"); this.subtype.add(SubType.NIGHTMARE); this.subtype.add(SubType.BEAST); this.power = new MageInt(5); this.toughness = new MageInt(6); // When Petradon enters the battlefield, exile two target lands. - Effect effect = new ExileTargetForSourceEffect(); - effect.setText("exile two target lands"); - Ability ability = new EntersBattlefieldTriggeredAbility(effect, false); - ability.addTarget(new TargetLandPermanent(2)); + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect(), false); + ability.addTarget(new TargetLandPermanent(2, 2, new FilterLandPermanent("lands"), false)); this.addAbility(ability); + // When Petradon leaves the battlefield, return the exiled cards to the battlefield under their owners' control. - this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD), false)); + this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD) + .withReturnName("cards", "their owners'"), false)); + // {R}: Petradon gets +1/+0 until end of turn. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl("{R}"))); } diff --git a/Mage.Sets/src/mage/cards/p/Petravark.java b/Mage.Sets/src/mage/cards/p/Petravark.java index 172191ebc8..57e20586cb 100644 --- a/Mage.Sets/src/mage/cards/p/Petravark.java +++ b/Mage.Sets/src/mage/cards/p/Petravark.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -15,14 +13,15 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.target.common.TargetLandPermanent; +import java.util.UUID; + /** - * * @author LoneFox */ public final class Petravark extends CardImpl { public Petravark(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.NIGHTMARE); this.subtype.add(SubType.BEAST); this.power = new MageInt(2); @@ -32,6 +31,7 @@ public final class Petravark extends CardImpl { Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect(), false); ability.addTarget(new TargetLandPermanent()); this.addAbility(ability); + // When Petravark leaves the battlefield, return the exiled card to the battlefield under its owner's control. this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD), false)); } diff --git a/Mage.Sets/src/mage/cards/r/RuinGhost.java b/Mage.Sets/src/mage/cards/r/RuinGhost.java index f74a2e2f26..a39b2da139 100644 --- a/Mage.Sets/src/mage/cards/r/RuinGhost.java +++ b/Mage.Sets/src/mage/cards/r/RuinGhost.java @@ -1,7 +1,5 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -17,20 +15,21 @@ import mage.constants.Zone; import mage.filter.common.FilterControlledLandPermanent; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class RuinGhost extends CardImpl { public RuinGhost(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.SPIRIT); this.power = new MageInt(1); this.toughness = new MageInt(1); - // {W}, {tap}: Exile target land you control, then return it to the battlefield under your control. + // {W}, {T}: Exile target land you control, then return it to the battlefield under your control. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect(), new ManaCostsImpl("{W")); ability.addCost(new TapSourceCost()); ability.addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect(true)); diff --git a/Mage.Sets/src/mage/cards/t/ThassaDeepDwelling.java b/Mage.Sets/src/mage/cards/t/ThassaDeepDwelling.java index 43ef9c402e..41b047baf5 100644 --- a/Mage.Sets/src/mage/cards/t/ThassaDeepDwelling.java +++ b/Mage.Sets/src/mage/cards/t/ThassaDeepDwelling.java @@ -56,7 +56,7 @@ public final class ThassaDeepDwelling extends CardImpl { // At the beginning of your end step, exile up to one other target creature you control, then return that card to the battlefield under your control. Ability ability = new BeginningOfEndStepTriggeredAbility( - new ExileTargetForSourceEffect()/*.setText("exile up to one other target creature you control")*/, + new ExileTargetForSourceEffect(), TargetController.YOU, false ); ability.addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect(true).concatBy(", then")); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileTargetForSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileTargetForSourceEffect.java index 1ded5be2d4..bee973d554 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileTargetForSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileTargetForSourceEffect.java @@ -69,10 +69,13 @@ public class ExileTargetForSourceEffect extends OneShotEffect { return staticText; } - String upToText = ""; + String amountText = ""; if (mode.getTargets().get(0).getMinNumberOfTargets() < mode.getTargets().get(0).getMaxNumberOfTargets()) { - upToText = "up to " + CardUtil.numberToText(mode.getTargets().get(0).getMaxNumberOfTargets()) + " "; + amountText = "up to " + CardUtil.numberToText(mode.getTargets().get(0).getMaxNumberOfTargets()) + " "; + } else if (mode.getTargets().get(0).getMinNumberOfTargets() > 1) { + amountText = CardUtil.numberToText(mode.getTargets().get(0).getMinNumberOfTargets()) + " "; } + String targetText = ""; if (mode.getTargets().get(0).getTargetName().contains("target ")) { targetText = ""; @@ -83,7 +86,7 @@ public class ExileTargetForSourceEffect extends OneShotEffect { if (mode.getTargets().isEmpty()) { return "exile it"; } else { - return "exile " + upToText + targetText + mode.getTargets().get(0).getTargetName(); + return "exile " + amountText + targetText + mode.getTargets().get(0).getTargetName(); } } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java index 5b12905f39..7bd9d4350e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import mage.MageObject; @@ -14,7 +13,6 @@ import mage.util.CardUtil; import org.apache.log4j.Logger; /** - * * @author BetaSteward_at_googlemail.com */ public class ReturnFromExileForSourceEffect extends OneShotEffect { @@ -22,9 +20,10 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect { private Zone returnToZone; private boolean tapped; private boolean previousZone; + private String returnName = "cards"; + private String returnControlName; /** - * * @param zone Zone the card should return to */ public ReturnFromExileForSourceEffect(Zone zone) { @@ -36,18 +35,28 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect { } /** - * * @param zone * @param tapped * @param previousZone if this is used from a dies leave battlefield or - * destroyed trigger, the exile zone is based on previous zone of the object + * destroyed trigger, the exile zone is based on previous zone of the object */ public ReturnFromExileForSourceEffect(Zone zone, boolean tapped, boolean previousZone) { super(Outcome.PutCardInPlay); this.returnToZone = zone; this.tapped = tapped; this.previousZone = previousZone; - setText(); + + // different default name for zones + switch (zone) { + case BATTLEFIELD: + this.returnControlName = "its owner's"; + break; + default: + this.returnControlName = "their owner's"; + break; + } + + updateText(); } public ReturnFromExileForSourceEffect(final ReturnFromExileForSourceEffect effect) { @@ -55,6 +64,10 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect { this.returnToZone = effect.returnToZone; this.tapped = effect.tapped; this.previousZone = effect.previousZone; + this.returnName = effect.returnName; + this.returnControlName = effect.returnControlName; + + updateText(); } @Override @@ -85,24 +98,30 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect { return false; } - private void setText() { + private void updateText() { StringBuilder sb = new StringBuilder(); - sb.append("return the exiled cards "); + sb.append("return the exiled " + this.returnName + " "); switch (returnToZone) { case BATTLEFIELD: - sb.append("to the battlefield under its owner's control"); + sb.append("to the battlefield under " + this.returnControlName + " control"); if (tapped) { sb.append(" tapped"); } break; case HAND: - sb.append("to their owner's hand"); + sb.append("to " + this.returnControlName + " hand"); break; case GRAVEYARD: - sb.append("to their owner's graveyard"); + sb.append("to " + this.returnControlName + " graveyard"); break; } staticText = sb.toString(); } + public ReturnFromExileForSourceEffect withReturnName(String returnName, String returnControlName) { + this.returnName = returnName; + this.returnControlName = returnControlName; + updateText(); + return this; + } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlTargetEffect.java index 24963b1ee0..db66028de2 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlTargetEffect.java @@ -53,8 +53,8 @@ public class ReturnToBattlefieldUnderOwnerControlTargetEffect extends OneShotEff private void updateText() { this.staticText = "return " + this.returnName - + " to the battlefield under " + this.returnUnderControlName + " control" - + (tapped ? " tapped" : ""); + + " to the battlefield" + (tapped ? " tapped" : "") + + " under " + this.returnUnderControlName + " control"; } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java index 547c62063c..25936223dd 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java @@ -23,6 +23,8 @@ public class ReturnToBattlefieldUnderYourControlTargetEffect extends OneShotEffe private boolean fromExileZone; private boolean tapped; private boolean attacking; + private String returnName = "that card"; + private String returnUnderControlName = "your"; public ReturnToBattlefieldUnderYourControlTargetEffect() { this(false); @@ -50,12 +52,14 @@ public class ReturnToBattlefieldUnderYourControlTargetEffect extends OneShotEffe this.fromExileZone = effect.fromExileZone; this.tapped = effect.tapped; this.attacking = effect.attacking; + this.returnName = effect.returnName; + this.returnUnderControlName = effect.returnUnderControlName; updateText(); } private void updateText() { - this.staticText = "return that card to the battlefield under your control" + this.staticText = "return " + returnName + " to the battlefield under " + returnUnderControlName + " control" + (tapped ? " tapped" : "") + (tapped && attacking ? " and" : "") + (attacking ? " attacking" : ""); @@ -111,4 +115,11 @@ public class ReturnToBattlefieldUnderYourControlTargetEffect extends OneShotEffe } return false; } + + public ReturnToBattlefieldUnderYourControlTargetEffect withReturnNames(String returnName, String returnUnderControlName) { + this.returnName = returnName; + this.returnUnderControlName = returnUnderControlName; + updateText(); + return this; + } }