diff --git a/.gitignore b/.gitignore index 5b29a556792..227cae92d1f 100644 --- a/.gitignore +++ b/.gitignore @@ -82,6 +82,7 @@ Mage.Server.Plugins/Mage.Draft.8PlayerBooster/target *.classpath *.iml +hs_err*.log /submitted /Mage.Server/config/ai.please.cast.this.txt @@ -91,4 +92,8 @@ Mage.Server.Plugins/Mage.Draft.8PlayerBooster/target *.txt Mage.Client/serverlist.txt /bin/ -/target/ \ No newline at end of file +/target/ + +client_secrets.json + +dependency-reduced-pom.xml diff --git a/Mage.Client/pom.xml b/Mage.Client/pom.xml index b39eb5c1b4e..52ff1498269 100644 --- a/Mage.Client/pom.xml +++ b/Mage.Client/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.6 + 1.4.8 org.mage diff --git a/Mage.Client/serverlist.txt b/Mage.Client/serverlist.txt index db223b403ff..a4379a04bbd 100644 --- a/Mage.Client/serverlist.txt +++ b/Mage.Client/serverlist.txt @@ -1,6 +1,6 @@ XMage.de 1 (Europe/Germany) fast :xmage.de:17171 woogerworks (North America/USA) :xmage.woogerworks.info:17171 -XMage.info 1 (Europe/France) new network code -> see forum :176.31.186.181:17171 +XMage Testserver (Europe/France) 1.4.8v0 :176.31.186.181:17171 XMage BR (South America/Brazil) :ec2-54-233-67-0.sa-east-1.compute.amazonaws.com:17171 Seedds Server (Asia) :115.29.203.80:17171 localhost -> connect to your local server (must be started):localhost:17171 diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index 4494e6951da..0190e7af98c 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -107,6 +107,7 @@ import mage.client.draft.DraftPanel; import mage.client.game.GamePane; import mage.client.game.GamePanel; import mage.client.plugins.impl.Plugins; +import mage.client.preference.MagePreferences; import mage.client.remote.CallbackClientImpl; import mage.client.table.TablesPane; import mage.client.tournament.TournamentPane; @@ -745,9 +746,10 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { } private boolean performConnect() { - String userName = prefs.get("userName", ""); - String server = prefs.get("serverAddress", ""); - int port = Integer.parseInt(prefs.get("serverPort", "")); + String server = MagePreferences.getServerAddress(); + int port = MagePreferences.getServerPort(); + String userName = MagePreferences.getUserName(server); + String password = MagePreferences.getPassword(server); String proxyServer = prefs.get("proxyAddress", ""); int proxyPort = Integer.parseInt(prefs.get("proxyPort", "0")); ProxyType proxyType = ProxyType.valueByText(prefs.get("proxyType", "None")); @@ -757,6 +759,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { setCursor(new Cursor(Cursor.WAIT_CURSOR)); Connection connection = new Connection(); connection.setUsername(userName); + connection.setPassword(password); connection.setHost(server); connection.setPort(port); connection.setProxyType(proxyType); 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 b90a94d858a..f66949a0ee5 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.java @@ -109,20 +109,20 @@ public class DeckEditorPanel extends javax.swing.JPanel { jSplitPane1.setOpaque(false); countdown = new Timer(1000, new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (--timeout > 0) { - setTimeout(timeout); - } else { - if (updateDeckTask != null) { - updateDeckTask.cancel(true); + @Override + public void actionPerformed(ActionEvent e) { + if (--timeout > 0) { + setTimeout(timeout); + } else { + if (updateDeckTask != null) { + updateDeckTask.cancel(true); + } + setTimeout(0); + countdown.stop(); + removeDeckEditor(); + } } - setTimeout(0); - countdown.stop(); - removeDeckEditor(); - } - } - }); + }); } /** @@ -154,7 +154,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { this.tableId = tableId; this.mode = mode; this.btnAddLand.setVisible(false); - + switch (mode) { case LIMITED_BUILDING: this.btnAddLand.setVisible(true); @@ -209,149 +209,145 @@ public class DeckEditorPanel extends javax.swing.JPanel { component.clearCardEventListeners(); component.addCardEventListener( new Listener() { - @Override - public void event(Event event) { - switch (event.getEventName()) { - case "double-click": - moveSelectorCardToDeck(event); - break; - case "alt-double-click": - if (mode == DeckEditorMode.FREE_BUILDING) { - moveSelectorCardToSideboard(event); - } else { - // because in match mode selector is used as sideboard the card goes to deck also for shift click - moveSelectorCardToDeck(event); + @Override + public void event(Event event) { + switch (event.getEventName()) { + case "double-click": + moveSelectorCardToDeck(event); + break; + case "alt-double-click": + if (mode == DeckEditorMode.FREE_BUILDING) { + moveSelectorCardToSideboard(event); + } else { + // because in match mode selector is used as sideboard the card goes to deck also for shift click + moveSelectorCardToDeck(event); + } + break; + case "remove-main": + DeckEditorPanel.this.deckArea.getDeckList().handleDoubleClick(); + break; + case "remove-sideboard": + DeckEditorPanel.this.deckArea.getSideboardList().handleDoubleClick(); + break; } - break; - case "remove-main": - DeckEditorPanel.this.deckArea.getDeckList().handleDoubleClick(); - break; - case "remove-sideboard": - DeckEditorPanel.this.deckArea.getSideboardList().handleDoubleClick(); - break; - } - refreshDeck(); - } - }); + refreshDeck(); + } + }); } this.deckArea.clearDeckEventListeners(); this.deckArea.addDeckEventListener( new Listener() { - @Override - public void event(Event event) { - if (mode.equals(DeckEditorMode.FREE_BUILDING)) { - switch (event.getEventName()) { - case "double-click": - { - SimpleCardView cardView = (SimpleCardView) event.getSource(); - for (Card card : deck.getCards()) { - if (card.getId().equals(cardView.getId())) { - deck.getCards().remove(card); + @Override + public void event(Event event) { + if (mode.equals(DeckEditorMode.FREE_BUILDING)) { + switch (event.getEventName()) { + case "double-click": { + SimpleCardView cardView = (SimpleCardView) event.getSource(); + for (Card card : deck.getCards()) { + if (card.getId().equals(cardView.getId())) { + deck.getCards().remove(card); + break; + } + } + hidePopup(); + refreshDeck(); + break; + } + case "alt-double-click": { + SimpleCardView cardView = (SimpleCardView) event.getSource(); + for (Card card : deck.getCards()) { + if (card.getId().equals(cardView.getId())) { + deck.getCards().remove(card); + deck.getSideboard().add(card); + break; + } + } + hidePopup(); + refreshDeck(); + break; + } + case "set-number": { + setCardNumberToCardsList(event, deck.getCards()); + } + } + } else { + // constructing phase or sideboarding during match -> card goes always to sideboard + switch (event.getEventName()) { + case "double-click": + case "alt-double-click": { + SimpleCardView cardView = (SimpleCardView) event.getSource(); + for (Card card : deck.getCards()) { + if (card.getId().equals(cardView.getId())) { + deck.getCards().remove(card); + deck.getSideboard().add(card); + cardSelector.loadSideboard(new ArrayList<>(deck.getSideboard()), getBigCard()); + break; + } + } + hidePopup(); + refreshDeck(); break; } } - hidePopup(); - refreshDeck(); - break; } - case "alt-double-click": - { - SimpleCardView cardView = (SimpleCardView) event.getSource(); - for (Card card : deck.getCards()) { - if (card.getId().equals(cardView.getId())) { - deck.getCards().remove(card); - deck.getSideboard().add(card); - break; - } - } - hidePopup(); - refreshDeck(); - break; - } - case "set-number": - { - setCardNumberToCardsList(event, deck.getCards()); - } } - } else { - // constructing phase or sideboarding during match -> card goes always to sideboard - switch (event.getEventName()) { - case "double-click": - case "alt-double-click": - { - SimpleCardView cardView = (SimpleCardView) event.getSource(); - for (Card card : deck.getCards()) { - if (card.getId().equals(cardView.getId())) { - deck.getCards().remove(card); - deck.getSideboard().add(card); - cardSelector.loadSideboard(new ArrayList<>(deck.getSideboard()), getBigCard()); - break; - } - } - hidePopup(); - refreshDeck(); - break; - } - } - } - } - }); + }); this.deckArea.addSideboardEventListener( new Listener() { - @Override - public void event(Event event) { - if (mode.equals(DeckEditorMode.FREE_BUILDING)) { - // normal edit mode - switch (event.getEventName()) { - case "double-click": - // remove card from sideboard (don't add it to deck) - SimpleCardView cardView = (SimpleCardView) event.getSource(); - for (Card card : deck.getSideboard()) { - if (card.getId().equals(cardView.getId())) { - deck.getSideboard().remove(card); + @Override + public void event(Event event) { + if (mode.equals(DeckEditorMode.FREE_BUILDING)) { + // normal edit mode + switch (event.getEventName()) { + case "double-click": + // remove card from sideboard (don't add it to deck) + SimpleCardView cardView = (SimpleCardView) event.getSource(); + for (Card card : deck.getSideboard()) { + if (card.getId().equals(cardView.getId())) { + deck.getSideboard().remove(card); + break; + } + } + hidePopup(); + refreshDeck(); break; - } - } - hidePopup(); - refreshDeck(); - break; - case "alt-double-click": - // remove card from sideboard - cardView = (SimpleCardView) event.getSource(); - for (Card card : deck.getSideboard()) { - if (card.getId().equals(cardView.getId())) { - deck.getSideboard().remove(card); - deck.getCards().add(card); + case "alt-double-click": + // remove card from sideboard + cardView = (SimpleCardView) event.getSource(); + for (Card card : deck.getSideboard()) { + if (card.getId().equals(cardView.getId())) { + deck.getSideboard().remove(card); + deck.getCards().add(card); + break; + } + } + hidePopup(); + refreshDeck(); break; + case "set-number": { + setCardNumberToCardsList(event, deck.getSideboard()); } - } - hidePopup(); - refreshDeck(); - break; - case "set-number": - { - setCardNumberToCardsList(event, deck.getSideboard()); - } - } - } else { - // construct phase or sideboarding during match - switch (event.getEventName()) { - case "double-click": - case "alt-double-click": - SimpleCardView cardView = (SimpleCardView) event.getSource(); - for (Card card : deck.getSideboard()) { - if (card.getId().equals(cardView.getId())) { - deck.getSideboard().remove(card); - deck.getCards().add(card); + } + } else { + // construct phase or sideboarding during match + switch (event.getEventName()) { + case "double-click": + case "alt-double-click": + SimpleCardView cardView = (SimpleCardView) event.getSource(); + for (Card card : deck.getSideboard()) { + if (card.getId().equals(cardView.getId())) { + deck.getSideboard().remove(card); + deck.getCards().add(card); + break; + } + } + hidePopup(); + refreshDeck(); break; - } - } hidePopup(); - refreshDeck(); - break; + } + } } - } - } - }); + }); refreshDeck(); this.setVisible(true); @@ -364,8 +360,8 @@ public class DeckEditorPanel extends javax.swing.JPanel { int cardsFound = 0; List toDelete = new ArrayList<>(); for (Card card : cards) { - if (card.getName().equals(cardView.getName()) - && card.getCardNumber() == cardView.getCardNumber() + if (card.getName().equals(cardView.getName()) + && card.getCardNumber() == cardView.getCardNumber() && card.getExpansionSetCode().equals(cardView.getExpansionSetCode())) { cardsFound++; if (cardsFound > numberToSet) { @@ -373,23 +369,23 @@ public class DeckEditorPanel extends javax.swing.JPanel { } } - } + } if (toDelete.isEmpty()) { // add cards CardInfo cardInfo = CardRepository.instance.findCard(cardView.getExpansionSetCode(), cardView.getCardNumber()); for (int i = cardsFound; i < numberToSet; i++) { cards.add(cardInfo.getMockCard()); - } + } } else { - // remove cards - for (Card card: toDelete) { + // remove cards + for (Card card : toDelete) { cards.remove(card); } } hidePopup(); refreshDeck(); } - + private void moveSelectorCardToDeck(Event event) { SimpleCardView cardView = (SimpleCardView) event.getSource(); CardInfo cardInfo = CardRepository.instance.findCard(cardView.getExpansionSetCode(), cardView.getCardNumber()); @@ -417,7 +413,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { ((CardInfoPane) cardInfoPane).setCard(new CardView(card), null); } hidePopup(); - } + } } private void moveSelectorCardToSideboard(Event event) { @@ -432,7 +428,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { } hidePopup(); } - + private void hidePopup() { Plugins.getInstance().getActionCallback().mouseExited(null, null); } @@ -483,7 +479,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { text = text + Integer.toString(second); } this.txtTimeRemaining.setText(text); - if (s==60) { + if (s == 60) { AudioManager.playOnCountdown1(); } } @@ -602,75 +598,73 @@ public class DeckEditorPanel extends javax.swing.JPanel { jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - /*.addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(jLayeredPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 256, Short.MAX_VALUE))*/ - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(6, 6, 6) - .addComponent(lblDeckName) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(txtDeckName, javax.swing.GroupLayout.DEFAULT_SIZE, 189, Short.MAX_VALUE)) - - .addComponent(cardInfoPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(bigCard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + /*.addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLayeredPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 256, Short.MAX_VALUE))*/ .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(btnSave) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnLoad) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnNew) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnExit)) - .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(btnImport) - .addContainerGap() - .addComponent(btnAddLand) - .addContainerGap() - .addComponent(btnSubmit)) - .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(txtTimeRemaining)) - ) - .addContainerGap())); + .addGap(6, 6, 6) + .addComponent(lblDeckName) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtDeckName, javax.swing.GroupLayout.DEFAULT_SIZE, 189, Short.MAX_VALUE)) + .addComponent(cardInfoPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(bigCard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(btnSave) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnLoad) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnNew) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnExit)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(btnImport) + .addContainerGap() + .addComponent(btnAddLand) + .addContainerGap() + .addComponent(btnSubmit)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(txtTimeRemaining)) + ) + .addContainerGap())); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(txtDeckName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblDeckName)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btnSave) - .addComponent(btnLoad) - .addComponent(btnNew) - .addComponent(btnExit)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btnImport) - .addComponent(btnAddLand) - .addComponent(btnSubmit)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(txtTimeRemaining)) - //.addComponent(jLayeredPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, isShowCardInfo ? 30 : 159, Short.MAX_VALUE) - .addComponent(cardInfoPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 104, Short.MAX_VALUE) - .addComponent(bigCard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))); + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtDeckName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblDeckName)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnSave) + .addComponent(btnLoad) + .addComponent(btnNew) + .addComponent(btnExit)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnImport) + .addComponent(btnAddLand) + .addComponent(btnSubmit)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtTimeRemaining)) + //.addComponent(jLayeredPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, isShowCardInfo ? 30 : 159, Short.MAX_VALUE) + .addComponent(cardInfoPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 104, Short.MAX_VALUE) + .addComponent(bigCard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 261, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0) - .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 604, Short.MAX_VALUE))); + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 261, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 604, Short.MAX_VALUE))); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) @@ -697,7 +691,9 @@ public class DeckEditorPanel extends javax.swing.JPanel { } refreshDeck(); try { - MageFrame.getPreferences().put("lastDeckFolder", file.getCanonicalPath()); + if (file != null) { + MageFrame.getPreferences().put("lastDeckFolder", file.getCanonicalPath()); + } } catch (IOException ex) { } } @@ -800,7 +796,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { addLand.showDialog(deck, mode); refreshDeck(); }//GEN-LAST:event_btnAddLandActionPerformed - + // Variables declaration - do not modify//GEN-BEGIN:variables private mage.client.cards.BigCard bigCard; private javax.swing.JButton btnExit; diff --git a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.form b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.form index e84af7c5e33..8d7227bc5f4 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.form @@ -28,18 +28,13 @@ - - - - - - + @@ -53,14 +48,29 @@ + - + + + + + + + + + + + + + + + @@ -85,6 +95,11 @@ + + + + + @@ -96,13 +111,16 @@ - + + + + @@ -152,6 +170,16 @@ + + + + + + + + + + @@ -209,5 +237,23 @@ + + + + + + + + + + + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java index ba8cbb2bf65..9a59abd1730 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java @@ -56,16 +56,17 @@ import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import javax.swing.JLayeredPane; import javax.swing.JOptionPane; import javax.swing.SwingWorker; import mage.client.MageFrame; import static mage.client.dialog.PreferencesDialog.KEY_CONNECTION_URL_SERVER_LIST; import static mage.client.dialog.PreferencesDialog.KEY_CONNECT_AUTO_CONNECT; import static mage.client.dialog.PreferencesDialog.KEY_CONNECT_FLAG; +import mage.client.preference.MagePreferences; import mage.client.util.Config; import mage.client.util.gui.countryBox.CountryItemEditor; import mage.remote.Connection; -import mage.remote.Connection.ProxyType; import org.apache.log4j.Logger; /** @@ -76,6 +77,8 @@ public class ConnectDialog extends MageDialog { private static final Logger logger = Logger.getLogger(ConnectDialog.class); private Connection connection; private ConnectTask task; + private RegisterUserDialog registerUserDialog; + private ResetPasswordDialog resetPasswordDialog; private final ActionListener connectAction = new ActionListener() { @Override @@ -90,15 +93,24 @@ public class ConnectDialog extends MageDialog { public ConnectDialog() { initComponents(); - this.txtUserName.addActionListener(connectAction); this.txtServer.addActionListener(connectAction); this.txtPort.addActionListener(connectAction); + this.txtUserName.addActionListener(connectAction); + this.txtPassword.addActionListener(connectAction); + + registerUserDialog = new RegisterUserDialog(this); + MageFrame.getDesktop().add(registerUserDialog, JLayeredPane.POPUP_LAYER); + + resetPasswordDialog = new ResetPasswordDialog(this); + MageFrame.getDesktop().add(resetPasswordDialog, JLayeredPane.POPUP_LAYER); } public void showDialog() { - this.txtServer.setText(MageFrame.getPreferences().get("serverAddress", Config.serverName)); - this.txtPort.setText(MageFrame.getPreferences().get("serverPort", Integer.toString(Config.port))); - this.txtUserName.setText(MageFrame.getPreferences().get("userName", "")); + String serverAddress = MagePreferences.getServerAddressWithDefault(Config.serverName); + this.txtServer.setText(serverAddress); + this.txtPort.setText(Integer.toString(MagePreferences.getServerPortWithDefault(Config.port))); + this.txtUserName.setText(MagePreferences.getUserName(serverAddress)); + this.txtPassword.setText(MagePreferences.getPassword(serverAddress)); this.chkAutoConnect.setSelected(Boolean.parseBoolean(MageFrame.getPreferences().get(KEY_CONNECT_AUTO_CONNECT, "false"))); this.chkForceUpdateDB.setSelected(false); // has always to be set manually to force comparison @@ -117,9 +129,11 @@ public class ConnectDialog extends MageDialog { } private void saveSettings() { - MageFrame.getPreferences().put("serverAddress", txtServer.getText().trim()); - MageFrame.getPreferences().put("serverPort", txtPort.getText().trim()); - MageFrame.getPreferences().put("userName", txtUserName.getText().trim()); + String serverAddress = txtServer.getText().trim(); + MagePreferences.setServerAddress(serverAddress); + MagePreferences.setServerPort(Integer.parseInt(txtPort.getText().trim())); + MagePreferences.setUserName(serverAddress, txtUserName.getText().trim()); + MagePreferences.setPassword(serverAddress, txtPassword.getText().trim()); MageFrame.getPreferences().put(KEY_CONNECT_AUTO_CONNECT, Boolean.toString(chkAutoConnect.isSelected())); } @@ -139,6 +153,8 @@ public class ConnectDialog extends MageDialog { txtPort = new javax.swing.JTextField(); lblUserName = new javax.swing.JLabel(); txtUserName = new javax.swing.JTextField(); + lblPassword = new javax.swing.JLabel(); + txtPassword = new javax.swing.JPasswordField(); lblFlag = new javax.swing.JLabel(); cbFlag = new mage.client.util.gui.countryBox.CountryComboBox(); chkAutoConnect = new javax.swing.JCheckBox(); @@ -147,6 +163,8 @@ public class ConnectDialog extends MageDialog { btnConnect = new javax.swing.JButton(); btnCancel = new javax.swing.JButton(); lblStatus = new javax.swing.JLabel(); + btnRegister = new javax.swing.JButton(); + btnForgotPassword = new javax.swing.JButton(); setTitle("Connect to server"); setNormalBounds(new java.awt.Rectangle(100, 100, 410, 307)); @@ -175,6 +193,9 @@ public class ConnectDialog extends MageDialog { lblUserName.setLabelFor(txtUserName); lblUserName.setText("User name:"); + lblPassword.setLabelFor(txtPassword); + lblPassword.setText("Password:"); + lblFlag.setLabelFor(txtUserName); lblFlag.setText("User flag:"); @@ -217,6 +238,22 @@ public class ConnectDialog extends MageDialog { } }); + btnRegister.setText("Register new user"); + btnRegister.setToolTipText("XMage now supports user authentication.
Register your account before you log in."); + btnRegister.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnRegisterActionPerformed(evt); + } + }); + + btnForgotPassword.setText("Forgot password"); + btnForgotPassword.setToolTipText("You can reset your password if you have registered
your account with an email address."); + btnForgotPassword.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnForgotPasswordActionPerformed(evt); + } + }); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( @@ -224,17 +261,13 @@ public class ConnectDialog extends MageDialog { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(btnConnect) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnCancel)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(lblPort) .addComponent(lblServer) - .addComponent(lblUserName)) + .addComponent(lblUserName) + .addComponent(lblPassword)) .addComponent(lblFlag, javax.swing.GroupLayout.Alignment.TRAILING)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -245,11 +278,23 @@ public class ConnectDialog extends MageDialog { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) .addComponent(txtServer, javax.swing.GroupLayout.DEFAULT_SIZE, 286, Short.MAX_VALUE) .addComponent(txtPort, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(txtUserName)) + .addComponent(txtUserName) + .addComponent(txtPassword)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(btnFind)) .addComponent(chkForceUpdateDB, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(chkAutoConnect, javax.swing.GroupLayout.DEFAULT_SIZE, 358, Short.MAX_VALUE)))) + .addComponent(chkAutoConnect, javax.swing.GroupLayout.DEFAULT_SIZE, 375, Short.MAX_VALUE))) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(btnRegister) + .addGroup(layout.createSequentialGroup() + .addComponent(btnConnect) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnForgotPassword) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnCancel))) + .addGap(26, 26, 26))) .addContainerGap()) ); layout.setVerticalGroup( @@ -269,6 +314,10 @@ public class ConnectDialog extends MageDialog { .addComponent(txtUserName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(lblUserName)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblPassword)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addComponent(lblFlag, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(cbFlag, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) @@ -278,12 +327,15 @@ public class ConnectDialog extends MageDialog { .addComponent(chkForceUpdateDB) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jProxySettingsButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 50, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 38, Short.MAX_VALUE) .addComponent(lblStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(btnConnect) - .addComponent(btnCancel)) + .addComponent(btnCancel) + .addComponent(btnForgotPassword)) + .addGap(3, 3, 3) + .addComponent(btnRegister) .addContainerGap()) ); @@ -302,10 +354,6 @@ public class ConnectDialog extends MageDialog { private void btnConnectActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnConnectActionPerformed - if (txtUserName.getText().isEmpty()) { - JOptionPane.showMessageDialog(rootPane, "Please provide a user name"); - return; - } if (txtServer.getText().trim().isEmpty()) { JOptionPane.showMessageDialog(rootPane, "Please provide a server address"); return; @@ -314,9 +362,14 @@ public class ConnectDialog extends MageDialog { JOptionPane.showMessageDialog(rootPane, "Please provide a port number"); return; } + if (txtUserName.getText().isEmpty()) { + JOptionPane.showMessageDialog(rootPane, "Please provide a user name"); + return; + } + // txtPassword is not checked here, because authentication might be disabled by the server config. if (Integer.valueOf(txtPort.getText()) < 1 || Integer.valueOf(txtPort.getText()) > 65535) { JOptionPane.showMessageDialog(rootPane, "Invalid port number"); - txtPort.setText(MageFrame.getPreferences().get("serverPort", Integer.toString(Config.port))); + txtPort.setText(Integer.toString(MagePreferences.getServerPortWithDefault(Config.port))); return; } @@ -327,30 +380,10 @@ public class ConnectDialog extends MageDialog { connection.setHost(this.txtServer.getText().trim()); connection.setPort(Integer.valueOf(this.txtPort.getText().trim())); connection.setUsername(this.txtUserName.getText().trim()); + connection.setPassword(this.txtPassword.getText().trim()); connection.setForceDBComparison(this.chkForceUpdateDB.isSelected()); MageFrame.getPreferences().put(KEY_CONNECT_FLAG, ((CountryItemEditor) cbFlag.getEditor()).getImageItem()); - - ProxyType configProxyType = Connection.ProxyType.valueByText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PROXY_TYPE, "None")); - - if (configProxyType != null) { - connection.setProxyType(configProxyType); - if (!configProxyType.equals(ProxyType.NONE)) { - String host = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PROXY_ADDRESS, ""); - String port = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PROXY_PORT, ""); - if (!host.isEmpty() && !port.isEmpty()) { - connection.setProxyHost(host); - connection.setProxyPort(Integer.valueOf(port)); - String username = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PROXY_USERNAME, ""); - connection.setProxyUsername(username); - if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PROXY_REMEMBER, "false").equals("true")) { - String password = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PROXY_PSWD, ""); - connection.setProxyPassword(password); - } - } else { - logger.warn("host or\\and port are empty: host=" + host + ", port=" + port); - } - } - } + PreferencesDialog.setProxyInformation(connection); // pref settings MageFrame.getInstance().setUserPrefsToConnection(connection); @@ -514,8 +547,12 @@ public class ConnectDialog extends MageDialog { if (selectedServer != null) { String[] params = selectedServer.split(":"); if (params.length == 3) { - this.txtServer.setText(params[1]); + String serverAddress = params[1]; + this.txtServer.setText(serverAddress); this.txtPort.setText(params[2]); + // Update userName and password according to the chosen server. + this.txtUserName.setText(MagePreferences.getUserName(serverAddress)); + this.txtPassword.setText(MagePreferences.getPassword(serverAddress)); } else { JOptionPane.showMessageDialog(null, "Wrong server data format."); } @@ -541,19 +578,47 @@ public class ConnectDialog extends MageDialog { // TODO add your handling code here: }//GEN-LAST:event_chkForceUpdateDBActionPerformed + private void txtUserNameActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtUserNameActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_txtUserNameActionPerformed + + private void txtPasswordActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtPasswordActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_txtPasswordActionPerformed + + private void btnRegisterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRegisterActionPerformed + registerUserDialog.showDialog(); + }//GEN-LAST:event_btnRegisterActionPerformed + + private void btnForgotPasswordActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnForgotPasswordActionPerformed + resetPasswordDialog.showDialog(); + }//GEN-LAST:event_btnForgotPasswordActionPerformed + + public String getServer() { + return this.txtServer.getText(); + } + + public String getPort() { + return this.txtPort.getText(); + } + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton btnCancel; private javax.swing.JButton btnConnect; private javax.swing.JButton btnFind; + private javax.swing.JButton btnForgotPassword; + private javax.swing.JButton btnRegister; private mage.client.util.gui.countryBox.CountryComboBox cbFlag; private javax.swing.JCheckBox chkAutoConnect; private javax.swing.JCheckBox chkForceUpdateDB; private javax.swing.JButton jProxySettingsButton; private javax.swing.JLabel lblFlag; + private javax.swing.JLabel lblPassword; private javax.swing.JLabel lblPort; private javax.swing.JLabel lblServer; private javax.swing.JLabel lblStatus; private javax.swing.JLabel lblUserName; + private javax.swing.JPasswordField txtPassword; private javax.swing.JTextField txtPort; private javax.swing.JTextField txtServer; private javax.swing.JTextField txtUserName; diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java index 6199384a981..88e68ca8659 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java @@ -2298,6 +2298,30 @@ public class PreferencesDialog extends javax.swing.JDialog { this.repaint(); } + public static void setProxyInformation(Connection connection) { + ProxyType configProxyType = Connection.ProxyType.valueByText(getCachedValue(KEY_PROXY_TYPE, "None")); + if (configProxyType == null) { + return; + } + + connection.setProxyType(configProxyType); + if (!configProxyType.equals(ProxyType.NONE)) { + String host = getCachedValue(KEY_PROXY_ADDRESS, ""); + String port = getCachedValue(KEY_PROXY_PORT, ""); + if (!host.isEmpty() && !port.isEmpty()) { + connection.setProxyHost(host); + connection.setProxyPort(Integer.valueOf(port)); + String username = getCachedValue(KEY_PROXY_USERNAME, ""); + connection.setProxyUsername(username); + if (getCachedValue(KEY_PROXY_REMEMBER, "false").equals("true")) { + String password = getCachedValue(KEY_PROXY_PSWD, ""); + connection.setProxyPassword(password); + } + } else { + log.warn("host or\\and port are empty: host=" + host + ", port=" + port); + } + } + } /** * @param args the command line arguments */ diff --git a/Mage.Client/src/main/java/mage/client/dialog/RegisterUserDialog.form b/Mage.Client/src/main/java/mage/client/dialog/RegisterUserDialog.form new file mode 100644 index 00000000000..1b343dc991b --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/RegisterUserDialog.form @@ -0,0 +1,219 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/RegisterUserDialog.java b/Mage.Client/src/main/java/mage/client/dialog/RegisterUserDialog.java new file mode 100644 index 00000000000..54096eeb626 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/RegisterUserDialog.java @@ -0,0 +1,286 @@ +package mage.client.dialog; + +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import javax.swing.SwingWorker; +import mage.client.MageFrame; +import mage.client.preference.MagePreferences; +import mage.remote.Connection; +import mage.remote.Session; +import mage.remote.SessionImpl; +import org.apache.log4j.Logger; + +public class RegisterUserDialog extends MageDialog { + + private static final Logger logger = Logger.getLogger(ConnectDialog.class); + private ConnectDialog connectDialog; + private Connection connection; + private ConnectTask task; + private Session session; + + /** + * Creates new form RegisterUserDialog + */ + public RegisterUserDialog(ConnectDialog connectDialog) { + initComponents(); + this.connectDialog = connectDialog; + } + + public void showDialog() { + this.txtServer.setText(this.connectDialog.getServer()); + this.txtPort.setText(this.connectDialog.getPort()); + this.lblStatus.setText(""); + + this.setModal(true); + this.setLocation(50, 50); + 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() { + + lblServer = new javax.swing.JLabel(); + lblPort = new javax.swing.JLabel(); + lblUserName = new javax.swing.JLabel(); + lblPassword = new javax.swing.JLabel(); + txtUserName = new javax.swing.JTextField(); + txtPassword = new javax.swing.JPasswordField(); + btnRegister = new javax.swing.JButton(); + btnCancel = new javax.swing.JButton(); + lblStatus = new javax.swing.JLabel(); + txtServer = new javax.swing.JTextField(); + txtPort = new javax.swing.JTextField(); + txtEmail = new javax.swing.JTextField(); + lblPasswordConfirmation = new javax.swing.JLabel(); + txtPasswordConfirmation = new javax.swing.JPasswordField(); + lblEmail = new javax.swing.JLabel(); + lblPasswordConfirmationReasoning = new javax.swing.JLabel(); + lblEmailReasoning = new javax.swing.JLabel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setTitle("Register"); + + lblServer.setLabelFor(txtServer); + lblServer.setText("Server:"); + + lblPort.setLabelFor(txtPort); + lblPort.setText("Port:"); + + lblUserName.setLabelFor(txtUserName); + lblUserName.setText("User name:"); + + lblPassword.setLabelFor(txtPassword); + lblPassword.setText("Password:"); + + txtUserName.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtUserNameActionPerformed(evt); + } + }); + + btnRegister.setText("Register"); + btnRegister.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnRegisterActionPerformed(evt); + } + }); + + btnCancel.setText("Cancel"); + btnCancel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnCancelActionPerformed(evt); + } + }); + + lblStatus.setToolTipText(""); + + lblPasswordConfirmation.setLabelFor(txtPasswordConfirmation); + lblPasswordConfirmation.setText("Password:"); + + lblEmail.setLabelFor(txtEmail); + lblEmail.setText("Email:"); + + lblPasswordConfirmationReasoning.setFont(new java.awt.Font("Lucida Grande", 0, 10)); // NOI18N + lblPasswordConfirmationReasoning.setLabelFor(txtPasswordConfirmation); + lblPasswordConfirmationReasoning.setText("(confirmation)"); + + lblEmailReasoning.setFont(new java.awt.Font("Lucida Grande", 0, 10)); // NOI18N + lblEmailReasoning.setLabelFor(txtEmail); + lblEmailReasoning.setText("(used for password reset)"); + lblEmailReasoning.setToolTipText(""); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblPasswordConfirmationReasoning) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblServer) + .addComponent(lblUserName) + .addComponent(lblPort) + .addComponent(lblPassword) + .addComponent(lblPasswordConfirmation) + .addComponent(lblEmail)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtUserName, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtPasswordConfirmation, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtEmail, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(lblEmailReasoning) + .addGroup(layout.createSequentialGroup() + .addComponent(btnRegister) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnCancel))) + .addComponent(lblStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap(22, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(9, 9, 9) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblServer) + .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblPort) + .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblUserName) + .addComponent(txtUserName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblPassword) + .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtPasswordConfirmation, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblPasswordConfirmation)) + .addComponent(lblPasswordConfirmationReasoning) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblEmail) + .addComponent(txtEmail, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblEmailReasoning) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnCancel) + .addComponent(btnRegister)) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + + private void txtUserNameActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtUserNameActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_txtUserNameActionPerformed + + private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed + this.hideDialog(); + }//GEN-LAST:event_btnCancelActionPerformed + + private void btnRegisterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRegisterActionPerformed + if (!this.txtPassword.getText().equals(this.txtPasswordConfirmation.getText())) { + MageFrame.getInstance().showError("Passwords don't match."); + return; + } + connection = new Connection(); + connection.setHost(this.txtServer.getText().trim()); + connection.setPort(Integer.valueOf(this.txtPort.getText().trim())); + connection.setUsername(this.txtUserName.getText().trim()); + connection.setPassword(this.txtPassword.getText().trim()); + connection.setEmail(this.txtEmail.getText().trim()); + PreferencesDialog.setProxyInformation(connection); + task = new ConnectTask(); + task.execute(); + }//GEN-LAST:event_btnRegisterActionPerformed + + private class ConnectTask extends SwingWorker { + + private boolean result = false; + + private static final int CONNECTION_TIMEOUT_MS = 2100; + + @Override + protected Boolean doInBackground() throws Exception { + lblStatus.setText("Connecting..."); + btnRegister.setEnabled(false); + session = new SessionImpl(MageFrame.getInstance()); + result = session.register(connection); + return result; + } + + @Override + protected void done() { + try { + get(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS); + if (result) { + // Save settings. + MagePreferences.setServerAddress(connection.getHost()); + MagePreferences.setServerPort(connection.getPort()); + MagePreferences.setUserName(connection.getHost(), connection.getUsername()); + MagePreferences.setPassword(connection.getHost(), connection.getPassword()); + MagePreferences.setEmail(connection.getHost(), connection.getEmail()); + + String message = "Registration succeeded"; + lblStatus.setText(message); + MageFrame.getInstance().showMessage(message); + hideDialog(); + } else { + lblStatus.setText("Could not register"); + } + } catch (InterruptedException | ExecutionException ex) { + logger.fatal("Registration task error", ex); + } catch (CancellationException ex) { + logger.info("Registration was canceled"); + lblStatus.setText("Registration was canceled (but an account might have been actually created)"); + } catch (TimeoutException ex) { + logger.fatal("Registration timeout: ", ex); + } finally { + MageFrame.stopConnecting(); + btnRegister.setEnabled(true); + } + } + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton btnCancel; + private javax.swing.JButton btnRegister; + private javax.swing.JLabel lblEmail; + private javax.swing.JLabel lblEmailReasoning; + private javax.swing.JLabel lblPassword; + private javax.swing.JLabel lblPasswordConfirmation; + private javax.swing.JLabel lblPasswordConfirmationReasoning; + private javax.swing.JLabel lblPort; + private javax.swing.JLabel lblServer; + private javax.swing.JLabel lblStatus; + private javax.swing.JLabel lblUserName; + private javax.swing.JTextField txtEmail; + private javax.swing.JPasswordField txtPassword; + private javax.swing.JPasswordField txtPasswordConfirmation; + private javax.swing.JTextField txtPort; + private javax.swing.JTextField txtServer; + private javax.swing.JTextField txtUserName; + // End of variables declaration//GEN-END:variables +} diff --git a/Mage.Client/src/main/java/mage/client/dialog/ResetPasswordDialog.form b/Mage.Client/src/main/java/mage/client/dialog/ResetPasswordDialog.form new file mode 100644 index 00000000000..36bf18ac94e --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/ResetPasswordDialog.form @@ -0,0 +1,320 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/ResetPasswordDialog.java b/Mage.Client/src/main/java/mage/client/dialog/ResetPasswordDialog.java new file mode 100644 index 00000000000..fa5db9f4a14 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/ResetPasswordDialog.java @@ -0,0 +1,431 @@ +package mage.client.dialog; + +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import javax.swing.SwingWorker; +import mage.client.MageFrame; +import mage.client.preference.MagePreferences; +import mage.remote.Connection; +import mage.remote.Session; +import mage.remote.SessionImpl; +import org.apache.log4j.Logger; + +public class ResetPasswordDialog extends MageDialog { + + private static final Logger logger = Logger.getLogger(ResetPasswordDialog.class); + private ConnectDialog connectDialog; + private Connection connection; + private Session session; + private GetAuthTokenTask getAuthTokenTask; + private ResetPasswordTask resetPasswordTask; + + /** + * Creates new form ResetPasswordDialog + */ + public ResetPasswordDialog(ConnectDialog connectDialog) { + initComponents(); + this.connectDialog = connectDialog; + } + + public void showDialog() { + String serverAddress = this.connectDialog.getServer(); + this.txtServer.setText(serverAddress); + this.txtPort.setText(this.connectDialog.getPort()); + this.txtEmail.setText(MagePreferences.getEmail(serverAddress)); + this.lblStatus.setText(""); + + this.setModal(true); + this.setLocation(50, 50); + 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() { + + jPanel2 = new javax.swing.JPanel(); + jLabel6 = new javax.swing.JLabel(); + lblAuthToken = new javax.swing.JLabel(); + lblPassword = new javax.swing.JLabel(); + lblPasswordConfirmation = new javax.swing.JLabel(); + txtAuthToken = new javax.swing.JTextField(); + btnSubmitNewPassword = new javax.swing.JButton(); + lblPasswordConfirmationReasoning = new javax.swing.JLabel(); + txtPassword = new javax.swing.JPasswordField(); + txtPasswordConfirmation = new javax.swing.JPasswordField(); + jPanel1 = new javax.swing.JPanel(); + jLabel5 = new javax.swing.JLabel(); + lblEmail = new javax.swing.JLabel(); + txtEmail = new javax.swing.JTextField(); + btnGetAuthToken = new javax.swing.JButton(); + lblStatus = new javax.swing.JLabel(); + btnCancel = new javax.swing.JButton(); + lblServer = new javax.swing.JLabel(); + txtServer = new javax.swing.JTextField(); + txtPort = new javax.swing.JTextField(); + lblPort = new javax.swing.JLabel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setTitle("Reset password"); + + jPanel2.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + + jLabel6.setFont(new java.awt.Font("Lucida Grande", 1, 13)); // NOI18N + jLabel6.setText("Step 2:"); + + lblAuthToken.setLabelFor(txtAuthToken); + lblAuthToken.setText("Auth token:"); + + lblPassword.setLabelFor(txtPassword); + lblPassword.setText("New password:"); + + lblPasswordConfirmation.setLabelFor(txtPasswordConfirmation); + lblPasswordConfirmation.setText("New password:"); + + btnSubmitNewPassword.setText("Submit a new password"); + btnSubmitNewPassword.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnSubmitNewPasswordActionPerformed(evt); + } + }); + + lblPasswordConfirmationReasoning.setFont(new java.awt.Font("Lucida Grande", 0, 10)); // NOI18N + lblPasswordConfirmationReasoning.setLabelFor(txtPasswordConfirmation); + lblPasswordConfirmationReasoning.setText("(confirmation)"); + + javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addComponent(jLabel6) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(lblAuthToken, javax.swing.GroupLayout.PREFERRED_SIZE, 74, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblPassword, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblPasswordConfirmation, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(txtAuthToken) + .addComponent(txtPassword) + .addComponent(txtPasswordConfirmation))) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup() + .addGap(0, 204, Short.MAX_VALUE) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblPasswordConfirmationReasoning, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(btnSubmitNewPassword, javax.swing.GroupLayout.Alignment.TRAILING)))) + .addContainerGap()) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addComponent(jLabel6) + .addGap(24, 24, 24) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblAuthToken) + .addComponent(txtAuthToken, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblPassword) + .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblPasswordConfirmation) + .addComponent(txtPasswordConfirmation, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblPasswordConfirmationReasoning) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(btnSubmitNewPassword) + .addContainerGap(9, Short.MAX_VALUE)) + ); + + jPanel1.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + + jLabel5.setFont(new java.awt.Font("Lucida Grande", 1, 13)); // NOI18N + jLabel5.setText("Step 1:"); + + lblEmail.setLabelFor(txtEmail); + lblEmail.setText("Email:"); + + btnGetAuthToken.setText("Email an auth token"); + btnGetAuthToken.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnGetAuthTokenActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jLabel5) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(lblEmail) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtEmail)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(btnGetAuthToken))) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jLabel5) + .addGap(24, 24, 24) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblEmail) + .addComponent(txtEmail, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnGetAuthToken) + .addContainerGap()) + ); + + btnCancel.setText("Cancel"); + btnCancel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnCancelActionPerformed(evt); + } + }); + + lblServer.setLabelFor(txtServer); + lblServer.setText("Server:"); + + lblPort.setLabelFor(txtPort); + lblPort.setText("Port:"); + + 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() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(btnCancel)) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblServer) + .addComponent(lblPort)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(txtServer) + .addComponent(txtPort)))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblServer) + .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblPort)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnCancel) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + private void btnGetAuthTokenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnGetAuthTokenActionPerformed + if (this.txtEmail.getText().length() == 0) { + MageFrame.getInstance().showError("Please enter an email address."); + return; + } + + connection = new Connection(); + connection.setHost(this.txtServer.getText().trim()); + connection.setPort(Integer.valueOf(this.txtPort.getText().trim())); + PreferencesDialog.setProxyInformation(connection); + connection.setEmail(this.txtEmail.getText().trim()); + + getAuthTokenTask = new GetAuthTokenTask(); + getAuthTokenTask.execute(); + }//GEN-LAST:event_btnGetAuthTokenActionPerformed + + private void btnSubmitNewPasswordActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSubmitNewPasswordActionPerformed + if (this.txtEmail.getText().length() == 0) { + MageFrame.getInstance().showError("Please enter an email address."); + return; + } + if (this.txtAuthToken.getText().length() == 0) { + MageFrame.getInstance().showError("Please enter an auth token."); + return; + } + if (this.txtPassword.getText().length() == 0) { + MageFrame.getInstance().showError("Please enter a new password."); + return; + } + if (!this.txtPassword.getText().equals(this.txtPasswordConfirmation.getText())) { + MageFrame.getInstance().showError("Passwords don't match."); + return; + } + + connection = new Connection(); + connection.setHost(this.txtServer.getText().trim()); + connection.setPort(Integer.valueOf(this.txtPort.getText().trim())); + PreferencesDialog.setProxyInformation(connection); + connection.setEmail(this.txtEmail.getText().trim()); + connection.setAuthToken(this.txtAuthToken.getText().trim()); + connection.setPassword(this.txtPassword.getText().trim()); + + resetPasswordTask = new ResetPasswordTask(); + resetPasswordTask.execute(); + }//GEN-LAST:event_btnSubmitNewPasswordActionPerformed + + private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed + this.hideDialog(); + }//GEN-LAST:event_btnCancelActionPerformed + + void disableButtons() { + btnGetAuthToken.setEnabled(false); + btnSubmitNewPassword.setEnabled(false); + } + + void enableButtons() { + btnGetAuthToken.setEnabled(true); + btnSubmitNewPassword.setEnabled(true); + } + + private class GetAuthTokenTask extends SwingWorker { + + private boolean result = false; + + private static final int CONNECTION_TIMEOUT_MS = 2100; + + @Override + protected Boolean doInBackground() throws Exception { + lblStatus.setText("Connecting..."); + disableButtons(); + session = new SessionImpl(MageFrame.getInstance()); + result = session.emailAuthToken(connection); + return result; + } + + @Override + protected void done() { + try { + get(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS); + if (result) { + // Save settings. + MagePreferences.setEmail(connection.getHost(), connection.getEmail()); + + String message = "Auth token is emailed. Please check your inbox."; + lblStatus.setText(message); + MageFrame.getInstance().showMessage(message); + } else { + lblStatus.setText("There was an issue while requesting an auth token."); + } + } catch (InterruptedException | ExecutionException ex) { + logger.fatal("Get Auth Token Task error", ex); + } catch (CancellationException ex) { + logger.info("Canceled"); + lblStatus.setText("Canceled"); + } catch (TimeoutException ex) { + logger.fatal("Timeout: ", ex); + } finally { + MageFrame.stopConnecting(); + enableButtons(); + } + } + } + + private class ResetPasswordTask extends SwingWorker { + + private boolean result = false; + + private static final int CONNECTION_TIMEOUT_MS = 2100; + + @Override + protected Boolean doInBackground() throws Exception { + lblStatus.setText("Connecting..."); + disableButtons(); + session = new SessionImpl(MageFrame.getInstance()); + result = session.resetPassword(connection); + return result; + } + + @Override + protected void done() { + try { + get(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS); + if (result) { + // Save settings. + MagePreferences.setPassword(connection.getHost(), connection.getPassword()); + + String message = "Password is reset successfully."; + lblStatus.setText(message); + MageFrame.getInstance().showMessage(message); + hideDialog(); + } else { + lblStatus.setText("There was an issue while resetting password."); + } + } catch (InterruptedException | ExecutionException ex) { + logger.fatal("Reset Password Task error", ex); + } catch (CancellationException ex) { + logger.info("Canceled"); + lblStatus.setText("Canceled"); + } catch (TimeoutException ex) { + logger.fatal("Timeout: ", ex); + } finally { + MageFrame.stopConnecting(); + enableButtons(); + } + } + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton btnCancel; + private javax.swing.JButton btnGetAuthToken; + private javax.swing.JButton btnSubmitNewPassword; + private javax.swing.JLabel jLabel5; + private javax.swing.JLabel jLabel6; + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel2; + private javax.swing.JLabel lblAuthToken; + private javax.swing.JLabel lblEmail; + private javax.swing.JLabel lblPassword; + private javax.swing.JLabel lblPasswordConfirmation; + private javax.swing.JLabel lblPasswordConfirmationReasoning; + private javax.swing.JLabel lblPort; + private javax.swing.JLabel lblServer; + private javax.swing.JLabel lblStatus; + private javax.swing.JTextField txtAuthToken; + private javax.swing.JTextField txtEmail; + private javax.swing.JPasswordField txtPassword; + private javax.swing.JPasswordField txtPasswordConfirmation; + private javax.swing.JTextField txtPort; + private javax.swing.JTextField txtServer; + // End of variables declaration//GEN-END:variables +} diff --git a/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java b/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java index 9840c82582b..2f307ea2f78 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java @@ -26,7 +26,7 @@ * or implied, of BetaSteward_at_googlemail.com. */ -/* + /* * TableWaitingDialog.java * * Created on Dec 16, 2009, 10:27:44 AM @@ -68,7 +68,7 @@ public class TableWaitingDialog extends MageDialog { private Session session; private final TableWaitModel tableWaitModel; private UpdateSeatsTask updateTask; - private static final int[] defaultColumnsWidth = {20, 50, 100, 100}; + private static final int[] defaultColumnsWidth = {20, 50, 100, 100, 100}; /** * Creates new form TableWaitingDialog @@ -268,10 +268,8 @@ public class TableWaitingDialog extends MageDialog { if (session.startMatch(roomId, tableId)) { closeDialog(); } - } else { - if (session.startTournament(roomId, tableId)) { - closeDialog(); - } + } else if (session.startTournament(roomId, tableId)) { + closeDialog(); } }//GEN-LAST:event_btnStartActionPerformed @@ -319,7 +317,7 @@ public class TableWaitingDialog extends MageDialog { class TableWaitModel extends AbstractTableModel { - private final String[] columnNames = new String[]{"Seat", "Loc", "Player Name", "Player Type"}; + private final String[] columnNames = new String[]{"Seat", "Loc", "Player Name", "Player Type", "History"}; private SeatView[] seats = new SeatView[0]; public void loadData(TableView table) { @@ -353,6 +351,8 @@ class TableWaitModel extends AbstractTableModel { return seats[arg0].getPlayerName(); case 3: return seats[arg0].getPlayerType(); + case 4: + return seats[arg0].getHistory(); } } return ""; diff --git a/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java b/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java index 347b69c1267..01e872dc5a7 100644 --- a/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java +++ b/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java @@ -26,7 +26,7 @@ * or implied, of BetaSteward_at_googlemail.com. */ -/* + /* * PlayerPanel.java * * Created on Nov 18, 2009, 3:01:31 PM @@ -288,7 +288,8 @@ public class PlayerPanelExt extends javax.swing.JPanel { basicTooltipText = "Name: " + player.getName() + "
Country: " + countryname + "
Deck hash code: " + player.getDeckHashCode() - + "
Wins: " + player.getWins() + " of " + player.getWinsNeeded() + " (to win the match)"; + + "
This match wins: " + player.getWins() + " of " + player.getWinsNeeded() + " (to win the match)" + + (player.getUserData() == null ? "" : "
History: " + player.getUserData().getHistory()); } // Extend tooltip StringBuilder tooltipText = new StringBuilder(basicTooltipText); @@ -580,7 +581,7 @@ public class PlayerPanelExt extends javax.swing.JPanel { manaCountLabelX.setText("0"); manaLabels.put("X", manaCountLabelX); r = new Rectangle(12, 12); - BufferedImage imageManaX = ManaSymbols.getManaSymbolImageSmall("X"); + BufferedImage imageManaX = ManaSymbols.getManaSymbolImageSmall("C"); HoverButton btnColorlessMana = new HoverButton(null, imageManaX, imageManaX, imageManaX, r); btnColorlessMana.setToolTipText("Colorless mana"); btnColorlessMana.setOpaque(false); diff --git a/Mage.Client/src/main/java/mage/client/preference/MagePreferences.java b/Mage.Client/src/main/java/mage/client/preference/MagePreferences.java new file mode 100644 index 00000000000..98e861c60e2 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/preference/MagePreferences.java @@ -0,0 +1,85 @@ +package mage.client.preference; + +import java.util.prefs.Preferences; +import mage.client.MageFrame; + +// TODO: Move all preference related logic from MageFrame and PreferencesDialog to this class. +public class MagePreferences { + + private static final String KEY_SERVER_ADDRESS = "serverAddress"; + private static final String KEY_SERVER_PORT = "serverPort"; + private static final String KEY_USER_NAME = "userName"; + private static final String KEY_PASSWORD = "password"; + private static final String KEY_EMAIL = "email"; + private static final String KEY_AUTO_CONNECT = "autoConnect"; + + private static Preferences prefs() { + // TODO: Move MageFrame.prefs to this class. + return MageFrame.getPreferences(); + } + + public static String getServerAddress() { + return prefs().get(KEY_SERVER_ADDRESS, ""); + } + + public static String getServerAddressWithDefault(String defaultValue) { + return prefs().get(KEY_SERVER_ADDRESS, defaultValue); + } + + public static void setServerAddress(String serverAddress) { + prefs().put(KEY_SERVER_ADDRESS, serverAddress); + } + + public static int getServerPort() { + return prefs().getInt(KEY_SERVER_PORT, 0); + } + + public static int getServerPortWithDefault(int defaultValue) { + return prefs().getInt(KEY_SERVER_PORT, defaultValue); + } + + public static void setServerPort(int port) { + prefs().putInt(KEY_SERVER_PORT, port); + } + + private static String prefixedKey(String prefix, String key) { + return prefix + "/" + key; + } + + public static String getUserName(String serverAddress) { + String userName = prefs().get(prefixedKey(serverAddress, KEY_USER_NAME), ""); + if (!userName.isEmpty()) { + return userName; + } + // For clients older than 1.4.7, userName is stored without a serverAddress prefix. + return prefs().get(KEY_USER_NAME, ""); + } + + public static void setUserName(String serverAddress, String userName) { + prefs().put(prefixedKey(serverAddress, KEY_USER_NAME), userName); + } + + public static String getPassword(String serverAddress) { + return prefs().get(prefixedKey(serverAddress, KEY_PASSWORD), ""); + } + + public static void setPassword(String serverAddress, String password) { + prefs().put(prefixedKey(serverAddress, KEY_PASSWORD), password); + } + + public static String getEmail(String serverAddress) { + return prefs().get(prefixedKey(serverAddress, KEY_EMAIL), ""); + } + + public static void setEmail(String serverAddress, String userName) { + prefs().put(prefixedKey(serverAddress, KEY_EMAIL), userName); + } + + public static boolean getAutoConnect() { + return prefs().getBoolean(KEY_AUTO_CONNECT, false); + } + + public static void setAutoConnect(boolean autoConnect) { + prefs().putBoolean(KEY_AUTO_CONNECT, autoConnect); + } +} diff --git a/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java b/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java index eff39e49483..795a8618cdf 100644 --- a/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java @@ -26,7 +26,7 @@ * or implied, of BetaSteward_at_googlemail.com. */ -/* + /* * ChatPanel.java * * Created on 15-Dec-2009, 11:04:31 PM @@ -61,7 +61,7 @@ public class PlayersChatPanel extends javax.swing.JPanel { private final List players = new ArrayList<>(); private final UserTableModel userTableModel; - private static final int[] defaultColumnsWidth = {20, 100, 100, 80, 80}; + private static final int[] DEFAULT_COLUMNS_WIDTH = {20, 100, 100, 80, 80}; /* @@ -78,7 +78,7 @@ public class PlayersChatPanel extends javax.swing.JPanel { jTablePlayers.setForeground(Color.white); jTablePlayers.setRowSorter(new MageTableRowSorter(userTableModel)); - TableUtil.setColumnWidthAndOrder(jTablePlayers, defaultColumnsWidth, KEY_USERS_COLUMNS_WIDTH, KEY_USERS_COLUMNS_ORDER); + TableUtil.setColumnWidthAndOrder(jTablePlayers, DEFAULT_COLUMNS_WIDTH, KEY_USERS_COLUMNS_WIDTH, KEY_USERS_COLUMNS_ORDER); jTablePlayers.setDefaultRenderer(Icon.class, new CountryCellRenderer()); jScrollPaneTalk.setSystemMessagesPane(colorPaneSystem); @@ -118,7 +118,7 @@ public class PlayersChatPanel extends javax.swing.JPanel { class UserTableModel extends AbstractTableModel { - private final String[] columnNames = new String[]{"Loc", "Players", "Info", "Games", "Connection"}; + private final String[] columnNames = new String[]{"Loc", "Players", "History", "Games", "Connection"}; private UsersView[] players = new UsersView[0]; public void loadData(Collection roomUserInfoList) throws MageRemoteException { @@ -154,7 +154,7 @@ public class PlayersChatPanel extends javax.swing.JPanel { case 1: return players[arg0].getUserName(); case 2: - return players[arg0].getInfoState(); + return players[arg0].getHistory(); case 3: return players[arg0].getInfoGames(); case 4: diff --git a/Mage.Client/src/main/java/mage/client/util/ButtonColumn.java b/Mage.Client/src/main/java/mage/client/util/ButtonColumn.java index 07a874d9f08..baada9087a6 100644 --- a/Mage.Client/src/main/java/mage/client/util/ButtonColumn.java +++ b/Mage.Client/src/main/java/mage/client/util/ButtonColumn.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.client.util; import java.awt.Component; @@ -78,64 +77,64 @@ public class ButtonColumn extends AbstractCellEditor implements TableCellRendere @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - if (hasFocus) - { + if (hasFocus) { renderButton.setForeground(table.getForeground()); renderButton.setBackground(UIManager.getColor("Button.background")); - } - else if (isSelected) - { + } else if (isSelected) { renderButton.setForeground(table.getSelectionForeground()); - renderButton.setBackground(table.getSelectionBackground()); - } - else - { + renderButton.setBackground(table.getSelectionBackground()); + } else { renderButton.setForeground(table.getForeground()); renderButton.setBackground(UIManager.getColor("Button.background")); } - renderButton.setText( (value == null) ? "" : value.toString() ); + renderButton.setText((value == null) ? "" : value.toString()); return renderButton; } @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { text = (value == null) ? "" : value.toString(); - editButton.setText( text ); + editButton.setText(text); return editButton; } @Override public void actionPerformed(ActionEvent e) { - int row = table.convertRowIndexToModel( table.getEditingRow() ); - fireEditingStopped(); - ActionEvent event = new ActionEvent(table, ActionEvent.ACTION_PERFORMED, "" + row); - action.actionPerformed(event); - + if (table.getRowCount() >= table.getEditingRow()) { + int row = table.convertRowIndexToModel(table.getEditingRow()); + fireEditingStopped(); + ActionEvent event = new ActionEvent(table, ActionEvent.ACTION_PERFORMED, "" + row); + action.actionPerformed(event); + } } @Override public void mousePressed(MouseEvent arg0) { - if (table.isEditing() && table.getCellEditor() == this) + if (table.isEditing() && table.getCellEditor() == this) { isButtonColumnEditor = true; + } } @Override public void mouseReleased(MouseEvent arg0) { - if (isButtonColumnEditor && table.isEditing()) + if (isButtonColumnEditor && table.isEditing()) { table.getCellEditor().stopCellEditing(); + } isButtonColumnEditor = false; } @Override - public void mouseClicked(MouseEvent arg0) {} + public void mouseClicked(MouseEvent arg0) { + } @Override - public void mouseEntered(MouseEvent arg0) {} + public void mouseEntered(MouseEvent arg0) { + } @Override - public void mouseExited(MouseEvent arg0) {} - + public void mouseExited(MouseEvent arg0) { + } } 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 c6be8e494b3..b645c0ae293 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 @@ -1,14 +1,9 @@ package org.mage.card.arcane; -import mage.cards.repository.ExpansionRepository; -import mage.client.dialog.PreferencesDialog; -import mage.client.util.ImageHelper; -import mage.client.util.gui.BufferedImageBuilder; -import org.apache.log4j.Logger; -import org.mage.plugins.card.constants.Constants; - -import javax.imageio.ImageIO; -import java.awt.*; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.io.File; import java.util.HashMap; @@ -16,6 +11,13 @@ import java.util.List; import java.util.Map; import java.util.StringTokenizer; import java.util.regex.Pattern; +import javax.imageio.ImageIO; +import mage.cards.repository.ExpansionRepository; +import mage.client.dialog.PreferencesDialog; +import mage.client.util.ImageHelper; +import mage.client.util.gui.BufferedImageBuilder; +import org.apache.log4j.Logger; +import org.mage.plugins.card.constants.Constants; public class ManaSymbols { @@ -30,10 +32,10 @@ public class ManaSymbols { public static void loadImages() { String[] symbols = new String[]{"0", "1", "10", "11", "12", "15", "16", "2", "3", "4", "5", "6", "7", "8", "9", "B", "BG", "BR", "G", "GU", "GW", "R", "RG", "RW", "S", "T", "U", "UB", "UR", "W", "WB", "WU", - "WP", "UP", "BP", "RP", "GP", "X" /*, "Y", "Z", "slash"*/}; + "WP", "UP", "BP", "RP", "GP", "X", "C" /*, "Y", "Z", "slash"*/}; for (String symbol : symbols) { - File file = new File(getSymbolsPath() + Constants.RESOURCE_PATH_MANA_MEDIUM + "/" + symbol + ".jpg"); + File file = new File(getSymbolsPath() + Constants.RESOURCE_PATH_MANA_MEDIUM + "/" + symbol + ".jpg"); Rectangle r = new Rectangle(11, 11); try { Image image = UI.getImageIcon(file.getAbsolutePath()).getImage(); @@ -198,6 +200,7 @@ public class ManaSymbols { } public enum Type { + CARD, TOOLTIP, PAY diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/DownloadJob.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/DownloadJob.java index 42b67cf7a57..32462dfa601 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/DownloadJob.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/DownloadJob.java @@ -1,12 +1,10 @@ /** * DownloadJob.java - * + * * Created on 25.08.2010 */ - package org.mage.plugins.card.dl; - import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -21,25 +19,26 @@ import org.mage.plugins.card.dl.beans.properties.Property; import org.mage.plugins.card.dl.lm.AbstractLaternaBean; import org.mage.plugins.card.utils.CardImageUtils; - /** * The class DownloadJob. - * + * * @version V0.0 25.08.2010 * @author Clemens Koza */ public class DownloadJob extends AbstractLaternaBean { + public static enum State { + NEW, WORKING, FINISHED, ABORTED; } - private final String name; - private final Source source; - private final Destination destination; - private final Property state = properties.property("state", State.NEW); - private final Property message = properties.property("message"); - private final Property error = properties.property("error"); - private final BoundedRangeModel progress = new DefaultBoundedRangeModel(); + private final String name; + private final Source source; + private final Destination destination; + private final Property state = properties.property("state", State.NEW); + private final Property message = properties.property("message"); + private final Property error = properties.property("error"); + private final BoundedRangeModel progress = new DefaultBoundedRangeModel(); public DownloadJob(String name, Source source, Destination destination) { this.name = name; @@ -48,7 +47,9 @@ public class DownloadJob extends AbstractLaternaBean { } /** - * Sets the job's state. If the state is {@link State#ABORTED}, it instead sets the error to "ABORTED" + * Sets the job's state. If the state is {@link State#ABORTED}, it instead + * sets the error to "ABORTED" + * * @param state */ public void setState(State state) { @@ -60,8 +61,9 @@ public class DownloadJob extends AbstractLaternaBean { } /** - * Sets the job's state to {@link State#ABORTED} and the error message to the given message. Logs a warning - * with the given message. + * Sets the job's state to {@link State#ABORTED} and the error message to + * the given message. Logs a warning with the given message. + * * @param message */ public void setError(String message) { @@ -69,8 +71,9 @@ public class DownloadJob extends AbstractLaternaBean { } /** - * Sets the job's state to {@link State#ABORTED} and the error to the given exception. Logs a warning with the - * given exception. + * Sets the job's state to {@link State#ABORTED} and the error to the given + * exception. Logs a warning with the given exception. + * * @param error */ public void setError(Exception error) { @@ -78,14 +81,15 @@ public class DownloadJob extends AbstractLaternaBean { } /** - * Sets the job's state to {@link State#ABORTED} and the error to the given exception. Logs a warning with the - * given message and exception. + * Sets the job's state to {@link State#ABORTED} and the error to the given + * exception. Logs a warning with the given message and exception. + * * @param message * @param error */ public void setError(String message, Exception error) { if (message == null) { - + message = "Download of " + this.getName() + "from " + this.getSource().toString() + " caused error: " + error.toString(); } // log.warn(message, error); @@ -97,6 +101,7 @@ public class DownloadJob extends AbstractLaternaBean { /** * Sets the job's message. + * * @param message */ public void setMessage(String message) { @@ -119,7 +124,6 @@ public class DownloadJob extends AbstractLaternaBean { return message.getValue(); } - public String getName() { return name; } @@ -163,9 +167,9 @@ public class DownloadJob extends AbstractLaternaBean { @Override public String toString() { - return proxy != null ? proxy.type().toString()+" " :"" + url; + return proxy != null ? proxy.type().toString() + " " : "" + url; } - + }; } @@ -189,11 +193,11 @@ public class DownloadJob extends AbstractLaternaBean { public int length() throws IOException { return getConnection().getContentLength(); } - + @Override public String toString() { - return proxy != null ? proxy.type().toString()+" " :"" + url; - } + return proxy != null ? proxy.type().toString() + " " : "" + url; + } }; } @@ -213,6 +217,14 @@ public class DownloadJob extends AbstractLaternaBean { return new FileOutputStream(file); } + @Override + public boolean isValid() throws IOException { + if (file.isFile()) { + return file.length() > 0; + } + return false; + } + @Override public boolean exists() { return file.isFile(); @@ -228,16 +240,20 @@ public class DownloadJob extends AbstractLaternaBean { } public interface Source { + InputStream open() throws IOException; int length() throws IOException; } public interface Destination { + OutputStream open() throws IOException; boolean exists() throws IOException; + boolean isValid() throws IOException; + void delete() throws IOException; } } 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 1ff78368e1f..ca5160a71db 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 @@ -1,9 +1,8 @@ /** * Downloader.java - * + * * Created on 25.08.2010 */ - package org.mage.plugins.card.dl; import java.io.BufferedInputStream; @@ -29,10 +28,9 @@ import org.mage.plugins.card.dl.DownloadJob.Source; import org.mage.plugins.card.dl.DownloadJob.State; import org.mage.plugins.card.dl.lm.AbstractLaternaBean; - /** * The class Downloader. - * + * * @version V0.0 25.08.2010 * @author Clemens Koza */ @@ -40,16 +38,16 @@ public class Downloader extends AbstractLaternaBean implements Disposable { private static final Logger logger = Logger.getLogger(Downloader.class); - private final List jobs = properties.list("jobs"); + private final List jobs = properties.list("jobs"); private final Channel channel = new MemoryChannel<>(); - private final ExecutorService pool = Executors.newCachedThreadPool(); - private final List fibers = new ArrayList<>(); + private final ExecutorService pool = Executors.newCachedThreadPool(); + private final List fibers = new ArrayList<>(); public Downloader() { PoolFiberFactory f = new PoolFiberFactory(pool); //subscribe multiple fibers for parallel execution - for(int i = 0, numThreads = 10; i < numThreads; i++) { + for (int i = 0, numThreads = 10; i < numThreads; i++) { Fiber fiber = f.create(); fiber.start(); fibers.add(fiber); @@ -59,15 +57,15 @@ public class Downloader extends AbstractLaternaBean implements Disposable { @Override public void dispose() { - for(DownloadJob j:getJobs()) { - switch(j.getState()) { + for (DownloadJob j : getJobs()) { + switch (j.getState()) { case NEW: case WORKING: j.setState(State.ABORTED); } } - for(Fiber f:fibers) { + for (Fiber f : fibers) { f.dispose(); } pool.shutdown(); @@ -84,10 +82,10 @@ public class Downloader extends AbstractLaternaBean implements Disposable { } public void add(DownloadJob job) { - if(job.getState() == State.WORKING) { + if (job.getState() == State.WORKING) { throw new IllegalArgumentException("Job already running"); } - if(job.getState() == State.FINISHED) { + if (job.getState() == State.FINISHED) { throw new IllegalArgumentException("Job already finished"); } job.setState(State.NEW); @@ -100,15 +98,17 @@ public class Downloader extends AbstractLaternaBean implements Disposable { } /** - * Performs the download job: Transfers data from {@link Source} to {@link Destination} and updates the - * download job's state to reflect the progress. + * Performs the download job: Transfers data from {@link Source} to + * {@link Destination} and updates the download job's state to reflect the + * progress. */ private class DownloadCallback implements Callback { + @Override public void onMessage(DownloadJob job) { //the job won't be processed by multiple threads - synchronized(job) { - if(job.getState() != State.NEW) { + synchronized (job) { + if (job.getState() != State.NEW) { return; } job.setState(State.WORKING); @@ -118,10 +118,17 @@ public class Downloader extends AbstractLaternaBean implements Disposable { Destination dst = job.getDestination(); BoundedRangeModel progress = job.getProgress(); - if(dst.exists()) { + if (dst.isValid()) { progress.setMaximum(1); progress.setValue(1); } else { + if (dst.exists()) { + try { + dst.delete(); + } catch (IOException ex1) { + logger.warn("While deleting not valid file", ex1); + } + } progress.setMaximum(src.length()); InputStream is = new BufferedInputStream(src.open()); try { @@ -129,45 +136,45 @@ public class Downloader extends AbstractLaternaBean implements Disposable { try { byte[] buf = new byte[8 * 1024]; int total = 0; - for(int len; (len = is.read(buf)) != -1;) { - if(job.getState() == State.ABORTED) { + for (int len; (len = is.read(buf)) != -1;) { + if (job.getState() == State.ABORTED) { throw new IOException("Job was aborted"); } progress.setValue(total += len); os.write(buf, 0, len); } - } catch(IOException ex) { + } catch (IOException ex) { try { dst.delete(); - } catch(IOException ex1) { + } catch (IOException ex1) { logger.warn("While deleting", ex1); } throw ex; } finally { try { os.close(); - } catch(IOException ex) { + } catch (IOException ex) { logger.warn("While closing", ex); } } } finally { try { is.close(); - } catch(IOException ex) { + } catch (IOException ex) { logger.warn("While closing", ex); } } } job.setState(State.FINISHED); - } catch(ConnectException ex) { + } catch (ConnectException ex) { String message; if (ex.getMessage() != null) { message = ex.getMessage(); } else { message = "Unknown error"; } - logger.warn("Error resource download " + job.getName() +" from "+ job.getSource().toString() + ": " + message); - } catch(IOException ex) { + logger.warn("Error resource download " + job.getName() + " from " + job.getSource().toString() + ": " + message); + } catch (IOException ex) { job.setError(ex); } } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java index 78995593cd7..5181afb9e91 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java @@ -89,6 +89,8 @@ public class MythicspoilerComSource implements CardImageSource { cardNameAliases.put("BFZ-unisonstrike", "tandemtactics"); cardNameAliases.put("BFZ-eldrazidevastator", "eldrazidevastator"); cardNameAliases.put("BFZ-kozliekschanneler", "kozilekschanneler"); + cardNameAliases.put("OGW-wastes", "wastes1"); + cardNameAliases.put("OGW-wastes2", "wastes2"); cardNameAliasesStart = new HashMap<>(); HashSet names = new HashSet<>(); @@ -156,14 +158,16 @@ public class MythicspoilerComSource implements CardImageSource { if (cardName != null && !cardName.isEmpty()) { if (cardNameAliases.containsKey(cardSet + "-" + cardName)) { cardName = cardNameAliases.get(cardSet + "-" + cardName); - } - if (cardName.endsWith("1") || cardName.endsWith("2") || cardName.endsWith("3") || cardName.endsWith("4") || cardName.endsWith("5")) { - if (!cardName.startsWith("forest") - && !cardName.startsWith("swamp") - && !cardName.startsWith("mountain") - && !cardName.startsWith("island") - && !cardName.startsWith("plains")) { - cardName = cardName.substring(0, cardName.length() - 1); + } else { + if (cardName.endsWith("1") || cardName.endsWith("2") || cardName.endsWith("3") || cardName.endsWith("4") || cardName.endsWith("5")) { + if (!cardName.startsWith("forest") + && !cardName.startsWith("swamp") + && !cardName.startsWith("mountain") + && !cardName.startsWith("island") + && !cardName.startsWith("plains")) { + + cardName = cardName.substring(0, cardName.length() - 1); + } } } setLinks.put(cardName, baseUrl + cardLink); @@ -203,7 +207,8 @@ public class MythicspoilerComSource implements CardImageSource { } @Override - public String generateTokenUrl(CardDownloadData card) { + public String generateTokenUrl(CardDownloadData card + ) { return null; } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java index b6d13d1f394..547cc1573fe 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java @@ -616,7 +616,9 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab new TFile(temporaryFile).cp_rp(outputFile); } } else { - logger.warn("Image download for " + card.getName() + "(" + card.getSet() + ") failed - responseCode: " + responseCode + " url: " + url.toString()); + logger.warn("Image download for " + card.getName() + + (!card.getDownloadName().equals(card.getName()) ? " downloadname: " + card.getDownloadName() : "") + + "(" + card.getSet() + ") failed - responseCode: " + responseCode + " url: " + url.toString()); if (logger.isDebugEnabled()) { // Shows the returned html from the request to the web server logger.debug("Return ed HTML ERROR:\n" + convertStreamToString(((HttpURLConnection) httpConn).getErrorStream())); } diff --git a/Mage.Client/src/main/resources/card-pictures-tok.txt b/Mage.Client/src/main/resources/card-pictures-tok.txt index 43518016531..36c4bd4801d 100644 --- a/Mage.Client/src/main/resources/card-pictures-tok.txt +++ b/Mage.Client/src/main/resources/card-pictures-tok.txt @@ -1,6 +1,14 @@ -#Generate|TOK:OGW|Elemental|| -#Generate|TOK:OGW|Plant|| -#Generate|TOK:OGW|Zombie|| +|Generate}TOK:OGW|Angel|| +|Generate|TOK:OGW|Elemental|1| +|Generate|TOK:OGW|Elemental|2| +|Generate}TOK:OGW|Eldrazi Scion|1| +|Generate}TOK:OGW|Eldrazi Scion|2| +|Generate}TOK:OGW|Eldrazi Scion|3| +|Generate}TOK:OGW|Eldrazi Scion|4| +|Generate}TOK:OGW|Eldrazi Scion|5| +|Generate}TOK:OGW|Eldrazi Scion|6| +|Generate|TOK:OGW|Plant|| +|Generate|TOK:OGW|Zombie|| #|Generate|TOK:DDQ|Angel|| diff --git a/Mage.Common/pom.xml b/Mage.Common/pom.xml index 00faf2b003d..bacf94c9a8c 100644 --- a/Mage.Common/pom.xml +++ b/Mage.Common/pom.xml @@ -7,7 +7,7 @@ org.mage mage-root - 1.4.6 + 1.4.8 mage-common diff --git a/Mage.Common/src/mage/interfaces/MageServer.java b/Mage.Common/src/mage/interfaces/MageServer.java index 4d30942a1e5..83ffce61e49 100644 --- a/Mage.Common/src/mage/interfaces/MageServer.java +++ b/Mage.Common/src/mage/interfaces/MageServer.java @@ -55,10 +55,21 @@ import mage.view.UserView; */ public interface MageServer { + // registers a user to the user DB. + boolean registerUser(String sessionId, String userName, String password, String email) throws MageException; + + boolean emailAuthToken(String sessionId, String email) throws MageException; + + boolean resetPassword(String sessionId, String email, String authToken, String password) throws MageException; + // connection methods + // DEPRECATED - Use connectUser instead. This is only kept for older clients. + // This can be deleted once users transitioned to newer clients (1.4.6v1 and later). boolean registerClient(String userName, String sessionId, MageVersion version) throws MageException; - boolean registerAdmin(String password, String sessionId, MageVersion version) throws MageException; + boolean connectUser(String userName, String password, String sessionId, MageVersion version) throws MageException; + + boolean connectAdmin(String password, String sessionId, MageVersion version) throws MageException; // Not used // void deregisterClient(String sessionId) throws MageException; diff --git a/Mage.Common/src/mage/remote/Connection.java b/Mage.Common/src/mage/remote/Connection.java index 0c4e86c827f..2a989da8dc6 100644 --- a/Mage.Common/src/mage/remote/Connection.java +++ b/Mage.Common/src/mage/remote/Connection.java @@ -45,6 +45,9 @@ public class Connection { private int port; private String username; private String password; + private String email; + private String authToken; + private String adminPassword; private ProxyType proxyType; private String proxyHost; private int proxyPort; @@ -172,6 +175,30 @@ public class Connection { this.password = password; } + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getAuthToken() { + return authToken; + } + + public void setAuthToken(String authToken) { + this.authToken = authToken; + } + + public String getAdminPassword() { + return adminPassword; + } + + public void setAdminPassword(String adminPassword) { + this.adminPassword = adminPassword; + } + public String getProxyHost() { return proxyHost; } diff --git a/Mage.Common/src/mage/remote/SessionImpl.java b/Mage.Common/src/mage/remote/SessionImpl.java index 3b4036d4c26..4960fdfd744 100644 --- a/Mage.Common/src/mage/remote/SessionImpl.java +++ b/Mage.Common/src/mage/remote/SessionImpl.java @@ -122,195 +122,36 @@ public class SessionImpl implements Session { return sessionId; } - @Override - public synchronized boolean connect(Connection connection) { - if (isConnected()) { - disconnect(true); - } - this.connection = connection; - this.canceled = false; - return connect(); + // RemotingTask encapsulates a task which is involved with some JBoss Remoting. This is + // intended to be used with handleRemotingTaskExceptions for sharing the common exception + // handling. + public interface RemotingTask { + public boolean run() throws Throwable; } - @Override - public boolean stopConnecting() { - canceled = true; - return true; - } - - @Override - public boolean connect() { - sessionState = SessionState.CONNECTING; + // handleRemotingTaskExceptions runs the given task and handles exceptions appropriately. This + // way we can share the common exception handling. + private boolean handleRemotingTaskExceptions(RemotingTask remoting) { try { - System.setProperty("http.nonProxyHosts", "code.google.com"); - System.setProperty("socksNonProxyHosts", "code.google.com"); - - // clear previous values - System.clearProperty("socksProxyHost"); - System.clearProperty("socksProxyPort"); - System.clearProperty("http.proxyHost"); - System.clearProperty("http.proxyPort"); - - switch (connection.getProxyType()) { - case SOCKS: - System.setProperty("socksProxyHost", connection.getProxyHost()); - System.setProperty("socksProxyPort", Integer.toString(connection.getProxyPort())); - break; - case HTTP: - System.setProperty("http.proxyHost", connection.getProxyHost()); - System.setProperty("http.proxyPort", Integer.toString(connection.getProxyPort())); - Authenticator.setDefault(new MageAuthenticator(connection.getProxyUsername(), connection.getProxyPassword())); - break; - } - InvokerLocator clientLocator = new InvokerLocator(connection.getURI()); - - Map metadata = new HashMap<>(); - /* - 5.8.3.1.1. Write timeouts - The socket timeout facility offered by the JDK applies only to read operations on the socket. As of release 2.5.2, - the socket and bisocket (and also sslsocket and sslbisocket) transports offer a write timeout facility. When a client - or server is configured, in any of the usual ways, with the parameter org.jboss.remoting.transport.socket.SocketWrapper.WRITE_TIMEOUT - (actual value "writeTimeout") set to a positive value (in milliseconds), all write operations will time out if they do - not complete within the configured period. When a write operation times out, the socket upon which the write was invoked - will be closed, which is likely to result in a java.net.SocketException. - Note. A SocketException is considered to be a "retriable" exception, so, if the parameter "numberOfCallRetries" is set - to a value greater than 1, an invocation interrupted by a write timeout can be retried. - Note. The write timeout facility applies to writing of both invocations and responses. It applies to push callbacks as well. - */ - metadata.put(SocketWrapper.WRITE_TIMEOUT, "2000"); - metadata.put("generalizeSocketException", "true"); - server = (MageServer) TransporterClient.createTransporterClient(clientLocator.getLocatorURI(), MageServer.class, metadata); - - // http://docs.jboss.org/jbossremoting/docs/guide/2.5/html_single/#d0e1057 - Map clientMetadata = new HashMap<>(); - - clientMetadata.put(SocketWrapper.WRITE_TIMEOUT, "2000"); - /* generalizeSocketException - * If set to false, a failed invocation will be retried in the case of - * SocketExceptions. If set to true, a failed invocation will be retried in the case of - * SocketExceptions and also any IOException - * whose message matches the regular expression - * ^.*(?:connection.*reset|connection.*closed|broken.*pipe).*$. - * See also the "numberOfCallRetries" parameter, above. The default value is false.*/ - clientMetadata.put("generalizeSocketException", "true"); - - /* A remoting server also has the capability to detect when a client is no longer available. - * This is done by estabilishing a lease with the remoting clients that connect to a server. - * On the client side, an org.jboss.remoting.LeasePinger periodically sends PING messages to - * the server, and on the server side an org.jboss.remoting.Lease informs registered listeners - * if the PING doesn't arrive withing the specified timeout period. */ - clientMetadata.put(Client.ENABLE_LEASE, "true"); - /* - When the socket client invoker makes its first invocation, it will check to see if there is an available - socket connection in its pool. Since is the first invocation, there will not be and will create a new socket - connection and use it for making the invocation. Then when finished making invocation, will return the still - active socket connection to the pool. As more client invocations are made, is possible for the number of - socket connections to reach the maximum allowed (which is controlled by 'clientMaxPoolSize' property). At this - point, when the next client invocation is made, it will wait up to some configured number of milliseconds, at - which point it will throw an org.jboss.remoting.CannotConnectException. The number of milliseconds is given by - the parameter MicroSocketClientInvoker.CONNECTION_WAIT (actual value "connectionWait"), with a default of - 30000 milliseconds. Note that if more than one call retry is configured (see next paragraph), - the CannotConnectException will be swallowed. - Once the socket client invoker get an available socket connection from the pool, are not out of the woods yet. - For example, a network problem could cause a java.net.SocketException. There is also a possibility that the socket - connection, while still appearing to be valid, has "gone stale" while sitting in the pool. For example, a ServerThread - on the other side of the connection could time out and close its socket. If the attempt to complete an invocation - fails, then MicroSocketClientInvoker will make a number of attempts, according to the parameter "numberOfCallRetries", - with a default value of 3. Once the configured number of retries has been exhausted, - an org.jboss.remoting.InvocationFailureException will be thrown. - */ - clientMetadata.put("numberOfCallRetries", "1"); - - /** - * I'll explain the meaning of "secondaryBindPort" and - * "secondaryConnectPort", and maybe that will help. The Remoting - * bisocket transport creates two ServerSockets on the server. The - * "primary" ServerSocket is used to create connections used for - * ordinary invocations, e.g., a request to create a JMS consumer, - * and the "secondary" ServerSocket is used to create "control" - * connections for internal Remoting messages. The port for the - * primary ServerSocket is configured by the "serverBindPort" - * parameter, and the port for the secondary ServerSocket is, by - * default, chosen randomly. The "secondaryBindPort" parameter can - * be used to assign a specific port to the secondary ServerSocket. - * Now, if there is a translating firewall between the client and - * server, the client should be given the value of the port that is - * translated to the actual binding port of the secondary - * ServerSocket. For example, your configuration will tell the - * secondary ServerSocket to bind to port 14000, and it will tell - * the client to connect to port 14001. It assumes that there is a - * firewall which will translate 14001 to 14000. Apparently, that's - * not happening. - */ - // secondaryBindPort - the port to which the secondary server socket is to be bound. By default, an arbitrary port is selected. - // secondaryConnectPort - the port clients are to use to connect to the secondary server socket. - // By default, the value of secondaryBindPort is used. secondaryConnectPort is useful if the server is behind a translating firewall. - // Indicated the max number of threads used within oneway thread pool. - clientMetadata.put(Client.MAX_NUM_ONEWAY_THREADS, "10"); - clientMetadata.put(Remoting.USE_CLIENT_CONNECTION_IDENTITY, "true"); - callbackClient = new Client(clientLocator, "callback", clientMetadata); - - Map listenerMetadata = new HashMap<>(); - if (debugMode) { - // prevent client from disconnecting while debugging - listenerMetadata.put(ConnectionValidator.VALIDATOR_PING_PERIOD, "1000000"); - listenerMetadata.put(ConnectionValidator.VALIDATOR_PING_TIMEOUT, "900000"); - } else { - listenerMetadata.put(ConnectionValidator.VALIDATOR_PING_PERIOD, "15000"); - listenerMetadata.put(ConnectionValidator.VALIDATOR_PING_TIMEOUT, "13000"); - } - callbackClient.connect(new ClientConnectionListener(), listenerMetadata); - - Map callbackMetadata = new HashMap<>(); - callbackMetadata.put(Bisocket.IS_CALLBACK_SERVER, "true"); - if (callbackHandler == null) { - callbackHandler = new CallbackHandler(); - } - callbackClient.addListener(callbackHandler, callbackMetadata); - - Set callbackConnectors = callbackClient.getCallbackConnectors(callbackHandler); - if (callbackConnectors.size() != 1) { - logger.warn("There should be one callback Connector (number existing = " + callbackConnectors.size() + ")"); - } - - logger.info("Trying to connect as " + (this.getUserName() == null ? "" : this.getUserName()) + " to XMAGE server at " + connection.getHost() + ":" + connection.getPort()); - callbackClient.invoke(null); - - this.sessionId = callbackClient.getSessionId(); - boolean registerResult; - if (connection.getPassword() == null) { - // for backward compatibility. don't remove twice call - first one does nothing but for version checking - registerResult = server.registerClient(connection.getUsername(), sessionId, client.getVersion()); - if (registerResult) { - server.setUserData(connection.getUsername(), sessionId, connection.getUserData()); - } - } else { - registerResult = server.registerAdmin(connection.getPassword(), sessionId, client.getVersion()); - } - if (registerResult) { - sessionState = SessionState.CONNECTED; - serverState = server.getServerState(); - if (!connection.getUsername().equals("Admin")) { - updateDatabase(connection.isForceDBComparison(), serverState); - } - logger.info("Connected as " + (this.getUserName() == null ? "" : this.getUserName()) + " to MAGE server at " + connection.getHost() + ":" + connection.getPort()); - client.connected(this.getUserName() == null ? "" : this.getUserName() + "@" + connection.getHost() + ":" + connection.getPort() + " "); - return true; - } - disconnect(false); - // client.showMessage("Unable to connect to server."); + return remoting.run(); } catch (MalformedURLException ex) { logger.fatal("", ex); client.showMessage("Unable to connect to server. " + ex.getMessage()); } catch (UndeclaredThrowableException ex) { String addMessage = ""; - if (ex.getCause() instanceof InvocationFailureException) { - InvocationFailureException exep = (InvocationFailureException) ex.getCause(); + Throwable cause = ex.getCause(); + if (cause instanceof InvocationFailureException) { + InvocationFailureException exep = (InvocationFailureException) cause; if (exep.getCause() instanceof IOException) { if (exep.getCause().getMessage().startsWith("Field hash null is not available on current")) { addMessage = "Probabaly the server version is not compatible to the client. "; } } + } else if (cause instanceof NoSuchMethodException) { + // NoSuchMethodException is thrown on an invocation of an unknow JBoss remoting + // method, so it's likely to be because of a version incompatibility. + addMessage = "The following method is not available in the server, probably the " + + "server version is not compatible to the client: " + cause.getMessage(); } if (addMessage.isEmpty()) { logger.fatal("", ex); @@ -347,6 +188,247 @@ public class SessionImpl implements Session { return false; } + @Override + public synchronized boolean register(final Connection connection) { + return establishJBossRemotingConnection(connection) && handleRemotingTaskExceptions(new RemotingTask() { + @Override + public boolean run() throws Throwable { + logger.info("Trying to register as " + getUserName() + " to XMAGE server at " + connection.getHost() + ":" + connection.getPort()); + boolean registerResult = server.registerUser(sessionId, connection.getUsername(), + connection.getPassword(), connection.getEmail()); + if (registerResult) { + logger.info("Registered as " + getUserName() + " to MAGE server at " + connection.getHost() + ":" + connection.getPort()); + } + return registerResult; + } + }); + } + + @Override + public synchronized boolean emailAuthToken(final Connection connection) { + return establishJBossRemotingConnection(connection) && handleRemotingTaskExceptions(new RemotingTask() { + @Override + public boolean run() throws Throwable { + logger.info("Trying to ask for an auth token to " + getEmail() + " to XMAGE server at " + connection.getHost() + ":" + connection.getPort()); + boolean result = server.emailAuthToken(sessionId, connection.getEmail()); + if (result) { + logger.info("An auth token is emailed to " + getEmail() + " from MAGE server at " + connection.getHost() + ":" + connection.getPort()); + } + return result; + } + }); + } + + @Override + public synchronized boolean resetPassword(final Connection connection) { + return establishJBossRemotingConnection(connection) && handleRemotingTaskExceptions(new RemotingTask() { + @Override + public boolean run() throws Throwable { + logger.info("Trying reset the password in XMAGE server at " + connection.getHost() + ":" + connection.getPort()); + boolean result = server.resetPassword(sessionId, connection.getEmail(), connection.getAuthToken(), connection.getPassword()); + if (result) { + logger.info("Password is successfully reset in MAGE server at " + connection.getHost() + ":" + connection.getPort()); + } + return result; + } + }); + } + + @Override + public synchronized boolean connect(final Connection connection) { + return establishJBossRemotingConnection(connection) && handleRemotingTaskExceptions(new RemotingTask() { + @Override + public boolean run() throws Throwable { + logger.info("Trying to log-in as " + getUserName() + " to XMAGE server at " + connection.getHost() + ":" + connection.getPort()); + boolean registerResult; + if (connection.getAdminPassword() == null) { + // for backward compatibility. don't remove twice call - first one does nothing but for version checking + registerResult = server.connectUser(connection.getUsername(), connection.getPassword(), sessionId, client.getVersion()); + if (registerResult) { + server.setUserData(connection.getUsername(), sessionId, connection.getUserData()); + } + } else { + registerResult = server.connectAdmin(connection.getAdminPassword(), sessionId, client.getVersion()); + } + if (registerResult) { + serverState = server.getServerState(); + if (!connection.getUsername().equals("Admin")) { + updateDatabase(connection.isForceDBComparison(), serverState); + } + logger.info("Logged-in as " + getUserName() + " to MAGE server at " + connection.getHost() + ":" + connection.getPort()); + client.connected(getUserName() + "@" + connection.getHost() + ":" + connection.getPort() + " "); + return true; + } + disconnect(false); + return false; + } + }); + } + + @Override + public boolean stopConnecting() { + canceled = true; + return true; + } + + private boolean establishJBossRemotingConnection(final Connection connection) { + if (isConnected()) { + disconnect(true); + } + this.connection = connection; + this.canceled = false; + sessionState = SessionState.CONNECTING; + boolean result = handleRemotingTaskExceptions(new RemotingTask() { + @Override + public boolean run() throws Throwable { + logger.info("Trying to connect to XMAGE server at " + connection.getHost() + ":" + connection.getPort()); + + System.setProperty("http.nonProxyHosts", "code.google.com"); + System.setProperty("socksNonProxyHosts", "code.google.com"); + + // clear previous values + System.clearProperty("socksProxyHost"); + System.clearProperty("socksProxyPort"); + System.clearProperty("http.proxyHost"); + System.clearProperty("http.proxyPort"); + + switch (connection.getProxyType()) { + case SOCKS: + System.setProperty("socksProxyHost", connection.getProxyHost()); + System.setProperty("socksProxyPort", Integer.toString(connection.getProxyPort())); + break; + case HTTP: + System.setProperty("http.proxyHost", connection.getProxyHost()); + System.setProperty("http.proxyPort", Integer.toString(connection.getProxyPort())); + Authenticator.setDefault(new MageAuthenticator(connection.getProxyUsername(), connection.getProxyPassword())); + break; + } + InvokerLocator clientLocator = new InvokerLocator(connection.getURI()); + + Map metadata = new HashMap<>(); + /* + 5.8.3.1.1. Write timeouts + The socket timeout facility offered by the JDK applies only to read operations on the socket. As of release 2.5.2, + the socket and bisocket (and also sslsocket and sslbisocket) transports offer a write timeout facility. When a client + or server is configured, in any of the usual ways, with the parameter org.jboss.remoting.transport.socket.SocketWrapper.WRITE_TIMEOUT + (actual value "writeTimeout") set to a positive value (in milliseconds), all write operations will time out if they do + not complete within the configured period. When a write operation times out, the socket upon which the write was invoked + will be closed, which is likely to result in a java.net.SocketException. + Note. A SocketException is considered to be a "retriable" exception, so, if the parameter "numberOfCallRetries" is set + to a value greater than 1, an invocation interrupted by a write timeout can be retried. + Note. The write timeout facility applies to writing of both invocations and responses. It applies to push callbacks as well. + */ + metadata.put(SocketWrapper.WRITE_TIMEOUT, "2000"); + metadata.put("generalizeSocketException", "true"); + server = (MageServer) TransporterClient.createTransporterClient(clientLocator.getLocatorURI(), MageServer.class, metadata); + + // http://docs.jboss.org/jbossremoting/docs/guide/2.5/html_single/#d0e1057 + Map clientMetadata = new HashMap<>(); + + clientMetadata.put(SocketWrapper.WRITE_TIMEOUT, "2000"); + /* generalizeSocketException + * If set to false, a failed invocation will be retried in the case of + * SocketExceptions. If set to true, a failed invocation will be retried in the case of + * SocketExceptions and also any IOException + * whose message matches the regular expression + * ^.*(?:connection.*reset|connection.*closed|broken.*pipe).*$. + * See also the "numberOfCallRetries" parameter, above. The default value is false.*/ + clientMetadata.put("generalizeSocketException", "true"); + + /* A remoting server also has the capability to detect when a client is no longer available. + * This is done by estabilishing a lease with the remoting clients that connect to a server. + * On the client side, an org.jboss.remoting.LeasePinger periodically sends PING messages to + * the server, and on the server side an org.jboss.remoting.Lease informs registered listeners + * if the PING doesn't arrive withing the specified timeout period. */ + clientMetadata.put(Client.ENABLE_LEASE, "true"); + /* + When the socket client invoker makes its first invocation, it will check to see if there is an available + socket connection in its pool. Since is the first invocation, there will not be and will create a new socket + connection and use it for making the invocation. Then when finished making invocation, will return the still + active socket connection to the pool. As more client invocations are made, is possible for the number of + socket connections to reach the maximum allowed (which is controlled by 'clientMaxPoolSize' property). At this + point, when the next client invocation is made, it will wait up to some configured number of milliseconds, at + which point it will throw an org.jboss.remoting.CannotConnectException. The number of milliseconds is given by + the parameter MicroSocketClientInvoker.CONNECTION_WAIT (actual value "connectionWait"), with a default of + 30000 milliseconds. Note that if more than one call retry is configured (see next paragraph), + the CannotConnectException will be swallowed. + Once the socket client invoker get an available socket connection from the pool, are not out of the woods yet. + For example, a network problem could cause a java.net.SocketException. There is also a possibility that the socket + connection, while still appearing to be valid, has "gone stale" while sitting in the pool. For example, a ServerThread + on the other side of the connection could time out and close its socket. If the attempt to complete an invocation + fails, then MicroSocketClientInvoker will make a number of attempts, according to the parameter "numberOfCallRetries", + with a default value of 3. Once the configured number of retries has been exhausted, + an org.jboss.remoting.InvocationFailureException will be thrown. + */ + clientMetadata.put("numberOfCallRetries", "1"); + + /** + * I'll explain the meaning of "secondaryBindPort" and + * "secondaryConnectPort", and maybe that will help. The Remoting + * bisocket transport creates two ServerSockets on the server. The + * "primary" ServerSocket is used to create connections used for + * ordinary invocations, e.g., a request to create a JMS consumer, + * and the "secondary" ServerSocket is used to create "control" + * connections for internal Remoting messages. The port for the + * primary ServerSocket is configured by the "serverBindPort" + * parameter, and the port for the secondary ServerSocket is, by + * default, chosen randomly. The "secondaryBindPort" parameter can + * be used to assign a specific port to the secondary ServerSocket. + * Now, if there is a translating firewall between the client and + * server, the client should be given the value of the port that is + * translated to the actual binding port of the secondary + * ServerSocket. For example, your configuration will tell the + * secondary ServerSocket to bind to port 14000, and it will tell + * the client to connect to port 14001. It assumes that there is a + * firewall which will translate 14001 to 14000. Apparently, that's + * not happening. + */ + // secondaryBindPort - the port to which the secondary server socket is to be bound. By default, an arbitrary port is selected. + // secondaryConnectPort - the port clients are to use to connect to the secondary server socket. + // By default, the value of secondaryBindPort is used. secondaryConnectPort is useful if the server is behind a translating firewall. + // Indicated the max number of threads used within oneway thread pool. + clientMetadata.put(Client.MAX_NUM_ONEWAY_THREADS, "10"); + clientMetadata.put(Remoting.USE_CLIENT_CONNECTION_IDENTITY, "true"); + callbackClient = new Client(clientLocator, "callback", clientMetadata); + + Map listenerMetadata = new HashMap<>(); + if (debugMode) { + // prevent client from disconnecting while debugging + listenerMetadata.put(ConnectionValidator.VALIDATOR_PING_PERIOD, "1000000"); + listenerMetadata.put(ConnectionValidator.VALIDATOR_PING_TIMEOUT, "900000"); + } else { + listenerMetadata.put(ConnectionValidator.VALIDATOR_PING_PERIOD, "15000"); + listenerMetadata.put(ConnectionValidator.VALIDATOR_PING_TIMEOUT, "13000"); + } + callbackClient.connect(new ClientConnectionListener(), listenerMetadata); + + Map callbackMetadata = new HashMap<>(); + callbackMetadata.put(Bisocket.IS_CALLBACK_SERVER, "true"); + if (callbackHandler == null) { + callbackHandler = new CallbackHandler(); + } + callbackClient.addListener(callbackHandler, callbackMetadata); + + Set callbackConnectors = callbackClient.getCallbackConnectors(callbackHandler); + if (callbackConnectors.size() != 1) { + logger.warn("There should be one callback Connector (number existing = " + callbackConnectors.size() + ")"); + } + + callbackClient.invoke(null); + + sessionId = callbackClient.getSessionId(); + sessionState = SessionState.CONNECTED; + logger.info("Connected to MAGE server at " + connection.getHost() + ":" + connection.getPort()); + return true; + } + }); + if (result) { + return true; + } + disconnect(false); + return false; + } + private void updateDatabase(boolean forceDBComparison, ServerState serverState) { long cardDBVersion = CardRepository.instance.getContentVersionFromDB(); if (forceDBComparison || serverState.getCardsContentVersion() > cardDBVersion) { @@ -1389,9 +1471,20 @@ public class SessionImpl implements Session { @Override public String getUserName() { - return connection.getUsername(); + String username = connection.getUsername(); + return username == null ? "" : username; } + private String getEmail() { + String email = connection.getEmail(); + return email == null ? "" : email; + } + + private String getAuthToken() { + String authToken = connection.getAuthToken(); + return authToken == null ? "" : authToken; + } + @Override public boolean updatePreferencesForServer(UserData userData) { try { diff --git a/Mage.Common/src/mage/remote/interfaces/Connect.java b/Mage.Common/src/mage/remote/interfaces/Connect.java index 948fc228d11..3eeff3eebec 100644 --- a/Mage.Common/src/mage/remote/interfaces/Connect.java +++ b/Mage.Common/src/mage/remote/interfaces/Connect.java @@ -34,12 +34,16 @@ import mage.remote.Connection; */ public interface Connect { + boolean register(Connection connection); + + boolean emailAuthToken(Connection connection); + + boolean resetPassword(Connection connection); + boolean connect(Connection connection); boolean stopConnecting(); - boolean connect(); - void disconnect(boolean showMessage); void reconnect(Throwable throwable); diff --git a/Mage.Common/src/mage/utils/MageVersion.java b/Mage.Common/src/mage/utils/MageVersion.java index 59a974dcb8f..e5acc0701b2 100644 --- a/Mage.Common/src/mage/utils/MageVersion.java +++ b/Mage.Common/src/mage/utils/MageVersion.java @@ -40,7 +40,7 @@ public class MageVersion implements Serializable, Comparable { */ public final static int MAGE_VERSION_MAJOR = 1; public final static int MAGE_VERSION_MINOR = 4; - public final static int MAGE_VERSION_PATCH = 6; + public final static int MAGE_VERSION_PATCH = 8; public final static String MAGE_VERSION_MINOR_PATCH = "v0"; public final static String MAGE_VERSION_INFO = ""; diff --git a/Mage.Common/src/mage/view/ManaPoolView.java b/Mage.Common/src/mage/view/ManaPoolView.java index b4871f66a64..746b87d8b94 100644 --- a/Mage.Common/src/mage/view/ManaPoolView.java +++ b/Mage.Common/src/mage/view/ManaPoolView.java @@ -1,43 +1,42 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.view; +import java.io.Serializable; import mage.ConditionalMana; import mage.players.ManaPool; -import java.io.Serializable; - /** * * @author BetaSteward_at_googlemail.com */ public class ManaPoolView implements Serializable { + private static final long serialVersionUID = 1L; private int red; diff --git a/Mage.Common/src/mage/view/SeatView.java b/Mage.Common/src/mage/view/SeatView.java index d812dadebd6..49d53db0917 100644 --- a/Mage.Common/src/mage/view/SeatView.java +++ b/Mage.Common/src/mage/view/SeatView.java @@ -44,6 +44,7 @@ public class SeatView implements Serializable { private UUID playerId; private final String playerName; private final String playerType; + private final String history; public SeatView(Seat seat) { if (seat.getPlayer() != null) { @@ -51,13 +52,16 @@ public class SeatView implements Serializable { this.playerName = seat.getPlayer().getName(); if (seat.getPlayer().getUserData() == null) { this.flagName = UserData.getDefaultFlagName(); + this.history = ""; } else { this.flagName = seat.getPlayer().getUserData().getFlagName(); + this.history = seat.getPlayer().getUserData().getHistory(); } } else { // Empty seat this.playerName = ""; this.flagName = ""; + this.history = ""; } this.playerType = seat.getPlayerType(); } @@ -78,4 +82,8 @@ public class SeatView implements Serializable { return flagName; } + public String getHistory() { + return history; + } + } diff --git a/Mage.Common/src/mage/view/UsersView.java b/Mage.Common/src/mage/view/UsersView.java index c5e8522bec4..40a39fc41e8 100644 --- a/Mage.Common/src/mage/view/UsersView.java +++ b/Mage.Common/src/mage/view/UsersView.java @@ -24,7 +24,7 @@ * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. -*/ + */ package mage.view; import java.io.Serializable; @@ -39,14 +39,14 @@ public class UsersView implements Serializable { private final String flagName; private final String userName; - private final String infoState; + private final String history; private final String infoGames; private final String infoPing; - public UsersView(String flagName, String userName, String infoState, String infoGames, String infoPing) { + public UsersView(String flagName, String userName, String history, String infoGames, String infoPing) { this.flagName = flagName; + this.history = history; this.userName = userName; - this.infoState = infoState; this.infoGames = infoGames; this.infoPing = infoPing; } @@ -59,8 +59,8 @@ public class UsersView implements Serializable { return userName; } - public String getInfoState() { - return infoState; + public String getHistory() { + return history; } public String getInfoGames() { diff --git a/Mage.Plugins/Mage.Counter.Plugin/pom.xml b/Mage.Plugins/Mage.Counter.Plugin/pom.xml index e928b2f3d87..3f49e74f486 100644 --- a/Mage.Plugins/Mage.Counter.Plugin/pom.xml +++ b/Mage.Plugins/Mage.Counter.Plugin/pom.xml @@ -7,7 +7,7 @@ org.mage mage-plugins - 1.4.6 + 1.4.8 mage-counter-plugin diff --git a/Mage.Plugins/pom.xml b/Mage.Plugins/pom.xml index d73170705bb..7e08821960b 100644 --- a/Mage.Plugins/pom.xml +++ b/Mage.Plugins/pom.xml @@ -7,7 +7,7 @@ org.mage mage-root - 1.4.6 + 1.4.8 mage-plugins diff --git a/Mage.Server.Console/pom.xml b/Mage.Server.Console/pom.xml index 7ca2419f772..38af4642cfd 100644 --- a/Mage.Server.Console/pom.xml +++ b/Mage.Server.Console/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.6 + 1.4.8 org.mage diff --git a/Mage.Server.Console/src/main/java/mage/server/console/ConnectDialog.java b/Mage.Server.Console/src/main/java/mage/server/console/ConnectDialog.java index 127efc1b713..6a4b6e8620e 100644 --- a/Mage.Server.Console/src/main/java/mage/server/console/ConnectDialog.java +++ b/Mage.Server.Console/src/main/java/mage/server/console/ConnectDialog.java @@ -413,7 +413,7 @@ public class ConnectDialog extends JDialog { connection = new Connection(); connection.setHost(this.txtServer.getText()); connection.setPort(Integer.valueOf(this.txtPort.getText())); - connection.setPassword(new String(txtPassword.getPassword())); + connection.setAdminPassword(new String(txtPassword.getPassword())); connection.setUsername("Admin"); connection.setProxyType((ProxyType) this.cbProxyType.getSelectedItem()); if (!this.cbProxyType.getSelectedItem().equals(ProxyType.NONE)) { diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml b/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml index 7c0c0a38787..a115b6be9f8 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.6 + 1.4.8 mage-deck-constructed diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java index ead9a0dfcc2..b9199751d6e 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java @@ -46,8 +46,8 @@ import mage.util.CardUtil; */ public class Commander extends DeckValidator { - protected List banned = new ArrayList<>(); - protected List bannedCommander = new ArrayList<>(); + protected List banned = new ArrayList<>(); + protected List bannedCommander = new ArrayList<>(); public Commander() { this("Commander"); @@ -74,6 +74,7 @@ public class Commander extends DeckValidator { banned.add("Painter's Servant"); banned.add("Panoptic Mirror"); banned.add("Primeval Titan"); + banned.add("Prophet of Kruphix"); banned.add("Protean Hulk"); banned.add("Recurring Nightmare"); banned.add("Rofellos, Llanowar Emissary"); @@ -103,7 +104,7 @@ public class Commander extends DeckValidator { valid = false; } - List basicLandNames = new ArrayList<>(Arrays.asList("Forest", "Island", "Mountain", "Swamp", "Plains", + List basicLandNames = new ArrayList<>(Arrays.asList("Forest", "Island", "Mountain", "Swamp", "Plains", "Wastes", "Snow-Covered Forest", "Snow-Covered Island", "Snow-Covered Mountain", "Snow-Covered Swamp", "Snow-Covered Plains")); Map counts = new HashMap<>(); countCards(counts, deck.getCards()); @@ -130,22 +131,22 @@ public class Commander extends DeckValidator { invalid.put("Commander", "Commander invalid "); return false; } - if ((commander.getCardType().contains(CardType.CREATURE) && commander.getSupertype().contains("Legendary")) || - (commander.getCardType().contains(CardType.PLANESWALKER) && commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance()))) { + if ((commander.getCardType().contains(CardType.CREATURE) && commander.getSupertype().contains("Legendary")) + || (commander.getCardType().contains(CardType.PLANESWALKER) && commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance()))) { if (!bannedCommander.contains(commander.getName())) { FilterMana color = CardUtil.getColorIdentity(commander); for (Card card : deck.getCards()) { if (!cardHasValidColor(color, card)) { - invalid.put(card.getName(), "Invalid color (" + commander.getName() +")"); + invalid.put(card.getName(), "Invalid color (" + commander.getName() + ")"); valid = false; } } } else { - invalid.put("Commander", "Commander banned (" + commander.getName() +")"); + invalid.put("Commander", "Commander banned (" + commander.getName() + ")"); valid = false; } } else { - invalid.put("Commander", "Commander invalid (" + commander.getName() +")"); + invalid.put("Commander", "Commander invalid (" + commander.getName() + ")"); valid = false; } } else { diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/DuelCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/DuelCommander.java index a380531598e..2e19b6a0bd9 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/DuelCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/DuelCommander.java @@ -40,7 +40,6 @@ public class DuelCommander extends Commander { banned.add("Balance"); banned.add("Back to Basics"); banned.add("Black Lotus"); - banned.add("Cataclysm"); banned.add("Channel"); banned.add("Entomb"); banned.add("Fastbond"); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Modern.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Modern.java index 5004b04cfb2..ff6ca105df0 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Modern.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Modern.java @@ -27,21 +27,18 @@ */ package mage.deck; +import java.util.Date; +import java.util.GregorianCalendar; import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; import mage.constants.SetType; -import java.util.Date; -import java.util.GregorianCalendar; - - /** * * @author LevelX2 */ - public class Modern extends Constructed { public Modern() { super("Constructed - Modern"); @@ -56,14 +53,14 @@ public class Modern extends Constructed { banned.add("Ancestral Vision"); banned.add("Ancient Den"); - banned.add("Birthing Pod"); // banned effective January 23, 2015 + banned.add("Birthing Pod"); banned.add("Blazing Shoal"); - banned.add("Bloodbraid Elf"); // (banned effective February 1, 2013) + banned.add("Bloodbraid Elf"); banned.add("Chrome Mox"); banned.add("Cloudpost"); banned.add("Dark Depths"); - banned.add("Deathrite Shaman"); // (banned effective February 7, 2014 - banned.add("Dig Through Time"); // banned effective January 23, 2015 + banned.add("Deathrite Shaman"); + banned.add("Dig Through Time"); banned.add("Dread Return"); banned.add("Glimpse of Nature"); banned.add("Great Furnace"); @@ -76,16 +73,17 @@ public class Modern extends Constructed { banned.add("Punishing Fire"); banned.add("Rite of Flame"); banned.add("Seat of the Synod"); - banned.add("Second Sunrise"); // (banned effective May 3, 2013) - banned.add("Seething Song"); // (banned effective February 1, 2013) + banned.add("Second Sunrise"); + banned.add("Seething Song"); banned.add("Sensei's Divining Top"); banned.add("Stoneforge Mystic"); banned.add("Skullclamp"); + banned.add("Splinter Twin"); + banned.add("Summer Bloom"); banned.add("Sword of the Meek"); - banned.add("Treasure Cruise"); // banned effective January 23, 2015 + banned.add("Treasure Cruise"); banned.add("Tree of Tales"); banned.add("Umezawa's Jitte"); banned.add("Vault of Whispers"); - } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Momir.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Momir.java index 48a05c3c81e..9d9ac7c27cb 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Momir.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Momir.java @@ -27,12 +27,13 @@ */ package mage.deck; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import mage.cards.Card; import mage.cards.decks.Deck; import mage.cards.decks.DeckValidator; -import java.util.*; - /** * * @author nigelzor diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java index 583b9ee154e..637db8c31d9 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java @@ -23,6 +23,7 @@ public class Pauper extends Constructed { rarities.add(Rarity.COMMON); rarities.add(Rarity.LAND); + banned.add("Cloud of Faeries"); banned.add("Cloudpost"); banned.add("Cranial Plating"); banned.add("Empty the Warrens"); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java index 7817d0be700..c9e6181cf50 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java @@ -120,7 +120,7 @@ public class TinyLeaders extends DeckValidator { valid = false; } - List basicLandNames = new ArrayList<>(Arrays.asList("Forest", "Island", "Mountain", "Swamp", "Plains", + List basicLandNames = new ArrayList<>(Arrays.asList("Forest", "Island", "Mountain", "Swamp", "Plains", "Wastes", "Snow-Covered Forest", "Snow-Covered Island", "Snow-Covered Mountain", "Snow-Covered Swamp", "Snow-Covered Plains")); Map counts = new HashMap<>(); counts.put(deck.getName(), 1); // add the commander to the counts, so it can't be in the deck or sideboard again @@ -145,19 +145,20 @@ public class TinyLeaders extends DeckValidator { if (deck.getSideboard().size() <= 10) { Card commander = GameTinyLeadersImpl.getCommanderCard(deck.getName(), null); /** - * 905.5b - Each card must have a converted mana cost of three of less. - * Cards with {X} in their mana cost count X as zero. - * Split and double-face cards are legal only if both of their halves would be legal independently. + * 905.5b - Each card must have a converted mana cost of three of + * less. Cards with {X} in their mana cost count X as zero. Split + * and double-face cards are legal only if both of their halves + * would be legal independently. */ - - if (commander == null || commander.getManaCost().convertedManaCost() > 3) { + + if (commander == null || commander.getManaCost().convertedManaCost() > 3) { if (commander == null) { if (deck.getName() == null) { - invalid.put("Leader", "You have to save your deck with the leader card name entered to the DECK NAME field of the DECK EDITOR (top left) so that XMage knows your leader." + - "(You can use the \"Sultai\" for a UBG (2/2) default Commander.)"); + invalid.put("Leader", "You have to save your deck with the leader card name entered to the DECK NAME field of the DECK EDITOR (top left) so that XMage knows your leader." + + "(You can use the \"Sultai\" for a UBG (3/3) default Commander or \"Glass\" for a colorless 3/3 default Commander.)"); } else { - invalid.put("Leader", "Leader [" + deck.getName() + "] not found. You have to enter the name of the leader card into the DECK NAME field of the DECK EDITOR (top left). Check your spelling " + - "(use the \"Sultai\" for a UBG (2/2) default Commander)"); + invalid.put("Leader", "Leader [" + deck.getName() + "] not found. You have to enter the name of the leader card into the DECK NAME field of the DECK EDITOR (top left). Check your spelling " + + "(use the \"Sultai\" for a UBG (3/3) default Commander or \"Glass\" for a colorless (3/3) default Commander)"); } } @@ -172,12 +173,12 @@ public class TinyLeaders extends DeckValidator { FilterMana color = CardUtil.getColorIdentity(commander); for (Card card : deck.getCards()) { if (!isCardFormatValid(card, commander, color)) { - valid = false; + valid = false; } } for (Card card : deck.getSideboard()) { if (!isCardFormatValid(card, commander, color)) { - valid = false; + valid = false; } } } else { @@ -204,14 +205,14 @@ public class TinyLeaders extends DeckValidator { //905.5b - Converted mana cost must be 3 or less if (card instanceof SplitCard) { - if (((SplitCard) card).getLeftHalfCard().getManaCost().convertedManaCost() > 3) { + if (((SplitCard) card).getLeftHalfCard().getManaCost().convertedManaCost() > 3) { invalid.put(card.getName(), "Invalid cost (" + ((SplitCard) card).getLeftHalfCard().getManaCost().convertedManaCost() + ")"); - return false; + return false; } - if (((SplitCard) card).getRightHalfCard().getManaCost().convertedManaCost() > 3 ) { + if (((SplitCard) card).getRightHalfCard().getManaCost().convertedManaCost() > 3) { invalid.put(card.getName(), "Invalid cost (" + ((SplitCard) card).getRightHalfCard().getManaCost().convertedManaCost() + ")"); - return false; - } + return false; + } } else { if (card.getManaCost().convertedManaCost() > 3) { invalid.put(card.getName(), "Invalid cost (" + card.getManaCost().convertedManaCost() + ")"); @@ -220,7 +221,7 @@ public class TinyLeaders extends DeckValidator { } return true; } - + /** * * @param commander FilterMana object with Color Identity of Commander set diff --git a/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml b/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml index ad51b6fe050..d750b4d3853 100644 --- a/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml +++ b/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.6 + 1.4.8 mage-deck-limited diff --git a/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml index 7a2563128e2..7d9a8e7549d 100644 --- a/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.6 + 1.4.8 mage-game-commanderduel diff --git a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml index f9c458cb372..35ca14148ac 100644 --- a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml @@ -6,7 +6,7 @@ org.mage mage-server-plugins - 1.4.6 + 1.4.8 mage-game-commanderfreeforall diff --git a/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml index 3816caad33a..48a762df5d8 100644 --- a/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.6 + 1.4.8 mage-game-freeforall diff --git a/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml index f6a35865beb..60d8c59dd06 100644 --- a/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.6 + 1.4.8 mage-game-momirduel diff --git a/Mage.Server.Plugins/Mage.Game.MomirDuel/src/mage/game/MomirDuel.java b/Mage.Server.Plugins/Mage.Game.MomirDuel/src/mage/game/MomirDuel.java index e34dd81d2a9..9d37e749ad4 100644 --- a/Mage.Server.Plugins/Mage.Game.MomirDuel/src/mage/game/MomirDuel.java +++ b/Mage.Server.Plugins/Mage.Game.MomirDuel/src/mage/game/MomirDuel.java @@ -27,6 +27,11 @@ */ package mage.game; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -38,7 +43,13 @@ import mage.cards.Card; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.MultiplayerAttackOption; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.constants.RangeOfInfluence; +import mage.constants.TimingRule; +import mage.constants.Zone; import mage.game.command.Emblem; import mage.game.match.MatchType; import mage.game.permanent.token.EmptyToken; @@ -46,8 +57,6 @@ import mage.game.turn.TurnMod; import mage.players.Player; import mage.util.CardUtil; -import java.util.*; - /** * * @author nigelzor @@ -89,7 +98,7 @@ public class MomirDuel extends GameImpl { @Override public Set getOpponents(UUID playerId) { Set opponents = new HashSet<>(); - for (UUID opponentId: this.getPlayer(playerId).getInRange()) { + for (UUID opponentId : this.getPlayer(playerId).getInRange()) { if (!opponentId.equals(playerId)) { opponents.add(opponentId); } @@ -114,7 +123,7 @@ class MomirEmblem extends Emblem { public MomirEmblem() { setName("Momir Vig, Simic Visionary"); - + //TODO: setExpansionSetCodeForImage(???); // {X}, Discard a card: Put a token into play as a copy of a random creature card with converted mana cost X. Play this ability only any time you could play a sorcery and only once each turn. LimitedTimesPerTurnActivatedAbility ability = new LimitedTimesPerTurnActivatedAbility(Zone.COMMAND, new MomirEffect(), new VariableManaCost()); ability.addCost(new DiscardCardCost()); @@ -153,7 +162,9 @@ class MomirEffect extends OneShotEffect { EmptyToken token = new EmptyToken(); CardUtil.copyTo(token).from(card); token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId(), false, false); + } else { + game.informPlayers("No random creature card with converted mana cost of " + value + " was found."); } return true; } -} \ No newline at end of file +} diff --git a/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml index e957b99153d..45fd9cc0cd9 100644 --- a/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.6 + 1.4.8 mage-game-tinyleadersduel diff --git a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml index e355ec4226e..f0fef0763f8 100644 --- a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.6 + 1.4.8 mage-game-twoplayerduel diff --git a/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml b/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml index c1b578d1829..3f199c86b60 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.6 + 1.4.8 mage-player-ai-draftbot diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml b/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml index 0bf78a21406..33ed3edb207 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.6 + 1.4.8 mage-player-ai-ma diff --git a/Mage.Server.Plugins/Mage.Player.AI/pom.xml b/Mage.Server.Plugins/Mage.Player.AI/pom.xml index 5bcdee9d51e..ef1eec05151 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AI/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.6 + 1.4.8 mage-player-ai 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 6e2acbb8fa9..187c0438957 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 @@ -56,6 +56,7 @@ import mage.abilities.SpellAbility; import mage.abilities.TriggeredAbility; import mage.abilities.costs.VariableCost; import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.costs.mana.ColorlessManaCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.HybridManaCost; import mage.abilities.costs.mana.ManaCost; @@ -1007,7 +1008,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (card.getManaCost().getVariableCosts().size() > 0) { //don't use variable mana costs unless there is at least 3 extra mana for X for (Mana option : options) { - option.add(Mana.ColorlessMana(3)); + option.add(Mana.GenericMana(3)); } } for (Mana mana : options) { @@ -1041,7 +1042,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (ability.getManaCosts().getVariableCosts().size() > 0) { //don't use variable mana costs unless there is at least 3 extra mana for X for (Mana option : abilityOptions) { - option.add(Mana.ColorlessMana(3)); + option.add(Mana.GenericMana(3)); } } if (abilityOptions.size() == 0) { @@ -1167,6 +1168,18 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } } + // pay colorless + for (ManaAbility manaAbility : perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { + if (cost instanceof ColorlessManaCost) { + for (Mana netMana : manaAbility.getNetMana(game)) { + if (cost.testPay(netMana) || spendAnyMana) { + if (activateAbility(manaAbility, game)) { + return true; + } + } + } + } + } // finally pay generic for (ManaAbility manaAbility : perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { if (cost instanceof GenericManaCost) { @@ -1182,7 +1195,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } // pay phyrexian life costs if (cost instanceof PhyrexianManaCost) { - if (cost.pay(null, game, null, playerId, false) || spendAnyMana) { + if (cost.pay(null, game, null, playerId, false, null) || spendAnyMana) { return true; } } diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml b/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml index 7a3965952c3..d6b9f5c2391 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.6 + 1.4.8 mage-player-ai-mcts diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml b/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml index 4a661539c2c..94f05621aad 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.6 + 1.4.8 mage-player-aiminimax diff --git a/Mage.Server.Plugins/Mage.Player.Human/pom.xml b/Mage.Server.Plugins/Mage.Player.Human/pom.xml index 4cceb3b98aa..e26cbefa9ce 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.Human/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.6 + 1.4.8 mage-player-human 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 ee62a58f33d..9dc9d7ff025 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 @@ -358,15 +358,13 @@ public class HumanPlayer extends PlayerImpl { } } } - } else { - if (target.canTarget(response.getUUID(), game)) { - if (target.getTargets().contains(response.getUUID())) { // if already included remove it with - target.remove(response.getUUID()); - } else { - target.addTarget(response.getUUID(), null, game); - if (target.doneChosing()) { - return true; - } + } else if (target.canTarget(response.getUUID(), game)) { + if (target.getTargets().contains(response.getUUID())) { // if already included remove it with + target.remove(response.getUUID()); + } else { + target.addTarget(response.getUUID(), null, game); + if (target.doneChosing()) { + return true; } } } @@ -530,12 +528,10 @@ public class HumanPlayer extends PlayerImpl { if (response.getUUID() != null) { if (target.getTargets().contains(response.getUUID())) { // if already included remove it target.remove(response.getUUID()); - } else { - if (target.canTarget(response.getUUID(), cards, game)) { - target.addTarget(response.getUUID(), source, game); - if (target.doneChosing()) { - return true; - } + } else if (target.canTarget(response.getUUID(), cards, game)) { + target.addTarget(response.getUUID(), source, game); + if (target.doneChosing()) { + return true; } } } else { @@ -805,7 +801,7 @@ public class HumanPlayer extends PlayerImpl { if (cost instanceof PhyrexianManaCost) { PhyrexianManaCost ph = (PhyrexianManaCost) cost; if (ph.canPay(null, null, playerId, game)) { - ((PhyrexianManaCost) cost).pay(null, game, null, playerId, false); + ((PhyrexianManaCost) cost).pay(null, game, null, playerId, false, null); } break; } @@ -1065,10 +1061,8 @@ public class HumanPlayer extends PlayerImpl { // does not block yet and can block or can block more attackers if (filter.match(blocker, null, playerId, game)) { selectCombatGroup(defendingPlayerId, blocker.getId(), game); - } else { - if (filterBlock.match(blocker, null, playerId, game) && game.getStack().isEmpty()) { - removeBlocker = true; - } + } else if (filterBlock.match(blocker, null, playerId, game) && game.getStack().isEmpty()) { + removeBlocker = true; } if (removeBlocker) { @@ -1546,4 +1540,9 @@ public class HumanPlayer extends PlayerImpl { pass(game); return true; } + + @Override + public String getHistory() { + return "no available"; + } } diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml index 96a49310ed3..8c2ffcdb398 100644 --- a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml +++ b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.6 + 1.4.8 mage-tournament-boosterdraft diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/MTGOLegacyCube.java b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/LegacyCube.java similarity index 99% rename from Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/MTGOLegacyCube.java rename to Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/LegacyCube.java index 5221f4668ca..5b64916b808 100644 --- a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/MTGOLegacyCube.java +++ b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/LegacyCube.java @@ -34,9 +34,9 @@ import mage.game.draft.DraftCube; * @author LevelX2 */ -public class MTGOLegacyCube extends DraftCube { +public class LegacyCube extends DraftCube { - public MTGOLegacyCube() { + public LegacyCube() { super("MTGO Legacy Cube (600 cards)"); cubeCards.add(new CardIdentity("Accorder Paladin","")); cubeCards.add(new CardIdentity("Abrupt Decay","")); diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/LegacyCubeJanuary2016.java b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/LegacyCubeJanuary2016.java new file mode 100644 index 00000000000..eb11a98cd10 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/LegacyCubeJanuary2016.java @@ -0,0 +1,642 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.tournament.cubes; + +import mage.game.draft.DraftCube; + +/** + * + * @author fireshoes + */ + +public class LegacyCubeJanuary2016 extends DraftCube { + + public LegacyCubeJanuary2016() { + super("MTGO Legacy Cube January 2016 (600 cards)"); + cubeCards.add(new DraftCube.CardIdentity("Abbot of Keral Keep","")); + cubeCards.add(new DraftCube.CardIdentity("Abhorrent Overlord","")); + cubeCards.add(new DraftCube.CardIdentity("Abrupt Decay","")); + cubeCards.add(new DraftCube.CardIdentity("Abyssal Persecutor","")); + cubeCards.add(new DraftCube.CardIdentity("Accorder Paladin","")); + cubeCards.add(new DraftCube.CardIdentity("Acidic Slime","")); + cubeCards.add(new DraftCube.CardIdentity("Act of Aggression","")); + cubeCards.add(new DraftCube.CardIdentity("Adarkar Wastes","")); + cubeCards.add(new DraftCube.CardIdentity("Ainok Survivalist","")); + cubeCards.add(new DraftCube.CardIdentity("Ajani Goldmane","")); + cubeCards.add(new DraftCube.CardIdentity("Ajani Vengeant","")); + cubeCards.add(new DraftCube.CardIdentity("Ajani, Caller of the Pride","")); + cubeCards.add(new DraftCube.CardIdentity("Anafenza, Kin-Tree Spirit","")); + cubeCards.add(new DraftCube.CardIdentity("Ancestral Vision","")); + cubeCards.add(new DraftCube.CardIdentity("Ancient Tomb","")); + cubeCards.add(new DraftCube.CardIdentity("Angel of Serenity","")); + cubeCards.add(new DraftCube.CardIdentity("Anger of the Gods","")); + cubeCards.add(new DraftCube.CardIdentity("Animate Dead","")); + cubeCards.add(new DraftCube.CardIdentity("Arbor Elf","")); + cubeCards.add(new DraftCube.CardIdentity("Arc Trail","")); + cubeCards.add(new DraftCube.CardIdentity("Archangel of Thune","")); + cubeCards.add(new DraftCube.CardIdentity("Arid Mesa","")); + cubeCards.add(new DraftCube.CardIdentity("Armageddon","")); + cubeCards.add(new DraftCube.CardIdentity("Ashcloud Phoenix","")); + cubeCards.add(new DraftCube.CardIdentity("Ashen Rider","")); + cubeCards.add(new DraftCube.CardIdentity("Ashenmoor Gouger","")); + cubeCards.add(new DraftCube.CardIdentity("Ashiok, Nightmare Weaver","")); + cubeCards.add(new DraftCube.CardIdentity("Assemble the Legion","")); + cubeCards.add(new DraftCube.CardIdentity("Attrition","")); + cubeCards.add(new DraftCube.CardIdentity("Augur of Bolas","")); + cubeCards.add(new DraftCube.CardIdentity("Avacyn's Pilgrim","")); + cubeCards.add(new DraftCube.CardIdentity("Avalanche Riders","")); + cubeCards.add(new DraftCube.CardIdentity("Avenger of Zendikar","")); + cubeCards.add(new DraftCube.CardIdentity("Badlands","")); + cubeCards.add(new DraftCube.CardIdentity("Baleful Strix","")); + cubeCards.add(new DraftCube.CardIdentity("Banefire","")); + cubeCards.add(new DraftCube.CardIdentity("Baneslayer Angel","")); + cubeCards.add(new DraftCube.CardIdentity("Banisher Priest","")); + cubeCards.add(new DraftCube.CardIdentity("Banishing Light","")); + cubeCards.add(new DraftCube.CardIdentity("Batterskull","")); + cubeCards.add(new DraftCube.CardIdentity("Battlefield Forge","")); + cubeCards.add(new DraftCube.CardIdentity("Bayou","")); + cubeCards.add(new DraftCube.CardIdentity("Beast Within","")); + cubeCards.add(new DraftCube.CardIdentity("Beetleback Chief","")); + cubeCards.add(new DraftCube.CardIdentity("Birds of Paradise","")); + cubeCards.add(new DraftCube.CardIdentity("Birthing Pod","")); + cubeCards.add(new DraftCube.CardIdentity("Bitterblossom","")); + cubeCards.add(new DraftCube.CardIdentity("Blade Splicer","")); + cubeCards.add(new DraftCube.CardIdentity("Blood Artist","")); + cubeCards.add(new DraftCube.CardIdentity("Blood Crypt","")); + cubeCards.add(new DraftCube.CardIdentity("Bloodbraid Elf","")); + cubeCards.add(new DraftCube.CardIdentity("Bloodghast","")); + cubeCards.add(new DraftCube.CardIdentity("Bloodsoaked Champion","")); + cubeCards.add(new DraftCube.CardIdentity("Bloodstained Mire","")); + cubeCards.add(new DraftCube.CardIdentity("Bloodthrone Vampire","")); + cubeCards.add(new DraftCube.CardIdentity("Bogardan Hellkite","")); + cubeCards.add(new DraftCube.CardIdentity("Bone Shredder","")); + cubeCards.add(new DraftCube.CardIdentity("Bonesplitter","")); + cubeCards.add(new DraftCube.CardIdentity("Bonfire of the Damned","")); + cubeCards.add(new DraftCube.CardIdentity("Boros Charm","")); + cubeCards.add(new DraftCube.CardIdentity("Boros Reckoner","")); + cubeCards.add(new DraftCube.CardIdentity("Brago, King Eternal","")); + cubeCards.add(new DraftCube.CardIdentity("Brainstorm","")); + cubeCards.add(new DraftCube.CardIdentity("Breeding Pool","")); + cubeCards.add(new DraftCube.CardIdentity("Brimaz, King of Oreskos","")); + cubeCards.add(new DraftCube.CardIdentity("Brimstone Volley","")); + cubeCards.add(new DraftCube.CardIdentity("Brushland","")); + cubeCards.add(new DraftCube.CardIdentity("Brutal Expulsion","")); + cubeCards.add(new DraftCube.CardIdentity("Buried Alive","")); + cubeCards.add(new DraftCube.CardIdentity("Burst Lightning","")); + cubeCards.add(new DraftCube.CardIdentity("Careful Study","")); + cubeCards.add(new DraftCube.CardIdentity("Carrier Thrall","")); + cubeCards.add(new DraftCube.CardIdentity("Carrion Feeder","")); + cubeCards.add(new DraftCube.CardIdentity("Catacomb Sifter","")); + cubeCards.add(new DraftCube.CardIdentity("Caves of Koilos","")); + cubeCards.add(new DraftCube.CardIdentity("Chain Lightning","")); + cubeCards.add(new DraftCube.CardIdentity("Chainer's Edict","")); + cubeCards.add(new DraftCube.CardIdentity("Chameleon Colossus","")); + cubeCards.add(new DraftCube.CardIdentity("Champion of the Parish","")); + cubeCards.add(new DraftCube.CardIdentity("Chandra Nalaar","")); + cubeCards.add(new DraftCube.CardIdentity("Chandra, Fire of Kaladesh","")); + cubeCards.add(new DraftCube.CardIdentity("Chandra, Pyromaster","")); + cubeCards.add(new DraftCube.CardIdentity("Chandra's Phoenix","")); + cubeCards.add(new DraftCube.CardIdentity("Char","")); + cubeCards.add(new DraftCube.CardIdentity("Chasm Skulker","")); + cubeCards.add(new DraftCube.CardIdentity("Chord of Calling","")); + cubeCards.add(new DraftCube.CardIdentity("Chromatic Lantern","")); + cubeCards.add(new DraftCube.CardIdentity("City of Brass","")); + cubeCards.add(new DraftCube.CardIdentity("Clifftop Retreat","")); + cubeCards.add(new DraftCube.CardIdentity("Cloudgoat Ranger","")); + cubeCards.add(new DraftCube.CardIdentity("Collected Company","")); + cubeCards.add(new DraftCube.CardIdentity("Compulsive Research","")); + cubeCards.add(new DraftCube.CardIdentity("Condemn","")); + cubeCards.add(new DraftCube.CardIdentity("Consecrated Sphinx","")); + cubeCards.add(new DraftCube.CardIdentity("Control Magic","")); + cubeCards.add(new DraftCube.CardIdentity("Coralhelm Commander","")); + cubeCards.add(new DraftCube.CardIdentity("Council's Judgment","")); + cubeCards.add(new DraftCube.CardIdentity("Counterspell","")); + cubeCards.add(new DraftCube.CardIdentity("Courser of Kruphix","")); + cubeCards.add(new DraftCube.CardIdentity("Crater's Claws","")); + cubeCards.add(new DraftCube.CardIdentity("Craterhoof Behemoth","")); + cubeCards.add(new DraftCube.CardIdentity("Crusade","")); + cubeCards.add(new DraftCube.CardIdentity("Crux of Fate","")); + cubeCards.add(new DraftCube.CardIdentity("Cryptic Command","")); + cubeCards.add(new DraftCube.CardIdentity("Cultivate","")); + cubeCards.add(new DraftCube.CardIdentity("Cunning Sparkmage","")); + cubeCards.add(new DraftCube.CardIdentity("Cursed Scroll","")); + cubeCards.add(new DraftCube.CardIdentity("Cyclonic Rift","")); + cubeCards.add(new DraftCube.CardIdentity("Damnation","")); + cubeCards.add(new DraftCube.CardIdentity("Dance of the Dead","")); + cubeCards.add(new DraftCube.CardIdentity("Dark Confidant","")); + cubeCards.add(new DraftCube.CardIdentity("Dark Depths","")); + cubeCards.add(new DraftCube.CardIdentity("Dark Petition","")); + cubeCards.add(new DraftCube.CardIdentity("Dark Ritual","")); + cubeCards.add(new DraftCube.CardIdentity("Day of Judgment","")); + cubeCards.add(new DraftCube.CardIdentity("Daze","")); + cubeCards.add(new DraftCube.CardIdentity("Deathrite Shaman","")); + cubeCards.add(new DraftCube.CardIdentity("Deceiver Exarch","")); + cubeCards.add(new DraftCube.CardIdentity("Deep Analysis","")); + cubeCards.add(new DraftCube.CardIdentity("Delver of Secrets","")); + cubeCards.add(new DraftCube.CardIdentity("Den Protector","")); + cubeCards.add(new DraftCube.CardIdentity("Deranged Hermit","")); + cubeCards.add(new DraftCube.CardIdentity("Desecration Demon","")); + cubeCards.add(new DraftCube.CardIdentity("Devil's Play","")); + cubeCards.add(new DraftCube.CardIdentity("Diabolic Servitude","")); + cubeCards.add(new DraftCube.CardIdentity("Dictate of Heliod","")); + cubeCards.add(new DraftCube.CardIdentity("Disciple of Bolas","")); + cubeCards.add(new DraftCube.CardIdentity("Disfigure","")); + cubeCards.add(new DraftCube.CardIdentity("Dismember","")); + cubeCards.add(new DraftCube.CardIdentity("Dismiss","")); + cubeCards.add(new DraftCube.CardIdentity("Dissipate","")); + cubeCards.add(new DraftCube.CardIdentity("Dissolve","")); + cubeCards.add(new DraftCube.CardIdentity("Divinity of Pride","")); + cubeCards.add(new DraftCube.CardIdentity("Domri Rade","")); + cubeCards.add(new DraftCube.CardIdentity("Doom Blade","")); + cubeCards.add(new DraftCube.CardIdentity("Dragon Fodder","")); + cubeCards.add(new DraftCube.CardIdentity("Dragonlord Atarka","")); + cubeCards.add(new DraftCube.CardIdentity("Dragonlord Dromoka","")); + cubeCards.add(new DraftCube.CardIdentity("Dragonlord Ojutai","")); + cubeCards.add(new DraftCube.CardIdentity("Dragonlord Silumgar","")); + cubeCards.add(new DraftCube.CardIdentity("Dragonskull Summit","")); + cubeCards.add(new DraftCube.CardIdentity("Drana, Liberator of Malakir","")); + cubeCards.add(new DraftCube.CardIdentity("Dread Return","")); + cubeCards.add(new DraftCube.CardIdentity("Dreadbore","")); + cubeCards.add(new DraftCube.CardIdentity("Dromoka's Command","")); + cubeCards.add(new DraftCube.CardIdentity("Drowned Catacomb","")); + cubeCards.add(new DraftCube.CardIdentity("Dualcaster Mage","")); + cubeCards.add(new DraftCube.CardIdentity("Dungeon Geists","")); + cubeCards.add(new DraftCube.CardIdentity("Duplicant","")); + cubeCards.add(new DraftCube.CardIdentity("Duress","")); + cubeCards.add(new DraftCube.CardIdentity("Eldrazi Monument","")); + cubeCards.add(new DraftCube.CardIdentity("Edric, Spymaster of Trest","")); + cubeCards.add(new DraftCube.CardIdentity("Electrolyze","")); + cubeCards.add(new DraftCube.CardIdentity("Elesh Norn, Grand Cenobite","")); + cubeCards.add(new DraftCube.CardIdentity("Elite Vanguard","")); + cubeCards.add(new DraftCube.CardIdentity("Elixir of Immortality","")); + cubeCards.add(new DraftCube.CardIdentity("Elspeth Tirel","")); + cubeCards.add(new DraftCube.CardIdentity("Elspeth, Knight-Errant","")); + cubeCards.add(new DraftCube.CardIdentity("Elspeth, Sun's Champion","")); + cubeCards.add(new DraftCube.CardIdentity("Elves of Deep Shadow","")); + cubeCards.add(new DraftCube.CardIdentity("Elvish Mystic","")); + cubeCards.add(new DraftCube.CardIdentity("Emeria Angel","")); + cubeCards.add(new DraftCube.CardIdentity("Emrakul, the Aeons Torn","")); + cubeCards.add(new DraftCube.CardIdentity("Entomb","")); + cubeCards.add(new DraftCube.CardIdentity("Entreat the Angels","")); + cubeCards.add(new DraftCube.CardIdentity("Erebos, God of the Dead","")); + cubeCards.add(new DraftCube.CardIdentity("Eternal Dragon","")); + cubeCards.add(new DraftCube.CardIdentity("Eternal Witness","")); + cubeCards.add(new DraftCube.CardIdentity("Eureka","")); + cubeCards.add(new DraftCube.CardIdentity("Evolutionary Leap","")); + cubeCards.add(new DraftCube.CardIdentity("Exalted Angel","")); + cubeCards.add(new DraftCube.CardIdentity("Exclude","")); + cubeCards.add(new DraftCube.CardIdentity("Exhume","")); + cubeCards.add(new DraftCube.CardIdentity("Explore","")); + cubeCards.add(new DraftCube.CardIdentity("Exquisite Firecraft","")); + cubeCards.add(new DraftCube.CardIdentity("Fact or Fiction","")); + cubeCards.add(new DraftCube.CardIdentity("Faith's Fetters","")); + cubeCards.add(new DraftCube.CardIdentity("Falkenrath Aristocrat","")); + cubeCards.add(new DraftCube.CardIdentity("Farseek","")); + cubeCards.add(new DraftCube.CardIdentity("Fauna Shaman","")); + cubeCards.add(new DraftCube.CardIdentity("Fertile Ground","")); + cubeCards.add(new DraftCube.CardIdentity("Fiend Hunter","")); + cubeCards.add(new DraftCube.CardIdentity("Fiery Confluence","")); + cubeCards.add(new DraftCube.CardIdentity("Fire // Ice","")); + cubeCards.add(new DraftCube.CardIdentity("Firebolt","")); + cubeCards.add(new DraftCube.CardIdentity("Firefist Striker","")); + cubeCards.add(new DraftCube.CardIdentity("Flame Slash","")); + cubeCards.add(new DraftCube.CardIdentity("Flametongue Kavu","")); + cubeCards.add(new DraftCube.CardIdentity("Flamewake Phoenix","")); + cubeCards.add(new DraftCube.CardIdentity("Flickerwisp","")); + cubeCards.add(new DraftCube.CardIdentity("Flooded Strand","")); + cubeCards.add(new DraftCube.CardIdentity("Forbid","")); + cubeCards.add(new DraftCube.CardIdentity("Forbidden Alchemy","")); + cubeCards.add(new DraftCube.CardIdentity("Force of Will","")); + cubeCards.add(new DraftCube.CardIdentity("Force Spike","")); + cubeCards.add(new DraftCube.CardIdentity("Forked Bolt","")); + cubeCards.add(new DraftCube.CardIdentity("Frenzied Goblin","")); + cubeCards.add(new DraftCube.CardIdentity("Freyalise, Llanowar's Fury","")); + cubeCards.add(new DraftCube.CardIdentity("From Beyond","")); + cubeCards.add(new DraftCube.CardIdentity("Frontline Medic","")); + cubeCards.add(new DraftCube.CardIdentity("Frost Titan","")); + cubeCards.add(new DraftCube.CardIdentity("Future Sight","")); + cubeCards.add(new DraftCube.CardIdentity("Fyndhorn Elves","")); + cubeCards.add(new DraftCube.CardIdentity("Gaddock Teeg","")); + cubeCards.add(new DraftCube.CardIdentity("Gaea's Cradle","")); + cubeCards.add(new DraftCube.CardIdentity("Garruk Relentless","")); + cubeCards.add(new DraftCube.CardIdentity("Garruk Wildspeaker","")); + cubeCards.add(new DraftCube.CardIdentity("Garruk, Apex Predator","")); + cubeCards.add(new DraftCube.CardIdentity("Garruk, Caller of Beasts","")); + cubeCards.add(new DraftCube.CardIdentity("Garruk, Primal Hunter","")); + cubeCards.add(new DraftCube.CardIdentity("Gatekeeper of Malakir","")); + cubeCards.add(new DraftCube.CardIdentity("Gather the Townsfolk","")); + cubeCards.add(new DraftCube.CardIdentity("Geist of Saint Traft","")); + cubeCards.add(new DraftCube.CardIdentity("Genesis Hydra","")); + cubeCards.add(new DraftCube.CardIdentity("Genesis Wave","")); + cubeCards.add(new DraftCube.CardIdentity("Geralf's Messenger","")); + cubeCards.add(new DraftCube.CardIdentity("Gideon, Ally of Zendikar","")); + cubeCards.add(new DraftCube.CardIdentity("Gideon Jura","")); + cubeCards.add(new DraftCube.CardIdentity("Gifts Ungiven","")); + cubeCards.add(new DraftCube.CardIdentity("Gilded Lotus","")); + cubeCards.add(new DraftCube.CardIdentity("Gilt-Leaf Winnower","")); + cubeCards.add(new DraftCube.CardIdentity("Gitaxian Probe","")); + cubeCards.add(new DraftCube.CardIdentity("Glacial Fortress","")); + cubeCards.add(new DraftCube.CardIdentity("Glen Elendra Archmage","")); + cubeCards.add(new DraftCube.CardIdentity("Glorious Anthem","")); + cubeCards.add(new DraftCube.CardIdentity("Go for the Throat","")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Bombardment","")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Bushwhacker","")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Glory Chaser","")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Guide","")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Rabblemaster","")); + cubeCards.add(new DraftCube.CardIdentity("Godless Shrine","")); + cubeCards.add(new DraftCube.CardIdentity("Gore-House Chainwalker","")); + cubeCards.add(new DraftCube.CardIdentity("Grafted Wargear","")); + cubeCards.add(new DraftCube.CardIdentity("Grave Titan","")); + cubeCards.add(new DraftCube.CardIdentity("Gravecrawler","")); + cubeCards.add(new DraftCube.CardIdentity("Gray Merchant of Asphodel","")); + cubeCards.add(new DraftCube.CardIdentity("Greater Gargadon","")); + cubeCards.add(new DraftCube.CardIdentity("Green Sun's Zenith","")); + cubeCards.add(new DraftCube.CardIdentity("Greenwarden of Murasa","")); + cubeCards.add(new DraftCube.CardIdentity("Grim Lavamancer","")); + cubeCards.add(new DraftCube.CardIdentity("Griselbrand","")); + cubeCards.add(new DraftCube.CardIdentity("Hall of Triumph","")); + cubeCards.add(new DraftCube.CardIdentity("Hallowed Fountain","")); + cubeCards.add(new DraftCube.CardIdentity("Hallowed Spiritkeeper","")); + cubeCards.add(new DraftCube.CardIdentity("Hangarback Walker","")); + cubeCards.add(new DraftCube.CardIdentity("Harbinger of the Tides","")); + cubeCards.add(new DraftCube.CardIdentity("Harmonize","")); + cubeCards.add(new DraftCube.CardIdentity("Hellrider","")); + cubeCards.add(new DraftCube.CardIdentity("Hero of Bladehold","")); + cubeCards.add(new DraftCube.CardIdentity("Hero's Downfall","")); + cubeCards.add(new DraftCube.CardIdentity("Hidden Dragonslayer","")); + cubeCards.add(new DraftCube.CardIdentity("High Market","")); + cubeCards.add(new DraftCube.CardIdentity("Hinterland Harbor","")); + cubeCards.add(new DraftCube.CardIdentity("Honor of the Pure","")); + cubeCards.add(new DraftCube.CardIdentity("Hordeling Outburst","")); + cubeCards.add(new DraftCube.CardIdentity("Hornet Queen","")); + cubeCards.add(new DraftCube.CardIdentity("Huntmaster of the Fells","")); + cubeCards.add(new DraftCube.CardIdentity("Hymn to Tourach","")); + cubeCards.add(new DraftCube.CardIdentity("Hypnotic Specter","")); + cubeCards.add(new DraftCube.CardIdentity("Imperial Recruiter","")); + cubeCards.add(new DraftCube.CardIdentity("Impulse","")); + cubeCards.add(new DraftCube.CardIdentity("Incinerate","")); + cubeCards.add(new DraftCube.CardIdentity("Indrik Stomphowler","")); + cubeCards.add(new DraftCube.CardIdentity("Inferno Titan","")); + cubeCards.add(new DraftCube.CardIdentity("Inquisition of Kozilek","")); + cubeCards.add(new DraftCube.CardIdentity("Into the Roil","")); + cubeCards.add(new DraftCube.CardIdentity("Ire Shaman","")); + cubeCards.add(new DraftCube.CardIdentity("Isamaru, Hound of Konda","")); + cubeCards.add(new DraftCube.CardIdentity("Isochron Scepter","")); + cubeCards.add(new DraftCube.CardIdentity("Isolated Chapel","")); + cubeCards.add(new DraftCube.CardIdentity("Izzet Charm","")); + cubeCards.add(new DraftCube.CardIdentity("Jace Beleren","")); + cubeCards.add(new DraftCube.CardIdentity("Jace, Architect of Thought","")); + cubeCards.add(new DraftCube.CardIdentity("Jace, the Mind Sculptor","")); + cubeCards.add(new DraftCube.CardIdentity("Jace, Vryn's Prodigy","")); + cubeCards.add(new DraftCube.CardIdentity("Jackal Pup","")); + cubeCards.add(new DraftCube.CardIdentity("Joraga Treespeaker","")); + cubeCards.add(new DraftCube.CardIdentity("Journey to Nowhere","")); + cubeCards.add(new DraftCube.CardIdentity("Kami of Ancient Law","")); + cubeCards.add(new DraftCube.CardIdentity("Karmic Guide","")); + cubeCards.add(new DraftCube.CardIdentity("Karn Liberated","")); + cubeCards.add(new DraftCube.CardIdentity("Karplusan Forest","")); + cubeCards.add(new DraftCube.CardIdentity("Keiga, the Tide Star","")); + cubeCards.add(new DraftCube.CardIdentity("Keranos, God of Storms","")); + cubeCards.add(new DraftCube.CardIdentity("Kiki-Jiki, Mirror Breaker","")); + cubeCards.add(new DraftCube.CardIdentity("Kiln Fiend","")); + cubeCards.add(new DraftCube.CardIdentity("Kiora, the Crashing Wave","")); + cubeCards.add(new DraftCube.CardIdentity("Kiora's Follower","")); + cubeCards.add(new DraftCube.CardIdentity("Kira, Great Glass-Spinner","")); + cubeCards.add(new DraftCube.CardIdentity("Kitchen Finks","")); + cubeCards.add(new DraftCube.CardIdentity("Kodama's Reach","")); + cubeCards.add(new DraftCube.CardIdentity("Kokusho, the Evening Star","")); + cubeCards.add(new DraftCube.CardIdentity("Kor Skyfisher","")); + cubeCards.add(new DraftCube.CardIdentity("Koth of the Hammer","")); + cubeCards.add(new DraftCube.CardIdentity("Kozilek, Butcher of Truth","")); + cubeCards.add(new DraftCube.CardIdentity("Krenko's Command","")); + cubeCards.add(new DraftCube.CardIdentity("Kytheon, Hero of Akros","")); + cubeCards.add(new DraftCube.CardIdentity("Land Tax","")); + cubeCards.add(new DraftCube.CardIdentity("Legacy's Allure","")); + cubeCards.add(new DraftCube.CardIdentity("Leonin Relic-Warder","")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Bolt","")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Greaves","")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Helix","")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Mauler","")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Strike","")); + cubeCards.add(new DraftCube.CardIdentity("Liliana of the Veil","")); + cubeCards.add(new DraftCube.CardIdentity("Liliana Vess","")); + cubeCards.add(new DraftCube.CardIdentity("Liliana, Heretical Healer","")); + cubeCards.add(new DraftCube.CardIdentity("Lingering Souls","")); + cubeCards.add(new DraftCube.CardIdentity("Linvala, Keeper of Silence","")); + cubeCards.add(new DraftCube.CardIdentity("Living Death","")); + cubeCards.add(new DraftCube.CardIdentity("Llanowar Elves","")); + cubeCards.add(new DraftCube.CardIdentity("Llanowar Wastes","")); + cubeCards.add(new DraftCube.CardIdentity("Looter il-Kor","")); + cubeCards.add(new DraftCube.CardIdentity("Lotus Cobra","")); + cubeCards.add(new DraftCube.CardIdentity("Loxodon Warhammer","")); + cubeCards.add(new DraftCube.CardIdentity("Maelstrom Pulse","")); + cubeCards.add(new DraftCube.CardIdentity("Magma Jet","")); + cubeCards.add(new DraftCube.CardIdentity("Makeshift Mannequin","")); + cubeCards.add(new DraftCube.CardIdentity("Malicious Affliction","")); + cubeCards.add(new DraftCube.CardIdentity("Man-o'-War","")); + cubeCards.add(new DraftCube.CardIdentity("Mana Confluence","")); + cubeCards.add(new DraftCube.CardIdentity("Mana Tithe","")); + cubeCards.add(new DraftCube.CardIdentity("Managorger Hydra","")); + cubeCards.add(new DraftCube.CardIdentity("Manic Vandal","")); + cubeCards.add(new DraftCube.CardIdentity("Marsh Flats","")); + cubeCards.add(new DraftCube.CardIdentity("Martial Coup","")); + cubeCards.add(new DraftCube.CardIdentity("Massacre Wurm","")); + cubeCards.add(new DraftCube.CardIdentity("Master of the Wild Hunt","")); + cubeCards.add(new DraftCube.CardIdentity("Master of Waves","")); + cubeCards.add(new DraftCube.CardIdentity("Meloku the Clouded Mirror","")); + cubeCards.add(new DraftCube.CardIdentity("Mentor of the Meek","")); + cubeCards.add(new DraftCube.CardIdentity("Merfolk Looter","")); + cubeCards.add(new DraftCube.CardIdentity("Meteor Blast","")); + cubeCards.add(new DraftCube.CardIdentity("Mimic Vat","")); + cubeCards.add(new DraftCube.CardIdentity("Mirari's Wake","")); + cubeCards.add(new DraftCube.CardIdentity("Mirran Crusader","")); + cubeCards.add(new DraftCube.CardIdentity("Miscalculation","")); + cubeCards.add(new DraftCube.CardIdentity("Mishra's Factory","")); + cubeCards.add(new DraftCube.CardIdentity("Misty Rainforest","")); + cubeCards.add(new DraftCube.CardIdentity("Mizzium Mortars","")); + cubeCards.add(new DraftCube.CardIdentity("Mogg War Marshal","")); + cubeCards.add(new DraftCube.CardIdentity("Mogis's Marauder","")); + cubeCards.add(new DraftCube.CardIdentity("Monastery Mentor","")); + cubeCards.add(new DraftCube.CardIdentity("Monastery Swiftspear","")); + cubeCards.add(new DraftCube.CardIdentity("Mother of Runes","")); + cubeCards.add(new DraftCube.CardIdentity("Mulldrifter","")); + cubeCards.add(new DraftCube.CardIdentity("Murderous Cut","")); + cubeCards.add(new DraftCube.CardIdentity("Mutavault","")); + cubeCards.add(new DraftCube.CardIdentity("Myr Battlesphere","")); + cubeCards.add(new DraftCube.CardIdentity("Mystic Confluence","")); + cubeCards.add(new DraftCube.CardIdentity("Mystic Snake","")); + cubeCards.add(new DraftCube.CardIdentity("Nantuko Husk","")); + cubeCards.add(new DraftCube.CardIdentity("Natural Order","")); + cubeCards.add(new DraftCube.CardIdentity("Nature's Lore","")); + cubeCards.add(new DraftCube.CardIdentity("Necromancy","")); + cubeCards.add(new DraftCube.CardIdentity("Negate","")); + cubeCards.add(new DraftCube.CardIdentity("Nekrataal","")); + cubeCards.add(new DraftCube.CardIdentity("Nicol Bolas, Planeswalker","")); + cubeCards.add(new DraftCube.CardIdentity("Nightveil Specter","")); + cubeCards.add(new DraftCube.CardIdentity("Nissa, Vastwood Seer","")); + cubeCards.add(new DraftCube.CardIdentity("Nissa, Worldwaker","")); + cubeCards.add(new DraftCube.CardIdentity("Noble Hierarch","")); + cubeCards.add(new DraftCube.CardIdentity("Nykthos, Shrine to Nyx","")); + cubeCards.add(new DraftCube.CardIdentity("Ob Nixilis Reignited","")); + cubeCards.add(new DraftCube.CardIdentity("Oblivion Ring","")); + cubeCards.add(new DraftCube.CardIdentity("Obstinate Baloth","")); + cubeCards.add(new DraftCube.CardIdentity("Ohran Viper","")); + cubeCards.add(new DraftCube.CardIdentity("Old Man of the Sea","")); + cubeCards.add(new DraftCube.CardIdentity("Olivia Voldaren","")); + cubeCards.add(new DraftCube.CardIdentity("Omnath, Locus of Rage","")); + cubeCards.add(new DraftCube.CardIdentity("Oona's Prowler","")); + cubeCards.add(new DraftCube.CardIdentity("Ophiomancer","")); + cubeCards.add(new DraftCube.CardIdentity("Opposition","")); + cubeCards.add(new DraftCube.CardIdentity("Oracle of Mul Daya","")); + cubeCards.add(new DraftCube.CardIdentity("Oust","")); + cubeCards.add(new DraftCube.CardIdentity("Outpost Siege","")); + cubeCards.add(new DraftCube.CardIdentity("Overgrown Battlement","")); + cubeCards.add(new DraftCube.CardIdentity("Overgrown Tomb","")); + cubeCards.add(new DraftCube.CardIdentity("Pack Rat","")); + cubeCards.add(new DraftCube.CardIdentity("Pact of Negation","")); + cubeCards.add(new DraftCube.CardIdentity("Parallax Wave","")); + cubeCards.add(new DraftCube.CardIdentity("Part the Waterveil","")); + cubeCards.add(new DraftCube.CardIdentity("Path to Exile","")); + cubeCards.add(new DraftCube.CardIdentity("Pestermite","")); + cubeCards.add(new DraftCube.CardIdentity("Phantasmal Image","")); + cubeCards.add(new DraftCube.CardIdentity("Phyrexian Arena","")); + cubeCards.add(new DraftCube.CardIdentity("Phyrexian Metamorph","")); + cubeCards.add(new DraftCube.CardIdentity("Phyrexian Obliterator","")); + cubeCards.add(new DraftCube.CardIdentity("Phyrexian Revoker","")); + cubeCards.add(new DraftCube.CardIdentity("Pia and Kiran Nalaar","")); + cubeCards.add(new DraftCube.CardIdentity("Pillar of Flame","")); + cubeCards.add(new DraftCube.CardIdentity("Plateau","")); + cubeCards.add(new DraftCube.CardIdentity("Polluted Delta","")); + cubeCards.add(new DraftCube.CardIdentity("Polukranos, World Eater","")); + cubeCards.add(new DraftCube.CardIdentity("Ponder","")); + cubeCards.add(new DraftCube.CardIdentity("Porcelain Legionnaire","")); + cubeCards.add(new DraftCube.CardIdentity("Precinct Captain","")); + cubeCards.add(new DraftCube.CardIdentity("Precursor Golem","")); + cubeCards.add(new DraftCube.CardIdentity("Preordain","")); + cubeCards.add(new DraftCube.CardIdentity("Primal Command","")); + cubeCards.add(new DraftCube.CardIdentity("Primeval Titan","")); + cubeCards.add(new DraftCube.CardIdentity("Profane Command","")); + cubeCards.add(new DraftCube.CardIdentity("Progenitus","")); + cubeCards.add(new DraftCube.CardIdentity("Prophetic Flamespeaker","")); + cubeCards.add(new DraftCube.CardIdentity("Psychatog","")); + cubeCards.add(new DraftCube.CardIdentity("Purphoros, God of the Forge","")); + cubeCards.add(new DraftCube.CardIdentity("Qasali Pridemage","")); + cubeCards.add(new DraftCube.CardIdentity("Quarantine Field","")); + cubeCards.add(new DraftCube.CardIdentity("Raise the Alarm","")); + cubeCards.add(new DraftCube.CardIdentity("Rakdos's Return","")); + cubeCards.add(new DraftCube.CardIdentity("Ral Zarek","")); + cubeCards.add(new DraftCube.CardIdentity("Rampaging Baloths","")); + cubeCards.add(new DraftCube.CardIdentity("Rampant Growth","")); + cubeCards.add(new DraftCube.CardIdentity("Ranger of Eos","")); + cubeCards.add(new DraftCube.CardIdentity("Ratchet Bomb","")); + cubeCards.add(new DraftCube.CardIdentity("Ravages of War","")); + cubeCards.add(new DraftCube.CardIdentity("Read the Bones","")); + cubeCards.add(new DraftCube.CardIdentity("Reanimate","")); + cubeCards.add(new DraftCube.CardIdentity("Reclamation Sage","")); + cubeCards.add(new DraftCube.CardIdentity("Recurring Nightmare","")); + cubeCards.add(new DraftCube.CardIdentity("Reflecting Pool","")); + cubeCards.add(new DraftCube.CardIdentity("Regrowth","")); + cubeCards.add(new DraftCube.CardIdentity("Relic of Progenitus","")); + cubeCards.add(new DraftCube.CardIdentity("Remand","")); + cubeCards.add(new DraftCube.CardIdentity("Remove Soul","")); + cubeCards.add(new DraftCube.CardIdentity("Repeal","")); + cubeCards.add(new DraftCube.CardIdentity("Restoration Angel","")); + cubeCards.add(new DraftCube.CardIdentity("Reveillark","")); + cubeCards.add(new DraftCube.CardIdentity("Rift Bolt","")); + cubeCards.add(new DraftCube.CardIdentity("Riftwing Cloudskate","")); + cubeCards.add(new DraftCube.CardIdentity("Righteous Confluence","")); + cubeCards.add(new DraftCube.CardIdentity("Rishadan Port","")); + cubeCards.add(new DraftCube.CardIdentity("Roast","")); + cubeCards.add(new DraftCube.CardIdentity("Rofellos, Llanowar Emissary","")); + cubeCards.add(new DraftCube.CardIdentity("Rootbound Crag","")); + cubeCards.add(new DraftCube.CardIdentity("Rune-Scarred Demon","")); + cubeCards.add(new DraftCube.CardIdentity("Sacred Foundry","")); + cubeCards.add(new DraftCube.CardIdentity("Sakura-Tribe Elder","")); + cubeCards.add(new DraftCube.CardIdentity("Sarkhan, the Dragonspeaker","")); + cubeCards.add(new DraftCube.CardIdentity("Savannah","")); + cubeCards.add(new DraftCube.CardIdentity("Scalding Tarn","")); + cubeCards.add(new DraftCube.CardIdentity("Scavenging Ooze","")); + cubeCards.add(new DraftCube.CardIdentity("Scroll Rack","")); + cubeCards.add(new DraftCube.CardIdentity("Scrubland","")); + cubeCards.add(new DraftCube.CardIdentity("Sea Gate Oracle","")); + cubeCards.add(new DraftCube.CardIdentity("Seal of Fire","")); + cubeCards.add(new DraftCube.CardIdentity("Search for Tomorrow","")); + cubeCards.add(new DraftCube.CardIdentity("Searing Spear","")); + cubeCards.add(new DraftCube.CardIdentity("Secure the Wastes","")); + cubeCards.add(new DraftCube.CardIdentity("Seeker of the Way","")); + cubeCards.add(new DraftCube.CardIdentity("Sensei's Divining Top","")); + cubeCards.add(new DraftCube.CardIdentity("Serendib Efreet","")); + cubeCards.add(new DraftCube.CardIdentity("Serum Visions","")); + cubeCards.add(new DraftCube.CardIdentity("Shadowmage Infiltrator","")); + cubeCards.add(new DraftCube.CardIdentity("Shaman of Forgotten Ways","")); + cubeCards.add(new DraftCube.CardIdentity("Shardless Agent","")); + cubeCards.add(new DraftCube.CardIdentity("Sheoldred, Whispering One","")); + cubeCards.add(new DraftCube.CardIdentity("Shivan Reef","")); + cubeCards.add(new DraftCube.CardIdentity("Show and Tell","")); + cubeCards.add(new DraftCube.CardIdentity("Shriekmaw","")); + cubeCards.add(new DraftCube.CardIdentity("Sidisi, Undead Vizier","")); + cubeCards.add(new DraftCube.CardIdentity("Siege-Gang Commander","")); + cubeCards.add(new DraftCube.CardIdentity("Silverblade Paladin","")); + cubeCards.add(new DraftCube.CardIdentity("Sin Collector","")); + cubeCards.add(new DraftCube.CardIdentity("Skinrender","")); + cubeCards.add(new DraftCube.CardIdentity("Skullcrack","")); + cubeCards.add(new DraftCube.CardIdentity("Slagstorm","")); + cubeCards.add(new DraftCube.CardIdentity("Slaughter Pact","")); + cubeCards.add(new DraftCube.CardIdentity("Snapcaster Mage","")); + cubeCards.add(new DraftCube.CardIdentity("Sneak Attack","")); + cubeCards.add(new DraftCube.CardIdentity("Soldier of the Pantheon","")); + cubeCards.add(new DraftCube.CardIdentity("Solemn Simulacrum","")); + cubeCards.add(new DraftCube.CardIdentity("Song of the Dryads","")); + cubeCards.add(new DraftCube.CardIdentity("Sorin Markov","")); + cubeCards.add(new DraftCube.CardIdentity("Sorin, Solemn Visitor","")); + cubeCards.add(new DraftCube.CardIdentity("Soulfire Grand Master","")); + cubeCards.add(new DraftCube.CardIdentity("Sower of Temptation","")); + cubeCards.add(new DraftCube.CardIdentity("Spear of Heliod","")); + cubeCards.add(new DraftCube.CardIdentity("Spectral Procession","")); + cubeCards.add(new DraftCube.CardIdentity("Spellskite","")); + cubeCards.add(new DraftCube.CardIdentity("Spell Pierce","")); + cubeCards.add(new DraftCube.CardIdentity("Sphinx's Revelation","")); + cubeCards.add(new DraftCube.CardIdentity("Spikeshot Elder","")); + cubeCards.add(new DraftCube.CardIdentity("Splinter Twin","")); + cubeCards.add(new DraftCube.CardIdentity("Staggershock","")); + cubeCards.add(new DraftCube.CardIdentity("Steam Vents","")); + cubeCards.add(new DraftCube.CardIdentity("Stoke the Flames","")); + cubeCards.add(new DraftCube.CardIdentity("Stomping Ground","")); + cubeCards.add(new DraftCube.CardIdentity("Stormbreath Dragon","")); + cubeCards.add(new DraftCube.CardIdentity("Stormtide Leviathan","")); + cubeCards.add(new DraftCube.CardIdentity("Stratus Dancer","")); + cubeCards.add(new DraftCube.CardIdentity("Stroke of Genius","")); + cubeCards.add(new DraftCube.CardIdentity("Stromkirk Noble","")); + cubeCards.add(new DraftCube.CardIdentity("Student of Warfare","")); + cubeCards.add(new DraftCube.CardIdentity("Sublime Archangel","")); + cubeCards.add(new DraftCube.CardIdentity("Sulfur Falls","")); + cubeCards.add(new DraftCube.CardIdentity("Sulfurous Springs","")); + cubeCards.add(new DraftCube.CardIdentity("Summoning Trap","")); + cubeCards.add(new DraftCube.CardIdentity("Sun Titan","")); + cubeCards.add(new DraftCube.CardIdentity("Sundering Titan","")); + cubeCards.add(new DraftCube.CardIdentity("Sunpetal Grove","")); + cubeCards.add(new DraftCube.CardIdentity("Supreme Verdict","")); + cubeCards.add(new DraftCube.CardIdentity("Surrak, the Hunt Caller","")); + cubeCards.add(new DraftCube.CardIdentity("Swords to Plowshares","")); + cubeCards.add(new DraftCube.CardIdentity("Sylvan Caryatid","")); + cubeCards.add(new DraftCube.CardIdentity("Sylvan Library","")); + cubeCards.add(new DraftCube.CardIdentity("Taiga","")); + cubeCards.add(new DraftCube.CardIdentity("Talrand, Sky Summoner","")); + cubeCards.add(new DraftCube.CardIdentity("Tamiyo, the Moon Sage","")); + cubeCards.add(new DraftCube.CardIdentity("Tangle Wire","")); + cubeCards.add(new DraftCube.CardIdentity("Tarmogoyf","")); + cubeCards.add(new DraftCube.CardIdentity("Tasigur, the Golden Fang","")); + cubeCards.add(new DraftCube.CardIdentity("Tectonic Edge","")); + cubeCards.add(new DraftCube.CardIdentity("Teferi, Mage of Zhalfir","")); + cubeCards.add(new DraftCube.CardIdentity("Temple Garden","")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Abandon","")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Deceit","")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Enlightenment","")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Epiphany","")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Malady","")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Malice","")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Mystery","")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Plenty","")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Silence","")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Triumph","")); + cubeCards.add(new DraftCube.CardIdentity("Terastodon","")); + cubeCards.add(new DraftCube.CardIdentity("Terminate","")); + cubeCards.add(new DraftCube.CardIdentity("Terminus","")); + cubeCards.add(new DraftCube.CardIdentity("Thalia, Guardian of Thraben","")); + cubeCards.add(new DraftCube.CardIdentity("Thassa, God of the Sea","")); + cubeCards.add(new DraftCube.CardIdentity("Thespian's Stage","")); + cubeCards.add(new DraftCube.CardIdentity("Thoughtseize","")); + cubeCards.add(new DraftCube.CardIdentity("Thragtusk","")); + cubeCards.add(new DraftCube.CardIdentity("Threads of Disloyalty","")); + cubeCards.add(new DraftCube.CardIdentity("Through the Breach","")); + cubeCards.add(new DraftCube.CardIdentity("Thrun, the Last Troll","")); + cubeCards.add(new DraftCube.CardIdentity("Thunderbreak Regent","")); + cubeCards.add(new DraftCube.CardIdentity("Thundermaw Hellkite","")); + cubeCards.add(new DraftCube.CardIdentity("Tidehollow Sculler","")); + cubeCards.add(new DraftCube.CardIdentity("Time Warp","")); + cubeCards.add(new DraftCube.CardIdentity("Tooth and Nail","")); + cubeCards.add(new DraftCube.CardIdentity("Toxic Deluge","")); + cubeCards.add(new DraftCube.CardIdentity("Treachery","")); + cubeCards.add(new DraftCube.CardIdentity("Tropical Island","")); + cubeCards.add(new DraftCube.CardIdentity("Trygon Predator","")); + cubeCards.add(new DraftCube.CardIdentity("Tundra","")); + cubeCards.add(new DraftCube.CardIdentity("Ugin, the Spirit Dragon","")); + cubeCards.add(new DraftCube.CardIdentity("Ulamog, the Ceaseless Hunger","")); + cubeCards.add(new DraftCube.CardIdentity("Ulamog, the Infinite Gyre","")); + cubeCards.add(new DraftCube.CardIdentity("Ultimate Price","")); + cubeCards.add(new DraftCube.CardIdentity("Unburial Rites","")); + cubeCards.add(new DraftCube.CardIdentity("Underground River","")); + cubeCards.add(new DraftCube.CardIdentity("Underground Sea","")); + cubeCards.add(new DraftCube.CardIdentity("Underworld Connections","")); + cubeCards.add(new DraftCube.CardIdentity("Unexpectedly Absent","")); + cubeCards.add(new DraftCube.CardIdentity("Upheaval","")); + cubeCards.add(new DraftCube.CardIdentity("Utopia Sprawl","")); + cubeCards.add(new DraftCube.CardIdentity("Vampire Hexmage","")); + cubeCards.add(new DraftCube.CardIdentity("Vampire Nighthawk","")); + cubeCards.add(new DraftCube.CardIdentity("Vendilion Clique","")); + cubeCards.add(new DraftCube.CardIdentity("Vengevine","")); + cubeCards.add(new DraftCube.CardIdentity("Venser, Shaper Savant","")); + cubeCards.add(new DraftCube.CardIdentity("Venser, the Sojourner","")); + cubeCards.add(new DraftCube.CardIdentity("Verdant Catacombs","")); + cubeCards.add(new DraftCube.CardIdentity("Vindicate","")); + cubeCards.add(new DraftCube.CardIdentity("Viscera Seer","")); + cubeCards.add(new DraftCube.CardIdentity("Volcanic Island","")); + cubeCards.add(new DraftCube.CardIdentity("Volrath's Stronghold","")); + cubeCards.add(new DraftCube.CardIdentity("Voyaging Satyr","")); + cubeCards.add(new DraftCube.CardIdentity("Vraska the Unseen","")); + cubeCards.add(new DraftCube.CardIdentity("Wake Thrasher","")); + cubeCards.add(new DraftCube.CardIdentity("Wall of Blossoms","")); + cubeCards.add(new DraftCube.CardIdentity("Wall of Omens","")); + cubeCards.add(new DraftCube.CardIdentity("Wall of Roots","")); + cubeCards.add(new DraftCube.CardIdentity("Warleader's Helix","")); + cubeCards.add(new DraftCube.CardIdentity("Waterfront Bouncer","")); + cubeCards.add(new DraftCube.CardIdentity("Watery Grave","")); + cubeCards.add(new DraftCube.CardIdentity("Whip of Erebos","")); + cubeCards.add(new DraftCube.CardIdentity("Whirler Rogue","")); + cubeCards.add(new DraftCube.CardIdentity("Whisperwood Elemental","")); + cubeCards.add(new DraftCube.CardIdentity("Windbrisk Heights","")); + cubeCards.add(new DraftCube.CardIdentity("Windswept Heath","")); + cubeCards.add(new DraftCube.CardIdentity("Winter Orb","")); + cubeCards.add(new DraftCube.CardIdentity("Wolfir Silverheart","")); + cubeCards.add(new DraftCube.CardIdentity("Wood Elves","")); + cubeCards.add(new DraftCube.CardIdentity("Wooded Foothills","")); + cubeCards.add(new DraftCube.CardIdentity("Woodfall Primus","")); + cubeCards.add(new DraftCube.CardIdentity("Woodland Cemetery","")); + cubeCards.add(new DraftCube.CardIdentity("Wrath of God","")); + cubeCards.add(new DraftCube.CardIdentity("Wretched Confluence","")); + cubeCards.add(new DraftCube.CardIdentity("Wurmcoil Engine","")); + cubeCards.add(new DraftCube.CardIdentity("Xenagos, the Reveler","")); + cubeCards.add(new DraftCube.CardIdentity("Yavimaya Coast","")); + cubeCards.add(new DraftCube.CardIdentity("Yavimaya Elder","")); + cubeCards.add(new DraftCube.CardIdentity("Yosei, the Morning Star","")); + cubeCards.add(new DraftCube.CardIdentity("Young Pyromancer","")); + cubeCards.add(new DraftCube.CardIdentity("Zealous Conscripts","")); + cubeCards.add(new DraftCube.CardIdentity("Zulaport Cutthroat","")); + } +} diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/MTGOLegacyCubeMarch2015.java b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/LegacyCubeMarch2015.java similarity index 99% rename from Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/MTGOLegacyCubeMarch2015.java rename to Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/LegacyCubeMarch2015.java index 6bfd5c837cc..402f1fee5bc 100644 --- a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/MTGOLegacyCubeMarch2015.java +++ b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/LegacyCubeMarch2015.java @@ -34,9 +34,9 @@ import mage.game.draft.DraftCube; * @author fireshoes */ -public class MTGOLegacyCubeMarch2015 extends DraftCube { +public class LegacyCubeMarch2015 extends DraftCube { - public MTGOLegacyCubeMarch2015() { + public LegacyCubeMarch2015() { super("MTGO Legacy Cube March 2015 (600 cards)"); cubeCards.add(new DraftCube.CardIdentity("Accorder Paladin","")); cubeCards.add(new DraftCube.CardIdentity("Abrupt Decay","")); diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/MTGOLegacyCubeSeptember2015.java b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/LegacyCubeSeptember2015.java similarity index 99% rename from Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/MTGOLegacyCubeSeptember2015.java rename to Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/LegacyCubeSeptember2015.java index 14f4a608c0a..b9abc2cf4d0 100644 --- a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/MTGOLegacyCubeSeptember2015.java +++ b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/LegacyCubeSeptember2015.java @@ -34,9 +34,9 @@ import mage.game.draft.DraftCube; * @author fireshoes */ -public class MTGOLegacyCubeSeptember2015 extends DraftCube { +public class LegacyCubeSeptember2015 extends DraftCube { - public MTGOLegacyCubeSeptember2015() { + public LegacyCubeSeptember2015() { super("MTGO Legacy Cube September 2015 (600 cards)"); cubeCards.add(new DraftCube.CardIdentity("Abbot of Keral Keep","")); cubeCards.add(new DraftCube.CardIdentity("Abhorrent Overlord","")); diff --git a/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml b/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml index 6940e7df1aa..351a99f9712 100644 --- a/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml +++ b/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.6 + 1.4.8 mage-tournament-constructed diff --git a/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml b/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml index 4818cd9d8b8..a722cc73ee8 100644 --- a/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml +++ b/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.6 + 1.4.8 mage-tournament-sealed diff --git a/Mage.Server.Plugins/pom.xml b/Mage.Server.Plugins/pom.xml index d2f4db41133..d72e100c2ff 100644 --- a/Mage.Server.Plugins/pom.xml +++ b/Mage.Server.Plugins/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.6 + 1.4.8 mage-server-plugins diff --git a/Mage.Server/config/config.xml b/Mage.Server/config/config.xml index 5bef52e6ac8..18c0364e689 100644 --- a/Mage.Server/config/config.xml +++ b/Mage.Server/config/config.xml @@ -19,6 +19,17 @@ userNamePattern - pattern for user name validity check maxAiOpponents - number of allowed AI opponents on the server saveGameActivated - allow game save and replay options (not working correctly yet) + authenticationActivated - "true" = user have to register to signon "false" = user need not to register + * mail configs only needed if authentication is activated: + * if mailUser = "" mailgun is used otherwise nativ mail server on the system + googleAccount - not supported currently + mailgunApiKey - key from the mailgun domain e.g. = "key-12121111..." + mailgunDomain - domain for the mailgun message sending + mailSmtpHost - hostname to send the mail + mailSmtpPort - port to send the mail + mailUser - username used to send the mail + mailPassword - passworf of the used user to send the mail + mailFromAddress - sender address --> @@ -73,9 +95,10 @@ - - - + + + + diff --git a/Mage.Server/pom.xml b/Mage.Server/pom.xml index dabb43df498..67862424c03 100644 --- a/Mage.Server/pom.xml +++ b/Mage.Server/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.6 + 1.4.8 mage-server @@ -148,6 +148,62 @@ ${project.version} runtime + + org.apache.shiro + shiro-core + 1.2.4 + jar + + + com.google.api-client + google-api-client + 1.21.0 + jar + + + com.google.apis + google-api-services-gmail + v1-rev35-1.21.0 + jar + + + com.google.oauth-client + google-oauth-client-java6 + 1.19.0 + jar + + + com.google.oauth-client + google-oauth-client-jetty + 1.19.0 + jar + + + javax.mail + mail + 1.4.2 + jar + + + com.sun.jersey + jersey-core + 1.19 + + + com.sun.jersey + jersey-client + 1.19 + + + com.sun.jersey.contribs + jersey-multipart + 1.19 + + + org.xerial + sqlite-jdbc + 3.7.2 + diff --git a/Mage.Server/release/config/config.xml b/Mage.Server/release/config/config.xml index fde0a0b1709..123ba8599f0 100644 --- a/Mage.Server/release/config/config.xml +++ b/Mage.Server/release/config/config.xml @@ -1,6 +1,36 @@ + @@ -52,9 +93,10 @@ - - - + + + + diff --git a/Mage.Server/src/main/java/mage/server/AuthorizedUser.java b/Mage.Server/src/main/java/mage/server/AuthorizedUser.java new file mode 100644 index 00000000000..f02b615e8c2 --- /dev/null +++ b/Mage.Server/src/main/java/mage/server/AuthorizedUser.java @@ -0,0 +1,60 @@ +package mage.server; + +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; +import org.apache.shiro.authc.AuthenticationInfo; +import org.apache.shiro.authc.AuthenticationToken; +import org.apache.shiro.authc.SimpleAuthenticationInfo; +import org.apache.shiro.authc.UsernamePasswordToken; +import org.apache.shiro.authc.credential.HashedCredentialsMatcher; +import org.apache.shiro.util.ByteSource; +import org.apache.shiro.codec.Base64; +import org.apache.shiro.crypto.hash.Hash; + +@DatabaseTable(tableName = "authorized_user") +public class AuthorizedUser { + + @DatabaseField(indexName = "name_index", unique = true) + protected String name; + + @DatabaseField + protected String password; + + @DatabaseField + protected String salt; + + @DatabaseField + protected String hashAlgorithm; + + @DatabaseField + protected int hashIterations; + + @DatabaseField(indexName = "email_index", unique = true) + protected String email; + + public AuthorizedUser() { + } + + public AuthorizedUser(String name, Hash hash, String email) { + this.name = name; + this.password = hash.toBase64(); + this.salt = hash.getSalt().toBase64(); + this.hashAlgorithm = hash.getAlgorithmName(); + this.hashIterations = hash.getIterations(); + this.email = email; + } + + public boolean doCredentialsMatch(String name, String password) { + HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(this.hashAlgorithm); + matcher.setHashIterations(this.hashIterations); + AuthenticationToken token = new UsernamePasswordToken(name, password); + AuthenticationInfo info = new SimpleAuthenticationInfo(this.name, + ByteSource.Util.bytes(Base64.decode(this.password)), + ByteSource.Util.bytes(Base64.decode(this.salt)), ""); + return matcher.doCredentialsMatch(token, info); + } + + public String getName() { + return this.name; + } +} diff --git a/Mage.Server/src/main/java/mage/server/AuthorizedUserRepository.java b/Mage.Server/src/main/java/mage/server/AuthorizedUserRepository.java new file mode 100644 index 00000000000..9507ce9a12d --- /dev/null +++ b/Mage.Server/src/main/java/mage/server/AuthorizedUserRepository.java @@ -0,0 +1,115 @@ +package mage.server; + +import com.j256.ormlite.dao.Dao; +import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.jdbc.JdbcConnectionSource; +import com.j256.ormlite.stmt.DeleteBuilder; +import com.j256.ormlite.stmt.QueryBuilder; +import com.j256.ormlite.stmt.SelectArg; +import com.j256.ormlite.support.ConnectionSource; +import com.j256.ormlite.support.DatabaseConnection; +import com.j256.ormlite.table.TableUtils; +import java.io.File; +import java.sql.SQLException; +import java.util.List; +import mage.cards.repository.RepositoryUtil; +import org.apache.log4j.Logger; +import org.apache.shiro.crypto.RandomNumberGenerator; +import org.apache.shiro.crypto.SecureRandomNumberGenerator; +import org.apache.shiro.crypto.hash.Hash; +import org.apache.shiro.crypto.hash.Sha256Hash; +import org.apache.shiro.crypto.hash.SimpleHash; + +public enum AuthorizedUserRepository { + + instance; + + private static final String JDBC_URL = "jdbc:h2:file:./db/authorized_user.h2;AUTO_SERVER=TRUE"; + private static final String VERSION_ENTITY_NAME = "authorized_user"; + // raise this if db structure was changed + private static final long DB_VERSION = 1; + private static final RandomNumberGenerator rng = new SecureRandomNumberGenerator(); + + private Dao dao; + + private AuthorizedUserRepository() { + File file = new File("db"); + if (!file.exists()) { + file.mkdirs(); + } + try { + ConnectionSource connectionSource = new JdbcConnectionSource(JDBC_URL); + boolean obsolete = RepositoryUtil.isDatabaseObsolete(connectionSource, VERSION_ENTITY_NAME, DB_VERSION); + + if (obsolete) { + TableUtils.dropTable(connectionSource, AuthorizedUser.class, true); + } + + TableUtils.createTableIfNotExists(connectionSource, AuthorizedUser.class); + dao = DaoManager.createDao(connectionSource, AuthorizedUser.class); + } catch (SQLException ex) { + Logger.getLogger(AuthorizedUserRepository.class).error("Error creating authorized_user repository - ", ex); + } + } + + public void add(final String userName, final String password, final String email) { + try { + Hash hash = new SimpleHash(Sha256Hash.ALGORITHM_NAME, password, rng.nextBytes(), 1024); + AuthorizedUser user = new AuthorizedUser(userName, hash, email); + dao.create(user); + } catch (SQLException ex) { + Logger.getLogger(AuthorizedUserRepository.class).error("Error adding a user to DB - ", ex); + } + } + + public void remove(final String userName) { + try { + DeleteBuilder db = dao.deleteBuilder(); + db.where().eq("name", new SelectArg(userName)); + db.delete(); + } catch (SQLException ex) { + Logger.getLogger(AuthorizedUserRepository.class).error("Error removing a user from DB - ", ex); + } + } + + public AuthorizedUser getByName(String userName) { + try { + QueryBuilder qb = dao.queryBuilder(); + qb.where().eq("name", new SelectArg(userName)); + List results = dao.query(qb.prepare()); + if (results.size() == 1) { + return results.get(0); + } + return null; + } catch (SQLException ex) { + Logger.getLogger(AuthorizedUserRepository.class).error("Error getting a authorized_user - ", ex); + } + return null; + } + + public AuthorizedUser getByEmail(String userName) { + try { + QueryBuilder qb = dao.queryBuilder(); + qb.where().eq("email", new SelectArg(userName)); + List results = dao.query(qb.prepare()); + if (results.size() == 1) { + return results.get(0); + } + return null; + } catch (SQLException ex) { + Logger.getLogger(AuthorizedUserRepository.class).error("Error getting a authorized_user - ", ex); + } + return null; + } + + public void closeDB() { + try { + if (dao != null && dao.getConnectionSource() != null) { + DatabaseConnection conn = dao.getConnectionSource().getReadWriteConnection(); + conn.executeStatement("shutdown compact", 0); + } + } catch (SQLException ex) { + Logger.getLogger(AuthorizedUserRepository.class).error("Error closing authorized_user repository - ", ex); + } + } +} diff --git a/Mage.Server/src/main/java/mage/server/ChatManager.java b/Mage.Server/src/main/java/mage/server/ChatManager.java index f5a5c945cf7..8fbc80dd99c 100644 --- a/Mage.Server/src/main/java/mage/server/ChatManager.java +++ b/Mage.Server/src/main/java/mage/server/ChatManager.java @@ -24,8 +24,7 @@ * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. -*/ - + */ package mage.server; import java.util.ArrayList; @@ -44,14 +43,15 @@ import org.apache.log4j.Logger; public class ChatManager { private static final Logger logger = Logger.getLogger(ChatManager.class); - + private static final ChatManager INSTANCE = new ChatManager(); public static ChatManager getInstance() { return INSTANCE; } - private ChatManager() {} + private ChatManager() { + } private final ConcurrentHashMap chatSessions = new ConcurrentHashMap<>(); @@ -66,16 +66,16 @@ public class ChatManager { if (chatSession != null) { chatSession.join(userId); } else { - logger.trace("Chat to join not found - chatId: " + chatId +" userId: " + userId); - } - + logger.trace("Chat to join not found - chatId: " + chatId + " userId: " + userId); + } + } public void leaveChat(UUID chatId, UUID userId) { ChatSession chatSession = chatSessions.get(chatId); if (chatSession != null && chatSession.hasUser(userId)) { chatSession.kill(userId, DisconnectReason.CleaningUp); - } + } } public void destroyChatSession(UUID chatId) { @@ -88,7 +88,7 @@ public class ChatManager { logger.trace("Chat removed - chatId: " + chatId); } else { logger.trace("Chat to destroy does not exist - chatId: " + chatId); - } + } } } } @@ -110,7 +110,7 @@ public class ChatManager { ChatSession chatSession = chatSessions.get(chatId); if (chatSession != null) { if (message.startsWith("\\") || message.startsWith("/")) { - User user = UserManager.getInstance().findUser(userName); + User user = UserManager.getInstance().getUserByName(userName); if (user != null && performUserCommand(user, message, chatId)) { return; } @@ -119,63 +119,56 @@ public class ChatManager { } } - private boolean performUserCommand(User user, String message, UUID chatId) { String command = message.substring(1).trim().toUpperCase(Locale.ENGLISH); - if (command.equals("I") || command.equals("INFO")) { - user.setInfo(""); - chatSessions.get(chatId).broadcastInfoToUser(user,message); - return true; - } - if (command.startsWith("I ") || command.startsWith("INFO ")) { - user.setInfo(message.substring(command.startsWith("I ") ? 3 : 6)); - chatSessions.get(chatId).broadcastInfoToUser(user,message); + if (command.startsWith("H ") || command.startsWith("HISTORY ")) { + message = UserManager.getInstance().getUserHistory(message.substring(command.startsWith("H ") ? 3 : 9)); + chatSessions.get(chatId).broadcastInfoToUser(user, message); return true; } if (command.startsWith("W ") || command.startsWith("WHISPER ")) { - String rest = message.substring(command.startsWith("W ")? 3 : 9); + String rest = message.substring(command.startsWith("W ") ? 3 : 9); int first = rest.indexOf(" "); if (first > 1) { - String userToName = rest.substring(0,first); + String userToName = rest.substring(0, first); rest = rest.substring(first + 1).trim(); - User userTo = UserManager.getInstance().findUser(userToName); + User userTo = UserManager.getInstance().getUserByName(userToName); if (userTo != null) { if (!chatSessions.get(chatId).broadcastWhisperToUser(user, userTo, rest)) { message += new StringBuilder("
User ").append(userToName).append(" not found").toString(); - chatSessions.get(chatId).broadcastInfoToUser(user,message); + chatSessions.get(chatId).broadcastInfoToUser(user, message); } } else { message += new StringBuilder("
User ").append(userToName).append(" not found").toString(); - chatSessions.get(chatId).broadcastInfoToUser(user,message); + chatSessions.get(chatId).broadcastInfoToUser(user, message); } return true; } } if (command.equals("L") || command.equals("LIST")) { message += new StringBuilder("
List of commands:") - .append("
\\info [text] - set a info text to your player") - .append("
\\list - Show a list of commands") - .append("
\\whisper [player name] [text] - whisper to the player with the given name").toString(); - chatSessions.get(chatId).broadcastInfoToUser(user,message); + .append("
\\history or \\h [username] - shows the history of a player") + .append("
\\list or \\l - Show a list of commands") + .append("
\\whisper or \\w [player name] [text] - whisper to the player with the given name").toString(); + chatSessions.get(chatId).broadcastInfoToUser(user, message); return true; } return false; } - - /** - * - * use mainly for announcing that a user connection was lost or that a user has reconnected - * + * + * use mainly for announcing that a user connection was lost or that a user + * has reconnected + * * @param userId * @param message - * @param color + * @param color */ public void broadcast(UUID userId, String message, MessageColor color) { User user = UserManager.getInstance().getUser(userId); if (user != null) { - for (ChatSession chat: chatSessions.values()) { + for (ChatSession chat : chatSessions.values()) { if (chat.hasUser(userId)) { chat.broadcast(user.getName(), message, color); } @@ -186,16 +179,16 @@ public class ChatManager { public void sendReconnectMessage(UUID userId) { User user = UserManager.getInstance().getUser(userId); if (user != null) { - for (ChatSession chat: chatSessions.values()) { + for (ChatSession chat : chatSessions.values()) { if (chat.hasUser(userId)) { chat.broadcast(null, user.getName() + " has reconnected", MessageColor.BLUE, true, MessageType.STATUS); - } - } + } + } } } - + public void removeUser(UUID userId, DisconnectReason reason) { - for (ChatSession chatSession: chatSessions.values()) { + for (ChatSession chatSession : chatSessions.values()) { if (chatSession.hasUser(userId)) { chatSession.kill(userId, reason); } diff --git a/Mage.Server/src/main/java/mage/server/GmailClient.java b/Mage.Server/src/main/java/mage/server/GmailClient.java new file mode 100644 index 00000000000..3edc2f307ed --- /dev/null +++ b/Mage.Server/src/main/java/mage/server/GmailClient.java @@ -0,0 +1,91 @@ +package mage.server; + +import com.google.api.client.auth.oauth2.Credential; +import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp; +import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver; +import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow; +import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets; +import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.json.JsonFactory; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.client.util.Base64; +import com.google.api.client.util.store.FileDataStoreFactory; +import com.google.api.services.gmail.Gmail; +import com.google.api.services.gmail.Gmail.Builder; +import com.google.api.services.gmail.GmailScopes; +import com.google.api.services.gmail.model.Message; +import java.io.ByteArrayOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.Collections; +import java.util.Properties; +import javax.mail.MessagingException; +import javax.mail.Session; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; +import mage.server.util.ConfigSettings; +import org.apache.log4j.Logger; + +public class GmailClient { + + private static final Logger logger = Logger.getLogger(Main.class); + private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance(); + private static final java.io.File DATA_STORE_DIR = new java.io.File(System.getProperty("user.home"), ".store/xmage"); + private static FileDataStoreFactory dataStoreFactory; + private static HttpTransport httpTransport; + private static Credential credential; + + public static boolean initilize() { + try { + dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR); + httpTransport = GoogleNetHttpTransport.newTrustedTransport(); + + GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new FileReader("client_secrets.json")); + if (clientSecrets.getDetails().getClientId().startsWith("Enter") + || clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) { + logger.error("client_secrets.json not found"); + return false; + } + + GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder( + httpTransport, JSON_FACTORY, clientSecrets, + Collections.singleton(GmailScopes.GMAIL_COMPOSE)).setDataStoreFactory( + dataStoreFactory).build(); + + credential = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user"); + return true; + } catch (IOException | GeneralSecurityException ex) { + logger.error("Error initializing GmailClient", ex); + } + return false; + } + + public static boolean sendMessage(String email, String subject, String text) { + if (email.length() == 0) { + logger.info("Email is not sent because the address is empty"); + return false; + } + try { + Gmail gmail = new Builder(httpTransport, JSON_FACTORY, credential).setApplicationName("XMage Server").build(); + + MimeMessage mimeMessage = new MimeMessage(Session.getDefaultInstance(new Properties())); + mimeMessage.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(email)); + mimeMessage.setSubject(subject); + mimeMessage.setText(text); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + mimeMessage.writeTo(baos); + Message message = new Message(); + message.setRaw(Base64.encodeBase64URLSafeString(baos.toByteArray())); + + gmail.users().messages().send(ConfigSettings.getInstance().getGoogleAccount() + + (ConfigSettings.getInstance().getGoogleAccount().endsWith("@gmail.com") ? "" : "@gmail.com"), message).execute(); + return true; + } catch (MessagingException | IOException ex) { + logger.error("Error sending message", ex); + } + return false; + } +} diff --git a/Mage.Server/src/main/java/mage/server/MageServerImpl.java b/Mage.Server/src/main/java/mage/server/MageServerImpl.java index 46c6ce0aadb..6489473a794 100644 --- a/Mage.Server/src/main/java/mage/server/MageServerImpl.java +++ b/Mage.Server/src/main/java/mage/server/MageServerImpl.java @@ -27,9 +27,12 @@ */ package mage.server; +import java.security.SecureRandom; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.ExecutorService; @@ -95,25 +98,105 @@ public class MageServerImpl implements MageServer { private static final Logger logger = Logger.getLogger(MageServerImpl.class); private static final ExecutorService callExecutor = ThreadExecutor.getInstance().getCallExecutor(); + private static final SecureRandom RANDOM = new SecureRandom(); - private final String password; + private final String adminPassword; private final boolean testMode; + private final LinkedHashMap activeAuthTokens = new LinkedHashMap() { + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + // Keep the latest 1024 auth tokens in memory. + return size() > 1024; + } + }; - public MageServerImpl(String password, boolean testMode) { - this.password = password; + public MageServerImpl(String adminPassword, boolean testMode) { + this.adminPassword = adminPassword; this.testMode = testMode; ServerMessagesUtil.getInstance().getMessages(); } + @Override + public boolean registerUser(String sessionId, String userName, String password, String email) throws MageException { + return SessionManager.getInstance().registerUser(sessionId, userName, password, email); + } + + // generateAuthToken returns a uniformly distributed 6-digits string. + static private String generateAuthToken() { + return String.format("%06d", RANDOM.nextInt(1000000)); + } + + @Override + public boolean emailAuthToken(String sessionId, String email) throws MageException { + if (!ConfigSettings.getInstance().isAuthenticationActivated()) { + sendErrorMessageToClient(sessionId, "Registration is disabled by the server config"); + return false; + } + AuthorizedUser authorizedUser = AuthorizedUserRepository.instance.getByEmail(email); + if (authorizedUser == null) { + sendErrorMessageToClient(sessionId, "No user was found with the email address " + email); + logger.info("Auth token is requested for " + email + " but there's no such user in DB"); + return false; + } + String authToken = generateAuthToken(); + activeAuthTokens.put(email, authToken); + String subject = "XMage Password Reset Auth Token"; + String text = "Use this auth token to reset your password: " + authToken + "\n" + + "It's valid until the next server restart."; + boolean success; + if (!ConfigSettings.getInstance().getMailUser().isEmpty()) { + success = MailClient.sendMessage(email, subject, text); + } else { + success = MailgunClient.sendMessage(email, subject, text); + } + if (!success) { + sendErrorMessageToClient(sessionId, "There was an error inside the server while emailing an auth token"); + return false; + } + return true; + } + + @Override + public boolean resetPassword(String sessionId, String email, String authToken, String password) throws MageException { + if (!ConfigSettings.getInstance().isAuthenticationActivated()) { + sendErrorMessageToClient(sessionId, "Registration is disabled by the server config"); + return false; + } + String storedAuthToken = activeAuthTokens.get(email); + if (storedAuthToken == null || !storedAuthToken.equals(authToken)) { + sendErrorMessageToClient(sessionId, "Invalid auth token"); + logger.info("Invalid auth token " + authToken + " is sent for " + email); + return false; + } + AuthorizedUser authorizedUser = AuthorizedUserRepository.instance.getByEmail(email); + if (authorizedUser == null) { + sendErrorMessageToClient(sessionId, "The user is no longer in the DB"); + logger.info("Auth token is valid, but the user with email address " + email + " is no longer in the DB"); + return false; + } + AuthorizedUserRepository.instance.remove(authorizedUser.getName()); + AuthorizedUserRepository.instance.add(authorizedUser.getName(), password, email); + activeAuthTokens.remove(email); + return true; + } + @Override public boolean registerClient(String userName, String sessionId, MageVersion version) throws MageException { + // This method is deprecated, so just inform the server version. + logger.info("MageVersionException: userName=" + userName + ", version=" + version); + LogServiceImpl.instance.log(LogKeys.KEY_WRONG_VERSION, userName, version.toString(), Main.getVersion().toString(), sessionId); + throw new MageVersionException(version, Main.getVersion()); + } + + @Override + public boolean connectUser(String userName, String password, String sessionId, MageVersion version) throws MageException { try { if (version.compareTo(Main.getVersion()) != 0) { logger.info("MageVersionException: userName=" + userName + ", version=" + version); LogServiceImpl.instance.log(LogKeys.KEY_WRONG_VERSION, userName, version.toString(), Main.getVersion().toString(), sessionId); throw new MageVersionException(version, Main.getVersion()); } - return SessionManager.getInstance().registerUser(sessionId, userName); + return SessionManager.getInstance().connectUser(sessionId, userName, password); } catch (MageException ex) { if (ex instanceof MageVersionException) { throw (MageVersionException) ex; @@ -134,15 +217,15 @@ public class MageServerImpl implements MageServer { } @Override - public boolean registerAdmin(String password, String sessionId, MageVersion version) throws MageException { + public boolean connectAdmin(String adminPassword, String sessionId, MageVersion version) throws MageException { try { if (version.compareTo(Main.getVersion()) != 0) { throw new MageException("Wrong client version " + version + ", expecting version " + Main.getVersion()); } - if (!password.equals(this.password)) { + if (!adminPassword.equals(this.adminPassword)) { throw new MageException("Wrong password"); } - return SessionManager.getInstance().registerAdmin(sessionId); + return SessionManager.getInstance().connectAdmin(sessionId); } catch (Exception ex) { handleException(ex); } @@ -362,7 +445,7 @@ public class MageServerImpl implements MageServer { // } @Override public boolean startMatch(final String sessionId, final UUID roomId, final UUID tableId) throws MageException { - if (!TableManager.getInstance().getController(tableId).changeTableState(TableState.STARTING)) { + if (!TableManager.getInstance().getController(tableId).changeTableStateToStarting()) { return false; } execute("startMatch", sessionId, new Action() { @@ -387,7 +470,7 @@ public class MageServerImpl implements MageServer { // } @Override public boolean startTournament(final String sessionId, final UUID roomId, final UUID tableId) throws MageException { - if (!TableManager.getInstance().getController(tableId).changeTableState(TableState.STARTING)) { + if (!TableManager.getInstance().getController(tableId).changeTableStateToStarting()) { return false; } execute("startTournament", sessionId, new Action() { @@ -1032,6 +1115,15 @@ public class MageServerImpl implements MageServer { } } + private void sendErrorMessageToClient(final String sessionId, final String message) throws MageException { + execute("sendErrorMessageToClient", sessionId, new Action() { + @Override + public void execute() { + SessionManager.getInstance().sendErrorMessageToClient(sessionId, message); + } + }); + } + protected void execute(final String actionName, final String sessionId, final Action action, boolean checkAdminRights) throws MageException { if (checkAdminRights) { if (!SessionManager.getInstance().isAdmin(sessionId)) { diff --git a/Mage.Server/src/main/java/mage/server/MailClient.java b/Mage.Server/src/main/java/mage/server/MailClient.java new file mode 100644 index 00000000000..9c7ef614589 --- /dev/null +++ b/Mage.Server/src/main/java/mage/server/MailClient.java @@ -0,0 +1,53 @@ +package mage.server; + +import java.util.Properties; +import javax.mail.Message; +import javax.mail.MessagingException; +import javax.mail.Session; +import javax.mail.Transport; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; +import mage.server.util.ConfigSettings; +import org.apache.log4j.Logger; + +public class MailClient { + + private static final Logger logger = Logger.getLogger(Main.class); + + public static boolean sendMessage(String email, String subject, String text) { + if (email.length() == 0) { + logger.info("Email is not sent because the address is empty"); + return false; + } + ConfigSettings config = ConfigSettings.getInstance(); + + Properties properties = System.getProperties(); + properties.setProperty("mail.smtps.host", config.getMailSmtpHost()); + properties.setProperty("mail.smtps.port", config.getMailSmtpPort()); + properties.setProperty("mail.smtps.auth", "true"); + properties.setProperty("mail.user", config.getMailUser()); + properties.setProperty("mail.password", config.getMailPassword()); + + Session session = Session.getDefaultInstance(properties); + + try{ + MimeMessage message = new MimeMessage(session); + message.setFrom(new InternetAddress(config.getMailFromAddress())); + message.addRecipient(Message.RecipientType.TO, new InternetAddress(email)); + message.setSubject(subject); + message.setText(text); + + Transport trnsport; + trnsport = session.getTransport("smtps"); + trnsport.connect(null, properties.getProperty("mail.password")); + message.saveChanges(); + trnsport.sendMessage(message, message.getAllRecipients()); + trnsport.close(); + + return true; + }catch (MessagingException ex) { + logger.error("Error sending message to " + email, ex); + } + return false; + } +} diff --git a/Mage.Server/src/main/java/mage/server/MailgunClient.java b/Mage.Server/src/main/java/mage/server/MailgunClient.java new file mode 100644 index 00000000000..77ba777783a --- /dev/null +++ b/Mage.Server/src/main/java/mage/server/MailgunClient.java @@ -0,0 +1,37 @@ +package mage.server; + +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.WebResource; +import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter; +import com.sun.jersey.core.util.MultivaluedMapImpl; +import javax.ws.rs.core.MediaType; +import mage.server.util.ConfigSettings; +import org.apache.log4j.Logger; + +public class MailgunClient { + + private static final Logger logger = Logger.getLogger(Main.class); + + public static boolean sendMessage(String email, String subject, String text) { + if (email.length() == 0) { + logger.info("Email is not sent because the address is empty"); + return false; + } + Client client = Client.create(); + client.addFilter(new HTTPBasicAuthFilter("api", ConfigSettings.getInstance().getMailgunApiKey())); + String domain = ConfigSettings.getInstance().getMailgunDomain(); + WebResource webResource = client.resource("https://api.mailgun.net/v3/" + domain + "/messages"); + MultivaluedMapImpl formData = new MultivaluedMapImpl(); + formData.add("from", "XMage "); + formData.add("to", email); + formData.add("subject", subject); + formData.add("text", text); + ClientResponse response = webResource.type(MediaType.APPLICATION_FORM_URLENCODED).post(ClientResponse.class, formData); + boolean succeeded = response.getStatus() == 200; + if (!succeeded) { + logger.error("Error sending message to " + email + ". Status code: " + response.getStatus()); + } + return succeeded; + } +} diff --git a/Mage.Server/src/main/java/mage/server/Main.java b/Mage.Server/src/main/java/mage/server/Main.java index 7e83044274d..54c2a2b477c 100644 --- a/Mage.Server/src/main/java/mage/server/Main.java +++ b/Mage.Server/src/main/java/mage/server/Main.java @@ -1,33 +1,39 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.server; +import java.io.File; +import java.io.FilenameFilter; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.util.HashMap; +import java.util.Map; +import javax.management.MBeanServer; import mage.cards.repository.CardScanner; import mage.game.match.MatchType; import mage.game.tournament.TournamentType; @@ -37,6 +43,7 @@ import mage.server.draft.CubeFactory; import mage.server.game.DeckValidatorFactory; import mage.server.game.GameFactory; import mage.server.game.PlayerFactory; +import mage.server.record.UserStatsRepository; import mage.server.tournament.TournamentFactory; import mage.server.util.ConfigSettings; import mage.server.util.PluginClassLoader; @@ -46,26 +53,23 @@ import mage.server.util.config.GamePlugin; import mage.server.util.config.Plugin; import mage.utils.MageVersion; import org.apache.log4j.Logger; -import org.jboss.remoting.*; +import org.jboss.remoting.Client; +import org.jboss.remoting.ClientDisconnectedException; +import org.jboss.remoting.ConnectionListener; +import org.jboss.remoting.InvocationRequest; +import org.jboss.remoting.InvokerLocator; +import org.jboss.remoting.Remoting; +import org.jboss.remoting.ServerInvocationHandler; +import org.jboss.remoting.ServerInvoker; import org.jboss.remoting.callback.InvokerCallbackHandler; import org.jboss.remoting.callback.ServerInvokerCallbackHandler; import org.jboss.remoting.transport.Connector; +import org.jboss.remoting.transport.bisocket.BisocketServerInvoker; import org.jboss.remoting.transport.socket.SocketWrapper; import org.jboss.remoting.transporter.TransporterClient; import org.jboss.remoting.transporter.TransporterServer; import org.w3c.dom.Element; -import javax.management.MBeanServer; -import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; -import java.net.InetAddress; -import java.net.MalformedURLException; -import java.util.HashMap; -import java.util.Map; -import org.jboss.remoting.transport.bisocket.BisocketServerInvoker; - - /** * * @author BetaSteward_at_googlemail.com @@ -73,14 +77,13 @@ import org.jboss.remoting.transport.bisocket.BisocketServerInvoker; public class Main { private static final Logger logger = Logger.getLogger(Main.class); - private static final MageVersion version = new MageVersion(MageVersion.MAGE_VERSION_MAJOR, MageVersion.MAGE_VERSION_MINOR, MageVersion.MAGE_VERSION_PATCH, MageVersion.MAGE_VERSION_MINOR_PATCH, MageVersion.MAGE_VERSION_INFO); + private static final MageVersion version = new MageVersion(MageVersion.MAGE_VERSION_MAJOR, MageVersion.MAGE_VERSION_MINOR, MageVersion.MAGE_VERSION_PATCH, MageVersion.MAGE_VERSION_MINOR_PATCH, MageVersion.MAGE_VERSION_INFO); private static final String testModeArg = "-testMode="; private static final String fastDBModeArg = "-fastDbMode="; private static final String adminPasswordArg = "-adminPassword="; private static final String pluginFolder = "plugins"; - public static PluginClassLoader classLoader = new PluginClassLoader(); public static TransporterServer server; protected static boolean testMode; @@ -95,19 +98,17 @@ public class Main { logger.info("Logging level: " + logger.getEffectiveLevel()); String adminPassword = ""; - for (String arg: args) { + for (String arg : args) { if (arg.startsWith(testModeArg)) { testMode = Boolean.valueOf(arg.replace(testModeArg, "")); - } - else if (arg.startsWith(adminPasswordArg)) { + } else if (arg.startsWith(adminPasswordArg)) { adminPassword = arg.replace(adminPasswordArg, ""); adminPassword = SystemUtil.sanitize(adminPassword); - } - else if (arg.startsWith(fastDBModeArg)) { + } else if (arg.startsWith(fastDBModeArg)) { fastDbMode = Boolean.valueOf(arg.replace(fastDBModeArg, "")); } } - + logger.info("Loading cards..."); if (fastDbMode) { CardScanner.scanned = true; @@ -116,54 +117,68 @@ public class Main { } logger.info("Done."); + logger.info("Updating user stats DB..."); + UserStatsRepository.instance.updateUserStats(); + logger.info("Done."); + deleteSavedGames(); ConfigSettings config = ConfigSettings.getInstance(); - for (GamePlugin plugin: config.getGameTypes()) { + for (GamePlugin plugin : config.getGameTypes()) { GameFactory.getInstance().addGameType(plugin.getName(), loadGameType(plugin), loadPlugin(plugin)); } - for (GamePlugin plugin: config.getTournamentTypes()) { + for (GamePlugin plugin : config.getTournamentTypes()) { TournamentFactory.getInstance().addTournamentType(plugin.getName(), loadTournamentType(plugin), loadPlugin(plugin)); } - for (Plugin plugin: config.getPlayerTypes()) { + for (Plugin plugin : config.getPlayerTypes()) { PlayerFactory.getInstance().addPlayerType(plugin.getName(), loadPlugin(plugin)); } - for (Plugin plugin: config.getDraftCubes()) { + for (Plugin plugin : config.getDraftCubes()) { CubeFactory.getInstance().addDraftCube(plugin.getName(), loadPlugin(plugin)); } - for (Plugin plugin: config.getDeckTypes()) { + for (Plugin plugin : config.getDeckTypes()) { DeckValidatorFactory.getInstance().addDeckType(plugin.getName(), loadPlugin(plugin)); } logger.info("Config - max seconds idle: " + config.getMaxSecondsIdle()); logger.info("Config - max game threads: " + config.getMaxGameThreads()); logger.info("Config - max AI opponents: " + config.getMaxAiOpponents()); - logger.info("Config - min user name l.: " + config.getMinUserNameLength()); - logger.info("Config - max user name l.: " + config.getMaxUserNameLength()); - logger.info("Config - save game active: " + (config.isSaveGameActivated() ? "True":"false")); - + logger.info("Config - min usr name le.: " + config.getMinUserNameLength()); + logger.info("Config - max usr name le.: " + config.getMaxUserNameLength()); + logger.info("Config - min pswrd length: " + config.getMinPasswordLength()); + logger.info("Config - max pswrd length: " + config.getMaxPasswordLength()); + logger.info("Config - inv.usr name pat: " + config.getInvalidUserNamePattern()); + logger.info("Config - save game active: " + (config.isSaveGameActivated() ? "true" : "false")); logger.info("Config - backlog size : " + config.getBacklogSize()); logger.info("Config - lease period : " + config.getLeasePeriod()); logger.info("Config - max pool size : " + config.getMaxPoolSize()); logger.info("Config - num accp.threads: " + config.getNumAcceptThreads()); logger.info("Config - second.bind port: " + config.getSecondaryBindPort()); - + logger.info("Config - auth. activated : " + (config.isAuthenticationActivated() ? "true" : "false")); + logger.info("Config - mailgun api key : " + config.getMailgunApiKey()); + logger.info("Config - mailgun domain : " + config.getMailgunDomain()); + logger.info("Config - mail smtp Host : " + config.getMailSmtpHost()); + logger.info("Config - mail smtpPort : " + config.getMailSmtpPort()); + logger.info("Config - mail user : " + config.getMailUser()); + logger.info("Config - mail passw. len.: " + config.getMailPassword().length()); + logger.info("Config - mail from addre.: " + config.getMailFromAddress()); + logger.info("Config - google account : " + config.getGoogleAccount()); + Connection connection = new Connection("&maxPoolSize=" + config.getMaxPoolSize()); connection.setHost(config.getServerAddress()); connection.setPort(config.getPort()); try { // Parameter: serializationtype => jboss - InvokerLocator serverLocator = new InvokerLocator(connection.getURI()); + InvokerLocator serverLocator = new InvokerLocator(connection.getURI()); if (!isAlreadyRunning(serverLocator)) { server = new MageTransporterServer(serverLocator, new MageServerImpl(adminPassword, testMode), MageServer.class.getName(), new MageServerInvocationHandler()); server.start(); logger.info("Started MAGE server - listening on " + connection.toString()); - + if (testMode) { logger.info("MAGE server running in test mode"); } initStatistics(); - } - else { + } else { logger.fatal("Unable to start MAGE server - another server is already started"); } } catch (Exception ex) { @@ -192,6 +207,7 @@ public class Main { } static class ClientConnectionListener implements ConnectionListener { + @Override public void handleConnectionException(Throwable throwable, Client client) { Session session = SessionManager.getInstance().getSession(client.getSessionId()); @@ -207,12 +223,12 @@ public class Main { if (throwable instanceof ClientDisconnectedException) { // Seems like the random diconnects from public server land here and should not be handled as explicit disconnects // So it should be possible to reconnect to server and continue games if DisconnectReason is set to LostConnection - //SessionManager.getInstance().disconnect(client.getSessionId(), DisconnectReason.Disconnected); + //SessionManager.getInstance().disconnect(client.getSessionId(), DisconnectReason.Disconnected); SessionManager.getInstance().disconnect(client.getSessionId(), DisconnectReason.LostConnection); logger.info("CLIENT DISCONNECTED - " + sessionInfo); logger.debug("Stack Trace", throwable); - } else { - SessionManager.getInstance().disconnect(client.getSessionId(), DisconnectReason.LostConnection); + } else { + SessionManager.getInstance().disconnect(client.getSessionId(), DisconnectReason.LostConnection); logger.info("LOST CONNECTION - " + sessionInfo); if (logger.isDebugEnabled()) { if (throwable == null) { @@ -220,7 +236,7 @@ public class Main { } else { logger.debug(" - cause: " + Session.getBasicCause(throwable).toString()); } - } + } } } } @@ -253,13 +269,13 @@ public class Main { @Override public void setMBeanServer(MBeanServer server) { - + } @Override - public void setInvoker(ServerInvoker invoker) { + public void setInvoker(ServerInvoker invoker) { ((BisocketServerInvoker) invoker).setSecondaryBindPort(ConfigSettings.getInstance().getSecondaryBindPort()); - ((BisocketServerInvoker) invoker).setBacklog(ConfigSettings.getInstance().getBacklogSize()); + ((BisocketServerInvoker) invoker).setBacklog(ConfigSettings.getInstance().getBacklogSize()); ((BisocketServerInvoker) invoker).setNumAcceptThreads(ConfigSettings.getInstance().getNumAcceptThreads()); } @@ -330,7 +346,7 @@ public class Main { logger.debug("Loading tournament type: " + plugin.getClassName()); return (TournamentType) Class.forName(plugin.getTypeName(), true, classLoader).newInstance(); } catch (ClassNotFoundException ex) { - logger.warn("Tournament type not found:" + plugin.getName() + " / "+ plugin.getJar() + " - check plugin folder", ex); + logger.warn("Tournament type not found:" + plugin.getName() + " / " + plugin.getJar() + " - check plugin folder", ex); } catch (Exception ex) { logger.fatal("Error loading game type " + plugin.getJar(), ex); } @@ -343,15 +359,14 @@ public class Main { directory.mkdirs(); } File[] files = directory.listFiles( - new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.endsWith(".game"); + new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.endsWith(".game"); + } } - } ); - for (File file : files) - { + for (File file : files) { file.delete(); } } diff --git a/Mage.Server/src/main/java/mage/server/Session.java b/Mage.Server/src/main/java/mage/server/Session.java index 9a03b6e0e0f..602281c4e89 100644 --- a/Mage.Server/src/main/java/mage/server/Session.java +++ b/Mage.Server/src/main/java/mage/server/Session.java @@ -55,6 +55,8 @@ import org.jboss.remoting.callback.InvokerCallbackHandler; public class Session { private static final Logger logger = Logger.getLogger(Session.class); + private final static Pattern alphabetsPattern = Pattern.compile("[a-zA-Z]"); + private final static Pattern digitsPattern = Pattern.compile("[0-9]"); private final String sessionId; private UUID userId; @@ -74,8 +76,98 @@ public class Session { this.lock = new ReentrantLock(); } - public String registerUser(String userName) throws MageException { - String returnMessage = registerUserHandling(userName); + public String registerUser(String userName, String password, String email) throws MageException { + if (!ConfigSettings.getInstance().isAuthenticationActivated()) { + String returnMessage = "Registration is disabled by the server config"; + sendErrorMessageToClient(returnMessage); + return returnMessage; + } + synchronized (AuthorizedUserRepository.instance) { + String returnMessage = validateUserName(userName); + if (returnMessage != null) { + sendErrorMessageToClient(returnMessage); + return returnMessage; + } + returnMessage = validatePassword(password, userName); + if (returnMessage != null) { + sendErrorMessageToClient(returnMessage); + return returnMessage; + } + returnMessage = validateEmail(email); + if (returnMessage != null) { + sendErrorMessageToClient(returnMessage); + return returnMessage; + } + AuthorizedUserRepository.instance.add(userName, password, email); + String subject = "XMage Registration Completed"; + String text = "You are successfully registered as " + userName + "."; + boolean success; + if (!ConfigSettings.getInstance().getMailUser().isEmpty()) { + success = MailClient.sendMessage(email, subject, text); + } else { + success = MailgunClient.sendMessage(email, subject, text); + } + if (success) { + logger.info("Sent a registration confirmation email to " + email + " for " + userName); + } else { + logger.error("Failed sending a registration confirmation email to " + email + " for " + userName); + } + return null; + } + } + + static private String validateUserName(String userName) { + if (userName.equals("Admin")) { + return "User name Admin already in use"; + } + ConfigSettings config = ConfigSettings.getInstance(); + if (userName.length() < config.getMinUserNameLength()) { + return "User name may not be shorter than " + config.getMinUserNameLength() + " characters"; + } + if (userName.length() > config.getMaxUserNameLength()) { + return "User name may not be longer than " + config.getMaxUserNameLength() + " characters"; + } + Pattern invalidUserNamePattern = Pattern.compile(ConfigSettings.getInstance().getInvalidUserNamePattern(), Pattern.CASE_INSENSITIVE); + Matcher m = invalidUserNamePattern.matcher(userName); + if (m.find()) { + return "User name '" + userName + "' includes not allowed characters: use a-z, A-Z and 0-9"; + } + AuthorizedUser authorizedUser = AuthorizedUserRepository.instance.getByName(userName); + if (authorizedUser != null) { + return "User name '" + userName + "' already in use"; + } + return null; + } + + static private String validatePassword(String password, String userName) { + ConfigSettings config = ConfigSettings.getInstance(); + if (password.length() < config.getMinPasswordLength()) { + return "Password may not be shorter than " + config.getMinPasswordLength() + " characters"; + } + if (password.length() > config.getMaxPasswordLength()) { + return "Password may not be longer than " + config.getMaxPasswordLength() + " characters"; + } + if (password.equals(userName)) { + return "Password may not be the same as your username"; + } + Matcher alphabetsMatcher = alphabetsPattern.matcher(password); + Matcher digitsMatcher = digitsPattern.matcher(password); + if (!alphabetsMatcher.find() || !digitsMatcher.find()) { + return "Password has to include at least one alphabet (a-zA-Z) and also at least one digit (0-9)"; + } + return null; + } + + static private String validateEmail(String email) { + AuthorizedUser authorizedUser = AuthorizedUserRepository.instance.getByEmail(email); + if (authorizedUser != null) { + return "Email address '" + email + "' is associated with another user"; + } + return null; + } + + public String connectUser(String userName, String password) throws MageException { + String returnMessage = connectUserHandling(userName, password); if (returnMessage != null) { sendErrorMessageToClient(returnMessage); } @@ -86,27 +178,21 @@ public class Session { return lock.isLocked(); } - public String registerUserHandling(String userName) throws MageException { + public String connectUserHandling(String userName, String password) throws MageException { this.isAdmin = false; - if (userName.equals("Admin")) { - return "User name Admin already in use"; - } - if (userName.length() > ConfigSettings.getInstance().getMaxUserNameLength()) { - return "User name may not be longer than " + ConfigSettings.getInstance().getMaxUserNameLength() + " characters"; - } - if (userName.length() < ConfigSettings.getInstance().getMinUserNameLength()) { - return "User name may not be shorter than " + ConfigSettings.getInstance().getMinUserNameLength() + " characters"; - } - Pattern p = Pattern.compile(ConfigSettings.getInstance().getUserNamePattern(), Pattern.CASE_INSENSITIVE); - Matcher m = p.matcher(userName); - if (m.find()) { - return "User name '" + userName + "' includes not allowed characters: use a-z, A-Z and 0-9"; + if (ConfigSettings.getInstance().isAuthenticationActivated()) { + AuthorizedUser authorizedUser = AuthorizedUserRepository.instance.getByName(userName); + if (authorizedUser == null || !authorizedUser.doCredentialsMatch(userName, password)) { + return "Wrong username or password. In case you haven't, please register your account first."; + } } + User user = UserManager.getInstance().createUser(userName, host); boolean reconnect = false; if (user == null) { // user already exists - user = UserManager.getInstance().findUser(userName); - if (user.getHost().equals(host)) { + user = UserManager.getInstance().getUserByName(userName); + // If authentication is not activated, check the identity using IP address. + if (ConfigSettings.getInstance().isAuthenticationActivated() || user.getHost().equals(host)) { user.updateLastActivity(null); // minimizes possible expiration this.userId = user.getId(); if (user.getSessionId().isEmpty()) { @@ -135,11 +221,11 @@ public class Session { return null; } - public void registerAdmin() { + public void connectAdmin() { this.isAdmin = true; User user = UserManager.getInstance().createUser("Admin", host); if (user == null) { - user = UserManager.getInstance().findUser("Admin"); + user = UserManager.getInstance().getUserByName("Admin"); } UserData adminUserData = UserData.getDefaultUserDataView(); adminUserData.setGroupId(UserGroup.ADMIN.getGroupId()); @@ -151,7 +237,7 @@ public class Session { } public boolean setUserData(String userName, UserData userData) { - User user = UserManager.getInstance().findUser(userName); + User user = UserManager.getInstance().getUserByName(userName); if (user != null) { if (user.getUserData() == null || user.getUserData().getGroupId() == UserGroup.DEFAULT.getGroupId()) { user.setUserData(userData); @@ -279,7 +365,7 @@ public class Session { this.host = hostAddress; } - void sendErrorMessageToClient(String message) { + public void sendErrorMessageToClient(String message) { List messageData = new LinkedList<>(); messageData.add("Error while connecting to server"); messageData.add(message); diff --git a/Mage.Server/src/main/java/mage/server/SessionManager.java b/Mage.Server/src/main/java/mage/server/SessionManager.java index d7a6db388e2..f52a138a4eb 100644 --- a/Mage.Server/src/main/java/mage/server/SessionManager.java +++ b/Mage.Server/src/main/java/mage/server/SessionManager.java @@ -70,31 +70,51 @@ public class SessionManager { sessions.put(sessionId, session); } - public boolean registerUser(String sessionId, String userName) throws MageException { + public boolean registerUser(String sessionId, String userName, String password, String email) throws MageException { + Session session = sessions.get(sessionId); + if (session == null) { + logger.error(userName + " tried to register with no sessionId"); + return false; + } + String returnMessage = session.registerUser(userName, password, email); + if (returnMessage != null) { + logger.debug(userName + " not registered: " + returnMessage); + return false; + } + LogServiceImpl.instance.log(LogKeys.KEY_USER_REGISTERED, userName, session.getHost(), sessionId); + + logger.info(userName + " registered"); + logger.debug("- userId: " + session.getUserId()); + logger.debug("- sessionId: " + sessionId); + logger.debug("- host: " + session.getHost()); + return true; + } + + public boolean connectUser(String sessionId, String userName, String password) throws MageException { Session session = sessions.get(sessionId); if (session != null) { - String returnMessage = session.registerUser(userName); + String returnMessage = session.connectUser(userName, password); if (returnMessage == null) { LogServiceImpl.instance.log(LogKeys.KEY_USER_CONNECTED, userName, session.getHost(), sessionId); - logger.info(userName + " joined server"); + logger.info(userName + " connected to server"); logger.debug("- userId: " + session.getUserId()); logger.debug("- sessionId: " + sessionId); logger.debug("- host: " + session.getHost()); return true; } else { - logger.debug(userName + " not registered: " + returnMessage); + logger.debug(userName + " not connected: " + returnMessage); } } else { - logger.error(userName + " tried to join with no sessionId"); + logger.error(userName + " tried to connect with no sessionId"); } return false; } - public boolean registerAdmin(String sessionId) { + public boolean connectAdmin(String sessionId) { Session session = sessions.get(sessionId); if (session != null) { - session.registerAdmin(); + session.connectAdmin(); LogServiceImpl.instance.log(LogKeys.KEY_ADMIN_CONNECTED, "Admin", session.getHost(), sessionId); logger.info("Admin connected from " + session.getHost()); return true; @@ -217,4 +237,13 @@ public class SessionManager { } return false; } + + public void sendErrorMessageToClient(String sessionId, String message) { + Session session = sessions.get(sessionId); + if (session == null) { + logger.error("Following error message is not delivered because session " + sessionId + " is not found: " + message); + return; + } + session.sendErrorMessageToClient(message); + } } diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java index ecc05278221..64edc644b12 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -62,6 +62,7 @@ import mage.server.game.DeckValidatorFactory; import mage.server.game.GameFactory; import mage.server.game.GameManager; import mage.server.game.PlayerFactory; +import mage.server.record.TableRecorderImpl; import mage.server.services.LogKeys; import mage.server.services.impl.LogServiceImpl; import mage.server.tournament.TournamentController; @@ -105,7 +106,7 @@ public class TableController { } else { controllerName = "System"; } - table = new Table(roomId, options.getGameType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getDeckType()), options.getPlayerTypes(), match); + table = new Table(roomId, options.getGameType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getDeckType()), options.getPlayerTypes(), TableRecorderImpl.getInstance(), match); chatId = ChatManager.getInstance().createChatSession("Match Table " + table.getId()); init(); } @@ -124,7 +125,7 @@ public class TableController { } else { controllerName = "System"; } - table = new Table(roomId, options.getTournamentType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getMatchOptions().getDeckType()), options.getPlayerTypes(), tournament); + table = new Table(roomId, options.getTournamentType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getMatchOptions().getDeckType()), options.getPlayerTypes(), TableRecorderImpl.getInstance(), tournament); chatId = ChatManager.getInstance().createChatSession("Tourn. table " + table.getId()); } @@ -237,6 +238,7 @@ public class TableController { TournamentPlayer newTournamentPlayer = tournament.getPlayer(newPlayer.getId()); newTournamentPlayer.setState(oldTournamentPlayer.getState()); + newTournamentPlayer.setReplacedTournamentPlayer(oldTournamentPlayer); DraftManager.getInstance().getController(table.getId()).replacePlayer(oldPlayer, newPlayer); return true; @@ -957,26 +959,16 @@ public class TableController { return getTable().getState(); } - public synchronized boolean changeTableState(TableState newTableState) { - switch (newTableState) { - case WAITING: - if (getTable().getState().equals(TableState.STARTING)) { - // tournament already started - return false; - } - break; - case STARTING: - if (!getTable().getState().equals(TableState.READY_TO_START)) { - // tournament is not ready, can't start - return false; - } - if (!table.allSeatsAreOccupied()) { - logger.debug("Not alle Seats are occupied: stop start tableId:" + table.getId()); - return false; - } - break; + public synchronized boolean changeTableStateToStarting() { + if (!getTable().getState().equals(TableState.READY_TO_START)) { + // tournament is not ready, can't start + return false; } - getTable().setState(newTableState); + if (!table.allSeatsAreOccupied()) { + logger.debug("Not alle Seats are occupied: stop start tableId:" + table.getId()); + return false; + } + getTable().setState(TableState.STARTING); return true; } } diff --git a/Mage.Server/src/main/java/mage/server/User.java b/Mage.Server/src/main/java/mage/server/User.java index 761a647495b..b6dad40c541 100644 --- a/Mage.Server/src/main/java/mage/server/User.java +++ b/Mage.Server/src/main/java/mage/server/User.java @@ -40,12 +40,15 @@ import java.util.concurrent.TimeUnit; import mage.cards.decks.Deck; import mage.constants.ManaType; import mage.game.Table; +import mage.game.result.ResultProtos; import mage.game.tournament.TournamentPlayer; import mage.interfaces.callback.ClientCallback; import mage.players.net.UserData; import mage.server.draft.DraftSession; import mage.server.game.GameManager; import mage.server.game.GameSessionPlayer; +import mage.server.record.UserStats; +import mage.server.record.UserStatsRepository; import mage.server.tournament.TournamentController; import mage.server.tournament.TournamentManager; import mage.server.tournament.TournamentSession; @@ -59,7 +62,7 @@ import org.apache.log4j.Logger; */ public class User { - private static final Logger logger = Logger.getLogger(User.class); + private static final Logger LOGGER = Logger.getLogger(User.class); public enum UserState { @@ -79,11 +82,11 @@ public class User { private final Map sideboarding; private final List watchedGames; private String sessionId; - private String info = ""; private String pingInfo = ""; private Date lastActivity; private UserState userState; private UserData userData; + private UserStats userStats; public User(String userName, String host) { this.userId = UUID.randomUUID(); @@ -103,6 +106,7 @@ public class User { this.watchedGames = new ArrayList<>(); this.tablesToDelete = new ArrayList<>(); this.sessionId = ""; + this.userStats = null; } public String getName() { @@ -126,15 +130,15 @@ public class User { if (sessionId.isEmpty()) { userState = UserState.Disconnected; lostConnection(); - logger.trace("USER - lost connection: " + userName + " id: " + userId); + LOGGER.trace("USER - lost connection: " + userName + " id: " + userId); } else if (userState == UserState.Created) { userState = UserState.Connected; - logger.trace("USER - created: " + userName + " id: " + userId); + LOGGER.trace("USER - created: " + userName + " id: " + userId); } else { userState = UserState.Reconnected; reconnect(); - logger.trace("USER - reconnected: " + userName + " id: " + userId); + LOGGER.trace("USER - reconnected: " + userName + " id: " + userId); } } @@ -270,12 +274,13 @@ public class User { public boolean isExpired(Date expired) { if (lastActivity.before(expired)) { - logger.trace(userName + " is expired!"); + LOGGER.trace(userName + " is expired!"); userState = UserState.Expired; return true; } - logger.trace(new StringBuilder("isExpired: User ").append(userName).append(" lastActivity: ").append(lastActivity).append(" expired: ").append(expired).toString()); - return false; /*userState == UserState.Disconnected && */ + LOGGER.trace(new StringBuilder("isExpired: User ").append(userName).append(" lastActivity: ").append(lastActivity).append(" expired: ").append(expired).toString()); + return false; + /*userState == UserState.Disconnected && */ } @@ -357,35 +362,35 @@ public class User { } public void remove(DisconnectReason reason) { - logger.trace("REMOVE " + getName() + " Draft sessions " + draftSessions.size()); + LOGGER.trace("REMOVE " + getName() + " Draft sessions " + draftSessions.size()); for (DraftSession draftSession : draftSessions.values()) { draftSession.setKilled(); } draftSessions.clear(); - logger.trace("REMOVE " + getName() + " Tournament sessions " + userTournaments.size()); + LOGGER.trace("REMOVE " + getName() + " Tournament sessions " + userTournaments.size()); for (UUID tournamentId : userTournaments.values()) { TournamentManager.getInstance().quit(tournamentId, getId()); } userTournaments.clear(); - logger.trace("REMOVE " + getName() + " Tables " + tables.size()); + LOGGER.trace("REMOVE " + getName() + " Tables " + tables.size()); for (Entry entry : tables.entrySet()) { - logger.debug("-- leave tableId: " + entry.getValue().getId()); + LOGGER.debug("-- leave tableId: " + entry.getValue().getId()); TableManager.getInstance().leaveTable(userId, entry.getValue().getId()); } tables.clear(); - logger.trace("REMOVE " + getName() + " Game sessions: " + gameSessions.size()); + LOGGER.trace("REMOVE " + getName() + " Game sessions: " + gameSessions.size()); for (GameSessionPlayer gameSessionPlayer : gameSessions.values()) { - logger.debug("-- kill game session of gameId: " + gameSessionPlayer.getGameId()); + LOGGER.debug("-- kill game session of gameId: " + gameSessionPlayer.getGameId()); GameManager.getInstance().quitMatch(gameSessionPlayer.getGameId(), userId); gameSessionPlayer.quitGame(); } gameSessions.clear(); - logger.trace("REMOVE " + getName() + " watched Games " + watchedGames.size()); + LOGGER.trace("REMOVE " + getName() + " watched Games " + watchedGames.size()); for (UUID gameId : watchedGames) { GameManager.getInstance().stopWatching(gameId, userId); } watchedGames.clear(); - logger.trace("REMOVE " + getName() + " Chats "); + LOGGER.trace("REMOVE " + getName() + " Chats "); ChatManager.getInstance().removeUser(userId, reason); } @@ -394,6 +399,12 @@ public class User { this.userData.update(userData); } else { this.userData = userData; + this.userStats = UserStatsRepository.instance.getUser(this.userName); + if (userStats != null) { + this.userData.setHistory(userStatsToString(userStats.getProto())); + } else { + this.userData.setHistory(""); + } } } @@ -443,11 +454,11 @@ public class User { } } else { // can happen if tournamet has just ended - logger.debug(getName() + " tournament player missing - tableId:" + table.getId(), null); + LOGGER.debug(getName() + " tournament player missing - tableId:" + table.getId(), null); tablesToDelete.add(tableEntry.getKey()); } } else { - logger.error(getName() + " tournament key missing - tableId: " + table.getId(), null); + LOGGER.error(getName() + " tournament key missing - tableId: " + table.getId(), null); } } else { switch (table.getState()) { @@ -497,14 +508,6 @@ public class User { return sb.toString(); } - public String getInfo() { - return info; - } - - public void setInfo(String Info) { - this.info = Info; - } - public void addGameWatchInfo(UUID gameId) { watchedGames.add(gameId); } @@ -525,4 +528,96 @@ public class User { } } + // getUserStats returns the UserStats for this user. This caches the result, so if the stats is + // updated call resetUserStats to refresh it. + public UserStats getUserStats() { + if (this.userStats == null) { + resetUserStats(); + } + return this.userStats; + } + + // resetUserStats loads UserStats from DB. + public void resetUserStats() { + this.userStats = UserStatsRepository.instance.getUser(this.userName); + if (userData != null) { + userData.setHistory(userStatsToString(userStats.getProto())); + } + } + + public String getHistory() { + if (userData != null) { + return userData.getHistory(); + } + return ""; + } + + public static String userStatsToString(ResultProtos.UserStatsProto proto) { + List builders = new ArrayList<>(); + if (proto.getMatches() > 0) { + StringBuilder builder = new StringBuilder(); + builder.append("Matches:"); + builder.append(proto.getMatches()); + List quit = new ArrayList<>(); + if (proto.getMatchesIdleTimeout() > 0) { + quit.add("I:" + Integer.toString(proto.getMatchesIdleTimeout())); + } + if (proto.getMatchesTimerTimeout() > 0) { + quit.add("T:" + Integer.toString(proto.getMatchesTimerTimeout())); + } + if (proto.getMatchesQuit() > 0) { + quit.add("Q:" + Integer.toString(proto.getMatchesQuit())); + } + if (quit.size() > 0) { + builder.append(" ("); + joinStrings(builder, quit, " "); + builder.append(")"); + } + builders.add(builder); + } + if (proto.getTourneys() > 0) { + StringBuilder builder = new StringBuilder(); + builder.append("Tourneys:"); + builder.append(proto.getTourneys()); + List quit = new ArrayList<>(); + if (proto.getTourneysQuitDuringDrafting() > 0) { + quit.add("D:" + Integer.toString(proto.getTourneysQuitDuringDrafting())); + } + if (proto.getTourneysQuitDuringConstruction() > 0) { + quit.add("C:" + Integer.toString(proto.getTourneysQuitDuringConstruction())); + } + if (proto.getTourneysQuitDuringRound() > 0) { + quit.add("R:" + Integer.toString(proto.getTourneysQuitDuringRound())); + } + if (quit.size() > 0) { + builder.append(" ("); + joinStrings(builder, quit, " "); + builder.append(")"); + } + builders.add(builder); + } + return joinBuilders(builders); + } + + private static String joinBuilders(List builders) { + if (builders.isEmpty()) { + return null; + } + StringBuilder builder = builders.get(0); + for (int i = 1; i < builders.size(); ++i) { + builder.append(" "); + builder.append(builders.get(i)); + } + return builder.toString(); + } + + private static void joinStrings(StringBuilder joined, List strings, String separator) { + for (int i = 0; i < strings.size(); ++i) { + if (i > 0) { + joined.append(separator); + } + joined.append(strings.get(i)); + } + } + } diff --git a/Mage.Server/src/main/java/mage/server/UserManager.java b/Mage.Server/src/main/java/mage/server/UserManager.java index f1d2e1e32b1..7b1b875869d 100644 --- a/Mage.Server/src/main/java/mage/server/UserManager.java +++ b/Mage.Server/src/main/java/mage/server/UserManager.java @@ -1,16 +1,16 @@ /* * Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,7 +20,7 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. @@ -38,6 +38,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import mage.server.User.UserState; +import mage.server.record.UserStats; +import mage.server.record.UserStatsRepository; import mage.server.util.ThreadExecutor; import org.apache.log4j.Logger; @@ -45,7 +47,7 @@ import org.apache.log4j.Logger; * * manages users - if a user is disconnected and 10 minutes have passed with no * activity the user is removed - * + * * @author BetaSteward_at_googlemail.com */ public class UserManager { @@ -55,7 +57,8 @@ public class UserManager { private static final Logger logger = Logger.getLogger(UserManager.class); private final ConcurrentHashMap users = new ConcurrentHashMap<>(); - + private final ConcurrentHashMap usersByName = new ConcurrentHashMap<>(); + private static final ExecutorService callExecutor = ThreadExecutor.getInstance().getCallExecutor(); private static final UserManager INSTANCE = new UserManager(); @@ -63,8 +66,8 @@ public class UserManager { public static UserManager getInstance() { return INSTANCE; } - - private UserManager() { + + private UserManager() { expireExecutor.scheduleAtFixedRate(new Runnable() { @Override public void run() { @@ -74,11 +77,12 @@ public class UserManager { } public User createUser(String userName, String host) { - if (findUser(userName) != null) { + if (getUserByName(userName) != null) { return null; //user already exists } User user = new User(userName, host); users.put(user.getId(), user); + usersByName.put(userName, user); return user; } @@ -89,13 +93,8 @@ public class UserManager { return null; } - public User findUser(String userName) { - for (User user: users.values()) { - if (user.getName().equals(userName)) { - return user; - } - } - return null; + public User getUserByName(String userName) { + return usersByName.get(userName); } public Collection getUsers() { @@ -116,7 +115,7 @@ public class UserManager { public void disconnect(UUID userId, DisconnectReason reason) { if (userId != null) { User user = users.get(userId); - if (user != null) { + if (user != null) { user.setSessionId(""); // Session will be set again with new id if user reconnects } ChatManager.getInstance().removeUser(userId, reason); @@ -126,43 +125,44 @@ public class UserManager { public boolean isAdmin(UUID userId) { if (userId != null) { User user = users.get(userId); - if (user != null) { + if (user != null) { return user.getName().equals("Admin"); } } return false; } - public void removeUser(final UUID userId, final DisconnectReason reason) { + public void removeUser(final UUID userId, final DisconnectReason reason) { if (userId != null) { final User user = users.get(userId); if (user != null) { callExecutor.execute( - new Runnable() { - @Override - public void run() { - try { - logger.info("USER REMOVE - " + user.getName() + " (" + reason.toString() + ") userId: " + userId); - user.remove(reason); - logger.debug("USER REMOVE END - " + user.getName()); - } catch (Exception ex) { - handleException(ex); - } finally { - users.remove(userId); - } + new Runnable() { + @Override + public void run() { + try { + logger.info("USER REMOVE - " + user.getName() + " (" + reason.toString() + ") userId: " + userId); + user.remove(reason); + logger.debug("USER REMOVE END - " + user.getName()); + } catch (Exception ex) { + handleException(ex); + } finally { + users.remove(userId); + usersByName.remove(user.getName()); } } + } ); } else { logger.warn("Trying to remove userId: " + userId + " - but it does not exist."); } - } + } } public boolean extendUserSession(UUID userId, String pingInfo) { if (userId != null) { User user = users.get(userId); - if (user != null) { + if (user != null) { user.updateLastActivity(pingInfo); return true; } @@ -171,7 +171,8 @@ public class UserManager { } /** - * Is the connection lost for more than 3 minutes, the user will be removed (within 3 minutes the user can reconnect) + * Is the connection lost for more than 3 minutes, the user will be removed + * (within 3 minutes the user can reconnect) */ private void checkExpired() { Calendar calendar = Calendar.getInstance(); @@ -187,13 +188,39 @@ public class UserManager { public void handleException(Exception ex) { if (ex != null) { - logger.fatal("User manager exception " + (ex.getMessage() == null ? "null":ex.getMessage())); + logger.fatal("User manager exception " + (ex.getMessage() == null ? "null" : ex.getMessage())); if (ex.getCause() != null) { - logger.debug("- Cause: " + (ex.getCause().getMessage() == null ? "null":ex.getCause().getMessage())); + logger.debug("- Cause: " + (ex.getCause().getMessage() == null ? "null" : ex.getCause().getMessage())); } ex.printStackTrace(); - }else { + } else { logger.fatal("User manager exception - null"); } } + + public String getUserHistory(String userName) { + User user = getUserByName(userName); + if (user == null) { + UserStats userStats = UserStatsRepository.instance.getUser(userName); + if (userStats == null) { + return "User " + userName + " not found"; + } + return User.userStatsToString(userStats.getProto()); + } + return "History of user " + userName + ": " + user.getUserData().getHistory(); + } + + public void updateUserHistory() { + callExecutor.execute(new Runnable() { + @Override + public void run() { + for (String updatedUser : UserStatsRepository.instance.updateUserStats()) { + User user = getUserByName(updatedUser); + if (user != null) { + user.resetUserStats(); + } + } + } + }); + } } diff --git a/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java b/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java index 9afcea78466..30b005e19c2 100644 --- a/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java +++ b/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java @@ -100,11 +100,7 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable { if (table.getState() != TableState.FINISHED) { tableList.add(new TableView(table)); } else if (matchList.size() < 50) { - if (table.isTournament()) { - matchList.add(new MatchView(table)); - } else { - matchList.add(new MatchView(table)); - } + matchList.add(new MatchView(table)); } else { // more since 50 matches finished since this match so remove it if (table.isTournament()) { @@ -118,13 +114,13 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable { List users = new ArrayList<>(); for (User user : UserManager.getInstance().getUsers()) { try { - users.add(new UsersView(user.getUserData().getFlagName(), user.getName(), user.getInfo(), user.getGameInfo(), user.getPingInfo())); + users.add(new UsersView(user.getUserData().getFlagName(), user.getName(), user.getHistory(), user.getGameInfo(), user.getPingInfo())); } catch (Exception ex) { logger.fatal("User update exception: " + user.getName() + " - " + ex.toString(), ex); users.add(new UsersView( (user.getUserData() != null && user.getUserData().getFlagName() != null) ? user.getUserData().getFlagName() : "world", user.getName() != null ? user.getName() : "", - user.getInfo() != null ? user.getInfo() : "", + user.getHistory() != null ? user.getHistory() : "", "[exception]", user.getPingInfo() != null ? user.getPingInfo() : "")); } diff --git a/Mage.Server/src/main/java/mage/server/record/TableRecord.java b/Mage.Server/src/main/java/mage/server/record/TableRecord.java new file mode 100644 index 00000000000..456e54c8031 --- /dev/null +++ b/Mage.Server/src/main/java/mage/server/record/TableRecord.java @@ -0,0 +1,37 @@ +package mage.server.record; + +import com.j256.ormlite.field.DataType; +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; +import mage.game.result.ResultProtos.TableProto; +import org.mage.mage.shaded.protobuf.InvalidProtocolBufferException; +import org.apache.log4j.Logger; + +@DatabaseTable(tableName = "table_history") +public class TableRecord { + + private static final Logger logger = Logger.getLogger(TableRecord.class); + + @DatabaseField(dataType = DataType.BYTE_ARRAY, indexName = "proto_index", unique = true) + protected byte[] proto; + + @DatabaseField(indexName = "end_time_ms") + protected long endTimeMs; + + public TableRecord() { + } + + public TableRecord(TableProto proto, long endTimeMs) { + this.proto = proto.toByteArray(); + this.endTimeMs = endTimeMs; + } + + public TableProto getProto() { + try { + return TableProto.parseFrom(this.proto); + } catch (InvalidProtocolBufferException ex) { + logger.error("Failed to parse serialized proto", ex); + } + return null; + } +} diff --git a/Mage.Server/src/main/java/mage/server/record/TableRecordRepository.java b/Mage.Server/src/main/java/mage/server/record/TableRecordRepository.java new file mode 100644 index 00000000000..927a474c397 --- /dev/null +++ b/Mage.Server/src/main/java/mage/server/record/TableRecordRepository.java @@ -0,0 +1,77 @@ +package mage.server.record; + +import com.j256.ormlite.dao.Dao; +import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.jdbc.JdbcConnectionSource; +import com.j256.ormlite.stmt.QueryBuilder; +import com.j256.ormlite.support.ConnectionSource; +import com.j256.ormlite.support.DatabaseConnection; +import com.j256.ormlite.table.TableUtils; +import java.io.File; +import java.sql.SQLException; +import java.util.List; +import mage.cards.repository.RepositoryUtil; +import org.apache.log4j.Logger; + +public enum TableRecordRepository { + + instance; + + private static final String JDBC_URL = "jdbc:sqlite:./db/table_record.db"; + private static final String VERSION_ENTITY_NAME = "table_record"; + // raise this if db structure was changed + private static final long DB_VERSION = 0; + + private Dao dao; + + private TableRecordRepository() { + File file = new File("db"); + if (!file.exists()) { + file.mkdirs(); + } + try { + ConnectionSource connectionSource = new JdbcConnectionSource(JDBC_URL); + boolean obsolete = RepositoryUtil.isDatabaseObsolete(connectionSource, VERSION_ENTITY_NAME, DB_VERSION); + + if (obsolete) { + TableUtils.dropTable(connectionSource, TableRecord.class, true); + } + + TableUtils.createTableIfNotExists(connectionSource, TableRecord.class); + dao = DaoManager.createDao(connectionSource, TableRecord.class); + } catch (SQLException ex) { + Logger.getLogger(TableRecordRepository.class).error("Error creating table_record repository - ", ex); + } + } + + public void add(TableRecord tableHistory) { + try { + dao.create(tableHistory); + } catch (SQLException ex) { + Logger.getLogger(TableRecordRepository.class).error("Error adding a table_record to DB - ", ex); + } + } + + public List getAfter(long endTimeMs) { + try { + QueryBuilder qb = dao.queryBuilder(); + qb.where().gt("endTimeMs", endTimeMs); + qb.orderBy("endTimeMs", true); + return dao.query(qb.prepare()); + } catch (SQLException ex) { + Logger.getLogger(TableRecordRepository.class).error("Error getting table_records from DB - ", ex); + } + return null; + } + + public void closeDB() { + try { + if (dao != null && dao.getConnectionSource() != null) { + DatabaseConnection conn = dao.getConnectionSource().getReadWriteConnection(); + conn.executeStatement("shutdown compact", 0); + } + } catch (SQLException ex) { + Logger.getLogger(TableRecordRepository.class).error("Error closing table_record repository - ", ex); + } + } +} diff --git a/Mage.Server/src/main/java/mage/server/record/TableRecorderImpl.java b/Mage.Server/src/main/java/mage/server/record/TableRecorderImpl.java new file mode 100644 index 00000000000..2bafdff9c1c --- /dev/null +++ b/Mage.Server/src/main/java/mage/server/record/TableRecorderImpl.java @@ -0,0 +1,23 @@ +package mage.server.record; + +import mage.game.Table; +import mage.game.Table.TableRecorder; +import mage.game.result.ResultProtos.TableProto; +import mage.server.UserManager; +import org.apache.log4j.Logger; + +public class TableRecorderImpl implements TableRecorder { + + private static TableRecorderImpl INSTANCE = new TableRecorderImpl(); + private static final Logger logger = Logger.getLogger(TableRecorderImpl.class); + + public static TableRecorderImpl getInstance() { + return INSTANCE; + } + + public void record(Table table) { + TableProto proto = table.toProto(); + TableRecordRepository.instance.add(new TableRecord(proto, proto.getEndTimeMs())); + UserManager.getInstance().updateUserHistory(); + } +} diff --git a/Mage.Server/src/main/java/mage/server/record/UserStats.java b/Mage.Server/src/main/java/mage/server/record/UserStats.java new file mode 100644 index 00000000000..94adcecc554 --- /dev/null +++ b/Mage.Server/src/main/java/mage/server/record/UserStats.java @@ -0,0 +1,45 @@ +package mage.server.record; + +import com.j256.ormlite.field.DataType; +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; +import mage.game.result.ResultProtos.UserStatsProto; +import org.mage.mage.shaded.protobuf.InvalidProtocolBufferException; +import org.apache.log4j.Logger; + +@DatabaseTable(tableName = "user_stats") +public class UserStats { + + private static final Logger logger = Logger.getLogger(TableRecord.class); + + @DatabaseField(indexName = "user_name_index", unique = true, id = true) + protected String userName; + + @DatabaseField(dataType = DataType.BYTE_ARRAY) + protected byte[] proto; + + @DatabaseField(indexName = "end_time_ms_index") + protected long endTimeMs; + + public UserStats() { + } + + public UserStats(UserStatsProto proto, long endTimeMs) { + this.userName = proto.getName(); + this.proto = proto.toByteArray(); + this.endTimeMs = endTimeMs; + } + + public UserStatsProto getProto() { + try { + return UserStatsProto.parseFrom(this.proto); + } catch (InvalidProtocolBufferException ex) { + logger.error("Failed to parse serialized proto", ex); + } + return null; + } + + public long getEndTimeMs() { + return this.endTimeMs; + } +} diff --git a/Mage.Server/src/main/java/mage/server/record/UserStatsRepository.java b/Mage.Server/src/main/java/mage/server/record/UserStatsRepository.java new file mode 100644 index 00000000000..26348de66a3 --- /dev/null +++ b/Mage.Server/src/main/java/mage/server/record/UserStatsRepository.java @@ -0,0 +1,187 @@ +package mage.server.record; + +import com.j256.ormlite.dao.Dao; +import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.jdbc.JdbcConnectionSource; +import com.j256.ormlite.stmt.QueryBuilder; +import com.j256.ormlite.support.ConnectionSource; +import com.j256.ormlite.support.DatabaseConnection; +import com.j256.ormlite.table.TableUtils; +import java.io.File; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import mage.cards.repository.RepositoryUtil; +import mage.game.result.ResultProtos; +import org.apache.log4j.Logger; + +public enum UserStatsRepository { + + instance; + + private static final String JDBC_URL = "jdbc:sqlite:./db/user_stats.db"; + private static final String VERSION_ENTITY_NAME = "user_stats"; + // raise this if db structure was changed + private static final long DB_VERSION = 0; + + private Dao dao; + + private UserStatsRepository() { + File file = new File("db"); + if (!file.exists()) { + file.mkdirs(); + } + try { + ConnectionSource connectionSource = new JdbcConnectionSource(JDBC_URL); + boolean obsolete = RepositoryUtil.isDatabaseObsolete(connectionSource, VERSION_ENTITY_NAME, DB_VERSION); + + if (obsolete) { + TableUtils.dropTable(connectionSource, UserStats.class, true); + } + + TableUtils.createTableIfNotExists(connectionSource, UserStats.class); + dao = DaoManager.createDao(connectionSource, UserStats.class); + } catch (SQLException ex) { + Logger.getLogger(UserStatsRepository.class).error("Error creating user_stats repository - ", ex); + } + } + + public void add(UserStats userStats) { + try { + dao.create(userStats); + } catch (SQLException ex) { + Logger.getLogger(UserStatsRepository.class).error("Error adding a user_stats to DB - ", ex); + } + } + + public void update(UserStats userStats) { + try { + dao.update(userStats); + } catch (SQLException ex) { + Logger.getLogger(UserStatsRepository.class).error("Error updating a user_stats in DB - ", ex); + } + } + + public UserStats getUser(String userName) { + try { + QueryBuilder qb = dao.queryBuilder(); + qb.where().eq("userName", userName); + List users = dao.query(qb.prepare()); + if (users.size() == 1) { + return users.get(0); + } + } catch (SQLException ex) { + Logger.getLogger(UserStatsRepository.class).error("Error getting a user from DB - ", ex); + } + return null; + } + + public List getAllUsers() { + try { + QueryBuilder qb = dao.queryBuilder(); + return dao.query(qb.prepare()); + } catch (SQLException ex) { + Logger.getLogger(UserStatsRepository.class).error("Error getting all users from DB - ", ex); + } + return null; + } + + public long getLatestEndTimeMs() { + try { + QueryBuilder qb = dao.queryBuilder(); + qb.orderBy("endTimeMs", false).limit(1); + List users = dao.query(qb.prepare()); + if (users.size() == 1) { + return users.get(0).getEndTimeMs(); + } + } catch (SQLException ex) { + Logger.getLogger(UserStatsRepository.class).error("Error getting the latest end time from DB - ", ex); + } + return 0; + } + + // updateUserStats reads tables finished after the last DB update and reflects it to the DB. + // It returns the list of user names that are upated. + public List updateUserStats() { + HashSet updatedUsers = new HashSet(); + // Lock the DB so that no other updateUserStats runs at the same time. + synchronized(this) { + long latestEndTimeMs = this.getLatestEndTimeMs(); + List records = TableRecordRepository.instance.getAfter(latestEndTimeMs); + for (TableRecord record : records) { + ResultProtos.TableProto table = record.getProto(); + if (table.getControllerName().equals("System")) { + // This is a sub table within a tournament, so it's already handled by the main + // tournament table. + continue; + } + if (table.hasMatch()) { + ResultProtos.MatchProto match = table.getMatch(); + for (ResultProtos.MatchPlayerProto player : match.getPlayersList()) { + UserStats userStats = this.getUser(player.getName()); + ResultProtos.UserStatsProto proto = userStats != null ? userStats.getProto() + : ResultProtos.UserStatsProto.newBuilder().setName(player.getName()).build(); + ResultProtos.UserStatsProto.Builder builder = ResultProtos.UserStatsProto.newBuilder(proto) + .setMatches(proto.getMatches() + 1); + switch (player.getQuit()) { + case IDLE_TIMEOUT: + builder.setMatchesIdleTimeout(proto.getMatchesIdleTimeout() + 1); + break; + case TIMER_TIMEOUT: + builder.setMatchesTimerTimeout(proto.getMatchesTimerTimeout() + 1); + break; + case QUIT: + builder.setMatchesQuit(proto.getMatchesQuit() + 1); + break; + } + if (userStats == null) { + this.add(new UserStats(builder.build(), table.getEndTimeMs())); + } else { + this.update(new UserStats(builder.build(), table.getEndTimeMs())); + } + updatedUsers.add(player.getName()); + } + } else if (table.hasTourney()) { + ResultProtos.TourneyProto tourney = table.getTourney(); + for (ResultProtos.TourneyPlayerProto player : tourney.getPlayersList()) { + UserStats userStats = this.getUser(player.getName()); + ResultProtos.UserStatsProto proto = userStats != null ? userStats.getProto() + : ResultProtos.UserStatsProto.newBuilder().setName(player.getName()).build(); + ResultProtos.UserStatsProto.Builder builder = ResultProtos.UserStatsProto.newBuilder(proto) + .setTourneys(proto.getTourneys() + 1); + switch (player.getQuit()) { + case DURING_ROUND: + builder.setTourneysQuitDuringRound(proto.getTourneysQuitDuringRound() + 1); + break; + case DURING_DRAFTING: + builder.setTourneysQuitDuringDrafting(proto.getTourneysQuitDuringDrafting() + 1); + break; + case DURING_CONSTRUCTION: + builder.setTourneysQuitDuringConstruction(proto.getTourneysQuitDuringConstruction() + 1); + break; + } + if (userStats == null) { + this.add(new UserStats(builder.build(), table.getEndTimeMs())); + } else { + this.update(new UserStats(builder.build(), table.getEndTimeMs())); + } + updatedUsers.add(player.getName()); + } + } + } + } + return new ArrayList(updatedUsers); + } + + public void closeDB() { + try { + if (dao != null && dao.getConnectionSource() != null) { + DatabaseConnection conn = dao.getConnectionSource().getReadWriteConnection(); + conn.executeStatement("shutdown compact", 0); + } + } catch (SQLException ex) { + Logger.getLogger(UserStatsRepository.class).error("Error closing user_stats repository - ", ex); + } + } +} diff --git a/Mage.Server/src/main/java/mage/server/services/LogKeys.java b/Mage.Server/src/main/java/mage/server/services/LogKeys.java index 45a77a7ef42..93b628025f9 100644 --- a/Mage.Server/src/main/java/mage/server/services/LogKeys.java +++ b/Mage.Server/src/main/java/mage/server/services/LogKeys.java @@ -7,6 +7,8 @@ public interface LogKeys { String KEY_GAME_STARTED = "gameStarted"; + String KEY_USER_REGISTERED = "userRegistered"; + String KEY_USER_CONNECTED = "userConnected"; String KEY_ADMIN_CONNECTED = "adminConnected"; 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 fa26d966f17..a212ad60b3d 100644 --- a/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java +++ b/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java @@ -43,6 +43,7 @@ import mage.game.events.TableEvent; import static mage.game.events.TableEvent.EventType.CONSTRUCT; import mage.game.match.Match; import mage.game.match.MatchOptions; +import mage.game.result.ResultProtos.TourneyQuitStatus; import mage.game.tournament.Tournament; import mage.game.tournament.TournamentPairing; import mage.game.tournament.TournamentPlayer; @@ -351,31 +352,34 @@ public class TournamentController { tournamentSession.setKilled(); if (tournamentPlayer.isInTournament()) { String info; + TourneyQuitStatus status; if (tournament.isDoneConstructing()) { info = new StringBuilder("during round ").append(tournament.getRounds().size()).toString(); // quit active matches of that tournament TableManager.getInstance().userQuitTournamentSubTables(tournament.getId(), userId); - } else { - if (tournamentPlayer.getState().equals(TournamentPlayerState.DRAFTING)) { - info = "during Draft phase"; - if (!checkToReplaceDraftPlayerByAi(userId, tournamentPlayer)) { - this.abortDraftTournament(); - } else { - DraftController draftController = DraftManager.getInstance().getController(tableId); - if (draftController != null) { - DraftSession draftSession = draftController.getDraftSession(playerId); - if (draftSession != null) { - DraftManager.getInstance().kill(draftSession.getDraftId(), userId); - } + status = TourneyQuitStatus.DURING_ROUND; + } else if (tournamentPlayer.getState().equals(TournamentPlayerState.DRAFTING)) { + info = "during Draft phase"; + if (!checkToReplaceDraftPlayerByAi(userId, tournamentPlayer)) { + this.abortDraftTournament(); + } else { + DraftController draftController = DraftManager.getInstance().getController(tableId); + if (draftController != null) { + DraftSession draftSession = draftController.getDraftSession(playerId); + if (draftSession != null) { + DraftManager.getInstance().kill(draftSession.getDraftId(), userId); } } - } else if (tournamentPlayer.getState().equals(TournamentPlayerState.CONSTRUCTING)) { - info = "during Construction phase"; - } else { - info = ""; } + status = TourneyQuitStatus.DURING_DRAFTING; + } else if (tournamentPlayer.getState().equals(TournamentPlayerState.CONSTRUCTING)) { + info = "during Construction phase"; + status = TourneyQuitStatus.DURING_CONSTRUCTION; + } else { + info = ""; + status = TourneyQuitStatus.NO_TOURNEY_QUIT; } - tournamentPlayer.setQuit(info); + tournamentPlayer.setQuit(info, status); tournament.quit(playerId); tournamentSession.quit(); ChatManager.getInstance().broadcast(chatId, "", tournamentPlayer.getPlayer().getLogName() + " has quit the tournament", MessageColor.BLACK, true, MessageType.STATUS, SoundToPlay.PlayerQuitTournament); diff --git a/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java b/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java index cee5d5bdee6..d472b0a8cea 100644 --- a/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java +++ b/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java @@ -94,7 +94,7 @@ public class ConfigSettings { public int getBacklogSize() { return config.getServer().getBacklogSize().intValue(); } - + public int getMaxGameThreads() { return config.getServer().getMaxGameThreads().intValue(); } @@ -111,17 +111,61 @@ public class ConfigSettings { return config.getServer().getMaxUserNameLength().intValue(); } - public String getUserNamePattern() { - return config.getServer().getUserNamePattern(); + public String getInvalidUserNamePattern() { + return config.getServer().getInvalidUserNamePattern(); } - + + public int getMinPasswordLength() { + return config.getServer().getMinPasswordLength().intValue(); + } + + public int getMaxPasswordLength() { + return config.getServer().getMaxPasswordLength().intValue(); + } + public String getMaxAiOpponents() { return config.getServer().getMaxAiOpponents(); } public Boolean isSaveGameActivated() { - return config.getServer().isSaveGameActivated(); -} + return config.getServer().isSaveGameActivated(); + } + + public Boolean isAuthenticationActivated() { + return config.getServer().isAuthenticationActivated(); + } + + public String getGoogleAccount() { + return config.getServer().getGoogleAccount(); + } + + public String getMailgunApiKey() { + return config.getServer().getMailgunApiKey(); + } + + public String getMailgunDomain() { + return config.getServer().getMailgunDomain(); + } + + public String getMailSmtpHost() { + return config.getServer().getMailSmtpHost(); + } + + public String getMailSmtpPort() { + return config.getServer().getMailSmtpPort(); + } + + public String getMailUser() { + return config.getServer().getMailUser(); + } + + public String getMailPassword() { + return config.getServer().getMailPassword(); + } + + public String getMailFromAddress() { + return config.getServer().getMailFromAddress(); + } public List getPlayerTypes() { return config.getPlayerTypes().getPlayerType(); diff --git a/Mage.Server/src/main/java/mage/server/util/resources/config.xml b/Mage.Server/src/main/java/mage/server/util/resources/config.xml index 56ca070a03c..f5696f65228 100644 --- a/Mage.Server/src/main/java/mage/server/util/resources/config.xml +++ b/Mage.Server/src/main/java/mage/server/util/resources/config.xml @@ -1,14 +1,14 @@ - diff --git a/Mage.Server/src/main/xml-resources/jaxb/Config/Config.xsd b/Mage.Server/src/main/xml-resources/jaxb/Config/Config.xsd index 8e57894338c..0a82ec9bae5 100644 --- a/Mage.Server/src/main/xml-resources/jaxb/Config/Config.xsd +++ b/Mage.Server/src/main/xml-resources/jaxb/Config/Config.xsd @@ -2,19 +2,19 @@ - + - + - + @@ -22,16 +22,27 @@ - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + @@ -56,7 +67,7 @@ - + diff --git a/Mage.Sets/pom.xml b/Mage.Sets/pom.xml index 72f15ac2c0f..4050b0efede 100644 --- a/Mage.Sets/pom.xml +++ b/Mage.Sets/pom.xml @@ -7,7 +7,7 @@ org.mage mage-root - 1.4.6 + 1.4.8 org.mage diff --git a/Mage.Sets/src/mage/sets/BattleForZendikar.java b/Mage.Sets/src/mage/sets/BattleForZendikar.java index f21179f9746..1572cccc7cf 100644 --- a/Mage.Sets/src/mage/sets/BattleForZendikar.java +++ b/Mage.Sets/src/mage/sets/BattleForZendikar.java @@ -48,7 +48,7 @@ public class BattleForZendikar extends ExpansionSet { return fINSTANCE; } - List savedSpecialLand = new ArrayList<>(); + protected final List savedSpecialLand = new ArrayList<>(); private BattleForZendikar() { super("Battle for Zendikar", "BFZ", "mage.sets.battleforzendikar", new GregorianCalendar(2015, 10, 2).getTime(), SetType.EXPANSION); @@ -56,25 +56,28 @@ public class BattleForZendikar extends ExpansionSet { this.hasBoosters = true; this.hasBasicLands = true; this.numBoosterLands = 1; - this.ratioBoosterSpecialLand = 20; // Approximately as rare as opening a foil mythic = 8 * 6 = ~every 48th booster includes one - // I set it to 20 to get it more often this.numBoosterCommon = 10; this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; this.numBoosterSpecial = 0; + + // Zendikar Expeditions 1-25 + // Approximately as rare as opening a foil mythic = 8 * 6 = ~every 48th booster includes one. + // I set it to 20 to get it more often + this.ratioBoosterSpecialLand = 20; } @Override public List getSpecialLand() { - List specialLand = new ArrayList<>(); if (savedSpecialLand.isEmpty()) { CardCriteria criteria = new CardCriteria(); criteria.setCodes("EXP"); - specialLand.addAll(CardRepository.instance.findCards(criteria)); + criteria.minCardNumber(1); + criteria.maxCardNumber(25); + savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); } - specialLand.addAll(savedSpecialLand); - return specialLand; + return new ArrayList<>(savedSpecialLand); } } diff --git a/Mage.Sets/src/mage/sets/OathOfTheGatewatch.java b/Mage.Sets/src/mage/sets/OathOfTheGatewatch.java index 8d1d9030923..c954424c02c 100644 --- a/Mage.Sets/src/mage/sets/OathOfTheGatewatch.java +++ b/Mage.Sets/src/mage/sets/OathOfTheGatewatch.java @@ -5,8 +5,14 @@ */ package mage.sets; +import java.util.ArrayList; import java.util.GregorianCalendar; +import java.util.List; + import mage.cards.ExpansionSet; +import mage.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; import mage.constants.SetType; /** @@ -21,9 +27,12 @@ public class OathOfTheGatewatch extends ExpansionSet { return fINSTANCE; } + protected final List savedSpecialLand = new ArrayList<>(); + private OathOfTheGatewatch() { super("Oath of the Gatewatch", "OGW", "mage.sets.oathofthegatewatch", new GregorianCalendar(2016, 1, 22).getTime(), SetType.EXPANSION); this.blockName = "Battle for Zendikar"; + this.parentSet = BattleForZendikar.getInstance(); this.hasBoosters = true; this.hasBasicLands = false; this.numBoosterLands = 1; @@ -31,5 +40,21 @@ public class OathOfTheGatewatch extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; + + // Zendikar Expeditions 26-45 + this.ratioBoosterSpecialLand = 20; + } + + @Override + public List getSpecialLand() { + if (savedSpecialLand.isEmpty()) { + CardCriteria criteria = new CardCriteria(); + criteria.setCodes("EXP"); + criteria.minCardNumber(26); + criteria.maxCardNumber(45); + savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); + } + + return new ArrayList<>(savedSpecialLand); } } diff --git a/Mage.Sets/src/mage/sets/alarareborn/Crystallization.java b/Mage.Sets/src/mage/sets/alarareborn/Crystallization.java index 66af16ece13..60df001baa4 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/Crystallization.java +++ b/Mage.Sets/src/mage/sets/alarareborn/Crystallization.java @@ -54,15 +54,11 @@ import mage.target.targetpointer.FixedTarget; * @author jeffwadsworth */ public class Crystallization extends CardImpl { - + public Crystallization(UUID ownerId) { super(ownerId, 144, "Crystallization", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{G/U}{W}"); this.expansionSetCode = "ARB"; this.subtype.add("Aura"); - - - - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); @@ -77,11 +73,11 @@ public class Crystallization extends CardImpl { // When enchanted creature becomes the target of a spell or ability, exile that creature. this.addAbility(new CrystallizationTriggeredAbility()); } - + public Crystallization(final Crystallization card) { super(card); } - + @Override public Crystallization copy() { return new Crystallization(this); @@ -89,15 +85,15 @@ public class Crystallization extends CardImpl { } class CrystallizationTriggeredAbility extends TriggeredAbilityImpl { - + public CrystallizationTriggeredAbility() { super(Zone.BATTLEFIELD, new ExileTargetEffect()); } - + public CrystallizationTriggeredAbility(final CrystallizationTriggeredAbility ability) { super(ability); } - + @Override public CrystallizationTriggeredAbility copy() { return new CrystallizationTriggeredAbility(this); @@ -107,7 +103,7 @@ class CrystallizationTriggeredAbility extends TriggeredAbilityImpl { public boolean checkEventType(GameEvent event, Game game) { return event.getType() == EventType.TARGETED; } - + @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent enchantment = game.getPermanent(sourceId); @@ -120,7 +116,7 @@ class CrystallizationTriggeredAbility extends TriggeredAbilityImpl { } return false; } - + @Override public String getRule() { return "When enchanted creature becomes the target of a spell or ability, exile that creature."; diff --git a/Mage.Sets/src/mage/sets/alarareborn/SlaveOfBolas.java b/Mage.Sets/src/mage/sets/alarareborn/SlaveOfBolas.java index da0c98d4ea7..19c4c24f08e 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/SlaveOfBolas.java +++ b/Mage.Sets/src/mage/sets/alarareborn/SlaveOfBolas.java @@ -98,10 +98,7 @@ class SlaveOfBolasEffect extends OneShotEffect { SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice this", source.getControllerId()); sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/alarareborn/VectisDominator.java b/Mage.Sets/src/mage/sets/alarareborn/VectisDominator.java index 6c3e4d6f24f..118f2f7bae6 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/VectisDominator.java +++ b/Mage.Sets/src/mage/sets/alarareborn/VectisDominator.java @@ -105,7 +105,7 @@ class VectisDominatorEffect extends OneShotEffect { cost.clearPaid(); final StringBuilder sb = new StringBuilder("Pay 2 life? (Otherwise ").append(targetCreature.getName()).append(" will be tapped)"); if (player.chooseUse(Outcome.Benefit, sb.toString(), source, game)) { - cost.pay(source, game, targetCreature.getControllerId(), targetCreature.getControllerId(), true); + cost.pay(source, game, targetCreature.getControllerId(), targetCreature.getControllerId(), true, null); } if (!cost.isPaid()) { return targetCreature.tap(game); diff --git a/Mage.Sets/src/mage/sets/alliances/BalduvianTradingPost.java b/Mage.Sets/src/mage/sets/alliances/BalduvianTradingPost.java index cbd7c330895..2e52191c1f2 100644 --- a/Mage.Sets/src/mage/sets/alliances/BalduvianTradingPost.java +++ b/Mage.Sets/src/mage/sets/alliances/BalduvianTradingPost.java @@ -30,7 +30,6 @@ package mage.sets.alliances; import java.util.UUID; import mage.Mana; import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.SacrificeTargetCost; @@ -71,7 +70,7 @@ public class BalduvianTradingPost extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.ALL, new EnterBattlefieldPayCostOrPutGraveyardEffect(new SacrificeTargetCost(new TargetControlledPermanent(filter))))); // {tap}: Add {C}{R} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 0, 0, 1,0 ), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 0, 0, 0, 0, 1), new TapSourceCost())); // {1}, {tap}: Balduvian Trading Post deals 1 damage to target attacking creature. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new GenericManaCost(1)); diff --git a/Mage.Sets/src/mage/sets/alliances/ElvishSpiritGuide.java b/Mage.Sets/src/mage/sets/alliances/ElvishSpiritGuide.java index c8edfd7de71..cd9ab9e056f 100644 --- a/Mage.Sets/src/mage/sets/alliances/ElvishSpiritGuide.java +++ b/Mage.Sets/src/mage/sets/alliances/ElvishSpiritGuide.java @@ -31,6 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.Mana; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.effects.common.BasicManaEffect; import mage.abilities.mana.SimpleManaAbility; @@ -83,7 +84,7 @@ class ExileSourceFromHandCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Card card = game.getCard(sourceId); Player player = game.getPlayer(controllerId); if (player != null && player.getHand().contains(sourceId) && card != null) { diff --git a/Mage.Sets/src/mage/sets/alliances/PhyrexianDevourer.java b/Mage.Sets/src/mage/sets/alliances/PhyrexianDevourer.java index 36a4e5d6da8..9c61a9cf524 100644 --- a/Mage.Sets/src/mage/sets/alliances/PhyrexianDevourer.java +++ b/Mage.Sets/src/mage/sets/alliances/PhyrexianDevourer.java @@ -160,7 +160,7 @@ class ExileTopCardLibraryCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { card = controller.getLibrary().getFromTop(game); diff --git a/Mage.Sets/src/mage/sets/alliances/SoldeviExcavations.java b/Mage.Sets/src/mage/sets/alliances/SoldeviExcavations.java index 204b0e70da3..300ebf9cc32 100644 --- a/Mage.Sets/src/mage/sets/alliances/SoldeviExcavations.java +++ b/Mage.Sets/src/mage/sets/alliances/SoldeviExcavations.java @@ -69,7 +69,7 @@ public class SoldeviExcavations extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.ALL, new EnterBattlefieldPayCostOrPutGraveyardEffect(new SacrificeTargetCost(new TargetControlledPermanent(filter))))); // {tap}: Add {C}{U} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 0, 0, 1, 0), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 0, 0, 0, 0, 1), new TapSourceCost())); // {1}, {tap}: Scry 1. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ScryEffect(1), new GenericManaCost(1)); diff --git a/Mage.Sets/src/mage/sets/antiquities/PowerArtifact.java b/Mage.Sets/src/mage/sets/antiquities/PowerArtifact.java index b36596b5cbe..b0088262c77 100644 --- a/Mage.Sets/src/mage/sets/antiquities/PowerArtifact.java +++ b/Mage.Sets/src/mage/sets/antiquities/PowerArtifact.java @@ -78,8 +78,8 @@ class PowerArtifactCostModificationEffect extends CostModificationEffectImpl { Player controller = game.getPlayer(abilityToModify.getControllerId()); if (controller != null) { Mana mana = abilityToModify.getManaCostsToPay().getMana(); - int reduce = mana.getColorless(); - if (reduce > 0 && mana.count() == mana.getColorless()) { + int reduce = mana.getGeneric(); + if (reduce > 0 && mana.count() == mana.getGeneric()) { reduce--; } if (reduce > 2) { diff --git a/Mage.Sets/src/mage/sets/apocalypse/ConsumeStrength.java b/Mage.Sets/src/mage/sets/apocalypse/ConsumeStrength.java index 9c3a352436b..c583f19ca4c 100644 --- a/Mage.Sets/src/mage/sets/apocalypse/ConsumeStrength.java +++ b/Mage.Sets/src/mage/sets/apocalypse/ConsumeStrength.java @@ -37,6 +37,8 @@ import mage.constants.Layer; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.SubLayer; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; @@ -54,8 +56,17 @@ public class ConsumeStrength extends CardImpl { // Target creature gets +2/+2 until end of turn. Another target creature gets -2/-2 until end of turn. this.getSpellAbility().addEffect(new ConsumeStrengthEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(2)); + 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); } public ConsumeStrength(final ConsumeStrength card) { @@ -91,7 +102,7 @@ class ConsumeStrengthEffect extends ContinuousEffectImpl { permanent.addPower(2); permanent.addToughness(2); } - permanent = game.getPermanent(source.getTargets().get(0).getTargets().get(1)); + permanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); if (permanent != null) { permanent.addPower(-2); permanent.addToughness(-2); diff --git a/Mage.Sets/src/mage/sets/apocalypse/PhyrexianArena.java b/Mage.Sets/src/mage/sets/apocalypse/PhyrexianArena.java index bb21eb8c14d..1acc6e3c405 100644 --- a/Mage.Sets/src/mage/sets/apocalypse/PhyrexianArena.java +++ b/Mage.Sets/src/mage/sets/apocalypse/PhyrexianArena.java @@ -28,14 +28,13 @@ package mage.sets.apocalypse; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.constants.TargetController; /** @@ -48,6 +47,7 @@ public class PhyrexianArena extends CardImpl { super(ownerId, 47, "Phyrexian Arena", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{B}"); this.expansionSetCode = "APC"; + // At the beginning of your upkeep, you draw a card and you lose 1 life. Ability ability = new BeginningOfUpkeepTriggeredAbility(new DrawCardSourceControllerEffect(1), TargetController.YOU, false); ability.addEffect(new LoseLifeSourceControllerEffect(1)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/archenemy/AvatarOfWoe.java b/Mage.Sets/src/mage/sets/archenemy/AvatarOfWoe.java index f5863fcf5ba..2a29baf45c0 100644 --- a/Mage.Sets/src/mage/sets/archenemy/AvatarOfWoe.java +++ b/Mage.Sets/src/mage/sets/archenemy/AvatarOfWoe.java @@ -100,12 +100,12 @@ class AvatarOfWoeCostReductionEffect extends CostModificationEffectImpl { public boolean apply(Game game, Ability source, Ability abilityToModify) { SpellAbility spellAbility = (SpellAbility) abilityToModify; Mana mana = spellAbility.getManaCostsToPay().getMana(); - if (mana.getColorless() > 0) { - int newCount = mana.getColorless() - 6; + if (mana.getGeneric() > 0) { + int newCount = mana.getGeneric() - 6; if (newCount < 0) { newCount = 0; } - mana.setColorless(newCount); + mana.setGeneric(newCount); spellAbility.getManaCostsToPay().load(mana.toString()); return true; } diff --git a/Mage.Sets/src/mage/sets/archenemy/NantukoMonastery.java b/Mage.Sets/src/mage/sets/archenemy/NantukoMonastery.java index 341918ccdae..c866c135130 100644 --- a/Mage.Sets/src/mage/sets/archenemy/NantukoMonastery.java +++ b/Mage.Sets/src/mage/sets/archenemy/NantukoMonastery.java @@ -35,10 +35,10 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; -import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -58,12 +58,10 @@ public class NantukoMonastery extends CardImpl { // {tap}: Add {C} to your mana pool. 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. - Effect effect = new BecomesCreatureSourceEffect(new NantukoMonasteryToken(), "land", Duration.Custom); - effect.setText("{this} becomes a 4/4 green and white Insect Monk creature"); - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{G}{W}"), - new CardsInControllerGraveCondition(7), - "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."); - ability.addEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn)); + Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect( + new NantukoMonasteryToken(), "land", Duration.EndOfTurn), new ManaCostsImpl<>("{G}{W}"), + new CardsInControllerGraveCondition(7)); + ability.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(ability); } @@ -80,7 +78,7 @@ public class NantukoMonastery extends CardImpl { class NantukoMonasteryToken extends Token { public NantukoMonasteryToken() { - super("", "4/4 green and white Insect Monk creature"); + super("", "4/4 green and white Insect Monk creature with first strike"); cardType.add(CardType.CREATURE); subtype.add("Insect"); subtype.add("Monk"); @@ -88,5 +86,6 @@ class NantukoMonasteryToken extends Token { color.setWhite(true); power = new MageInt(4); toughness = new MageInt(4); + this.addAbility(FirstStrikeAbility.getInstance()); } } diff --git a/Mage.Sets/src/mage/sets/avacynrestored/CavernOfSouls.java b/Mage.Sets/src/mage/sets/avacynrestored/CavernOfSouls.java index f84dff7fc55..747c9bb6b93 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/CavernOfSouls.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/CavernOfSouls.java @@ -36,6 +36,7 @@ import mage.Mana; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.common.ChooseCreatureTypeEffect; @@ -136,7 +137,7 @@ class CavernOfSoulsManaCondition extends CreatureCastManaCondition { } @Override - public boolean apply(Game game, Ability source, UUID manaProducer) { + public boolean apply(Game game, Ability source, UUID originalId, Cost costToPay) { // check: ... to cast a creature spell if (super.apply(game, source)) { // check: ... of the chosen type diff --git a/Mage.Sets/src/mage/sets/avacynrestored/SigardaHostOfHerons.java b/Mage.Sets/src/mage/sets/avacynrestored/SigardaHostOfHerons.java index 6807769fbe2..4652872c0d3 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/SigardaHostOfHerons.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/SigardaHostOfHerons.java @@ -28,23 +28,24 @@ package mage.sets.avacynrestored; import java.util.UUID; - -import mage.constants.*; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; -import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HexproofAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.PermanentCard; import mage.game.stack.Spell; - /** * @author noxx */ @@ -96,18 +97,18 @@ class SigardaHostOfHeronsEffect extends ContinuousRuleModifyingEffectImpl { public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.SACRIFICE_PERMANENT; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getPlayerId().equals(source.getControllerId())) { MageObject object = game.getObject(event.getSourceId()); if (object instanceof PermanentCard) { - if (game.getOpponents(source.getControllerId()).contains(((PermanentCard)object).getControllerId())) { + if (game.getOpponents(source.getControllerId()).contains(((PermanentCard) object).getControllerId())) { return true; } } if (object instanceof Spell) { - if (game.getOpponents(source.getControllerId()).contains(((Spell)object).getControllerId())) { + if (game.getOpponents(source.getControllerId()).contains(((Spell) object).getControllerId())) { return true; } } diff --git a/Mage.Sets/src/mage/sets/avacynrestored/ThatcherRevolt.java b/Mage.Sets/src/mage/sets/avacynrestored/ThatcherRevolt.java index 3e3518eebde..ef664dce351 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/ThatcherRevolt.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/ThatcherRevolt.java @@ -27,6 +27,7 @@ */ package mage.sets.avacynrestored; +import java.util.ArrayList; import java.util.UUID; import mage.MageInt; import mage.ObjectColor; @@ -42,7 +43,7 @@ import mage.constants.Rarity; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.Token; -import mage.target.targetpointer.FixedTarget; +import mage.target.targetpointer.FixedTargets; /** * @@ -88,14 +89,16 @@ class ThatcherRevoltEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { RedHumanToken token = new RedHumanToken(); token.putOntoBattlefield(3, game, source.getSourceId(), source.getControllerId()); + ArrayList toSacrifice = new ArrayList<>(); for (UUID tokenId : token.getLastAddedTokenIds()) { Permanent tokenPermanent = game.getPermanent(tokenId); if (tokenPermanent != null) { - SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect(); - sacrificeEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); - game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect), source); + toSacrifice.add(tokenPermanent); } } + SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect(); + sacrificeEffect.setTargetPointer(new FixedTargets(toSacrifice, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect), source); return true; } } diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/BrutalExpulsion.java b/Mage.Sets/src/mage/sets/battleforzendikar/BrutalExpulsion.java index fcddf947e1b..9bd5b1cf575 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/BrutalExpulsion.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/BrutalExpulsion.java @@ -79,7 +79,7 @@ public class BrutalExpulsion extends CardImpl { effect.setText("If that permanent would be put into a graveyard this turn, exile it instead"); mode.getEffects().add(effect); this.getSpellAbility().addMode(mode); - this.getSpellAbility().addWatcher(new DamagedByWatcher()); + this.getSpellAbility().addWatcher(new DamagedByWatcher(true)); } public BrutalExpulsion(final BrutalExpulsion card) { diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/ClutchOfCurrents.java b/Mage.Sets/src/mage/sets/battleforzendikar/ClutchOfCurrents.java index 2619589cb6a..65fe9140eae 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/ClutchOfCurrents.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/ClutchOfCurrents.java @@ -46,7 +46,7 @@ public class ClutchOfCurrents extends CardImpl { this.expansionSetCode = "BFZ"; // Return target creature to its owner's hand. - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect(true, false)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Awaken 3—{4}{U} diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/GraveBirthing.java b/Mage.Sets/src/mage/sets/battleforzendikar/GraveBirthing.java index 7d907fff3c4..f689d0ff894 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/GraveBirthing.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/GraveBirthing.java @@ -104,7 +104,7 @@ class GraveBirthingEffect extends OneShotEffect { target.setNotTarget(true); opponent.chooseTarget(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); - opponent.moveCards(card, null, Zone.EXILED, source, game); + opponent.moveCards(card, Zone.EXILED, source, game); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/GrovetenderDruids.java b/Mage.Sets/src/mage/sets/battleforzendikar/GrovetenderDruids.java index fa502b0d489..1aac7264904 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/GrovetenderDruids.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/GrovetenderDruids.java @@ -95,7 +95,7 @@ class GrovetenderDruidsEffect extends OneShotEffect { if(player != null) { if(player.chooseUse(Outcome.BoostCreature, "Do you want to to pay {1}?", source, game)) { Cost cost = new ManaCostsImpl("{1}"); - if(cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if(cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { new CreateTokenEffect(new GrovetenderDruidsPlantToken()).apply(game, source); } return true; diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/GruesomeSlaughter.java b/Mage.Sets/src/mage/sets/battleforzendikar/GruesomeSlaughter.java index 189f4108e21..65b5208a131 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/GruesomeSlaughter.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/GruesomeSlaughter.java @@ -65,7 +65,9 @@ public class GruesomeSlaughter extends CardImpl { effect.setText("{this} deals damage equal to its power to target creature."); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(new GainAbilityControlledEffect(ability, Duration.EndOfTurn, filter)); + effect = new GainAbilityControlledEffect(ability, Duration.EndOfTurn, filter); + effect.setText("Until end of turn, colorless creatures you control gain \"{T}: This creature deals damage equal to its power to target creature.\""); + this.getSpellAbility().addEffect(effect); } public GruesomeSlaughter(final GruesomeSlaughter card) { diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/MoltenNursery.java b/Mage.Sets/src/mage/sets/battleforzendikar/MoltenNursery.java index 71404a42606..35cf4945d05 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/MoltenNursery.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/MoltenNursery.java @@ -45,7 +45,7 @@ import mage.target.common.TargetCreatureOrPlayer; */ public class MoltenNursery extends CardImpl { - private static final FilterSpell filter = new FilterSpell("colorless spell"); + private static final FilterSpell filter = new FilterSpell("a colorless spell"); static { filter.add(new ColorlessPredicate()); diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/StasisSnare.java b/Mage.Sets/src/mage/sets/battleforzendikar/StasisSnare.java index ac6704bb5cd..b96674fe2ac 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/StasisSnare.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/StasisSnare.java @@ -87,7 +87,7 @@ class StasisSnareExileEffect extends OneShotEffect { public StasisSnareExileEffect() { super(Outcome.Benefit); - this.staticText = "exile target creature an opponent controls until Stasis Snare leaves the battlefield"; + this.staticText = "exile target creature an opponent controls until {this} leaves the battlefield"; } public StasisSnareExileEffect(final StasisSnareExileEffect effect) { diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/TideDrifter.java b/Mage.Sets/src/mage/sets/battleforzendikar/TideDrifter.java index 43dcbe4827d..0b078316928 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/TideDrifter.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/TideDrifter.java @@ -46,7 +46,7 @@ import mage.filter.predicate.mageobject.ColorlessPredicate; */ public class TideDrifter extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Other colorless creatures you control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("colorless creatures"); static { filter.add(new ColorlessPredicate()); diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/WastelandStrangler.java b/Mage.Sets/src/mage/sets/battleforzendikar/WastelandStrangler.java index 739f0d27721..553c5cdd10c 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/WastelandStrangler.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/WastelandStrangler.java @@ -60,7 +60,7 @@ public class WastelandStrangler extends CardImpl { // When Wasteland Strangler enters the battlefield, you may put a card an opponent owns from exile into that player's graveyard. If you do, target creature gets -3/-3 until end of turn. Ability ability = new EntersBattlefieldTriggeredAbility( - new DoIfCostPaid(new BoostTargetEffect(-3, -3, Duration.EndOfTurn), new ExileOpponentsCardFromExileToGraveyardCost(true)), true); + new DoIfCostPaid(new BoostTargetEffect(-3, -3, Duration.EndOfTurn), new ExileOpponentsCardFromExileToGraveyardCost(true)), false); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/BlindingPowder.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/BlindingPowder.java index 727a67b0c6f..81eb750bfc6 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/BlindingPowder.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/BlindingPowder.java @@ -31,6 +31,7 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.Effect; @@ -92,7 +93,7 @@ class BlindingPowderUnattachCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { for (UUID attachmentId : permanent.getAttachments()) { diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/MarkOfSakiko.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/MarkOfSakiko.java index 98dbfb2c5b4..3a996c6e835 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/MarkOfSakiko.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/MarkOfSakiko.java @@ -112,7 +112,7 @@ class MarkOfSakikoTriggeredAbility extends TriggeredAbilityImpl { if (((DamagedEvent) event).isCombatDamage()) { if (event.getSourceId().equals(getSourceId())) { this.getEffects().clear(); - Effect effect = new AddManaToManaPoolTargetControllerEffect(new Mana(0,event.getAmount(),0,0,0,0,0), "that player", true); + Effect effect = new AddManaToManaPoolTargetControllerEffect(new Mana(0,event.getAmount(),0,0,0,0,0, 0), "that player", true); effect.setTargetPointer(new FixedTarget(getControllerId())); effect.setText("add that much {G} to your mana pool. Until end of turn, this mana doesn't empty from your mana pool as steps and phases end"); this.addEffect(effect); diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/OgreMarauder.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/OgreMarauder.java index cc0ed1bcf5f..133834c0a3d 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/OgreMarauder.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/OgreMarauder.java @@ -100,7 +100,7 @@ class OgreMarauderEffect extends OneShotEffect { Cost cost = new SacrificeTargetCost(new TargetControlledCreaturePermanent()); if (cost.canPay(source, source.getSourceId(), defendingPlayerId, game) && defender.chooseUse(Outcome.LoseAbility, "Sacrifice a creature to prevent that " + sourceObject.getLogName() + " can't be blocked?", source, game)) { - if (!cost.pay(source, game, source.getSourceId(), defendingPlayerId, false)) { + if (!cost.pay(source, game, source.getSourceId(), defendingPlayerId, false, null)) { // cost was not payed - so source can't be blocked ContinuousEffect effect = new CantBeBlockedSourceEffect(Duration.EndOfTurn); game.addEffect(effect, source); diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/PetalmaneBaku.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/PetalmaneBaku.java index d31abe9b9c1..1bd98974269 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/PetalmaneBaku.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/PetalmaneBaku.java @@ -70,7 +70,7 @@ public class PetalmaneBaku extends CardImpl { // {1}, Remove X ki counters from Petalmane Baku: Add X mana of any one color to your mana pool. Ability ability = new DynamicManaAbility( - new Mana(0, 0, 0, 0, 0, 0, 1), + new Mana(0, 0, 0, 0, 0, 0, 1, 0), new RemovedCountersForCostValue(), new ManaCostsImpl<>("{1}"), "Add X mana of any one color to your mana pool", @@ -130,19 +130,19 @@ public class PetalmaneBaku extends CardImpl { } } if (choice.getColor().isBlack()) { - player.getManaPool().addMana(new Mana(0, 0, 0, 0, numberOfMana, 0, 0), game, source); + player.getManaPool().addMana(new Mana(0, 0, 0, 0, numberOfMana, 0, 0, 0), game, source); return true; } else if (choice.getColor().isBlue()) { - player.getManaPool().addMana(new Mana(0, 0, numberOfMana, 0, 0, 0, 0), game, source); + player.getManaPool().addMana(new Mana(0, 0, numberOfMana, 0, 0, 0, 0, 0), game, source); return true; } else if (choice.getColor().isRed()) { - player.getManaPool().addMana(new Mana(numberOfMana, 0, 0, 0, 0, 0, 0), game, source); + player.getManaPool().addMana(new Mana(numberOfMana, 0, 0, 0, 0, 0, 0, 0), game, source); return true; } else if (choice.getColor().isGreen()) { - player.getManaPool().addMana(new Mana(0, numberOfMana, 0, 0, 0, 0, 0), game, source); + player.getManaPool().addMana(new Mana(0, numberOfMana, 0, 0, 0, 0, 0, 0), game, source); return true; } else if (choice.getColor().isWhite()) { - player.getManaPool().addMana(new Mana(0, 0, 0, numberOfMana, 0, 0, 0), game, source); + player.getManaPool().addMana(new Mana(0, 0, 0, numberOfMana, 0, 0, 0, 0), game, source); return true; } } diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/SakikoMotherOfSummer.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/SakikoMotherOfSummer.java index fe8a3787c2f..c8a8159ea10 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/SakikoMotherOfSummer.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/SakikoMotherOfSummer.java @@ -101,7 +101,7 @@ class SakikoMotherOfSummerTriggeredAbility extends TriggeredAbilityImpl { Permanent creature = game.getPermanent(event.getSourceId()); if (creature != null && creature.getControllerId().equals(controllerId)) { this.getEffects().clear(); - Effect effect = new AddManaToManaPoolTargetControllerEffect(new Mana(0,event.getAmount(),0,0,0,0,0), "that player", true); + Effect effect = new AddManaToManaPoolTargetControllerEffect(new Mana(0,event.getAmount(),0,0,0,0,0, 0), "that player", true); effect.setTargetPointer(new FixedTarget(creature.getControllerId())); effect.setText("add that much {G} to your mana pool. Until end of turn, this mana doesn't empty from your mana pool as steps and phases end"); this.addEffect(effect); diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/ShireiShizosCaretaker.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/ShireiShizosCaretaker.java index 58f970e9d42..1e38f7a391b 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/ShireiShizosCaretaker.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/ShireiShizosCaretaker.java @@ -79,15 +79,15 @@ public class ShireiShizosCaretaker extends CardImpl { } class ShireiShizosCaretakerTriggeredAbility extends TriggeredAbilityImpl { - + ShireiShizosCaretakerTriggeredAbility(UUID shireiId) { super(Zone.BATTLEFIELD, new ShireiShizosCaretakerEffect(shireiId), false); } - + ShireiShizosCaretakerTriggeredAbility(final ShireiShizosCaretakerTriggeredAbility ability) { super(ability); } - + @Override public ShireiShizosCaretakerTriggeredAbility copy() { return new ShireiShizosCaretakerTriggeredAbility(this); @@ -97,19 +97,19 @@ class ShireiShizosCaretakerTriggeredAbility extends TriggeredAbilityImpl { public boolean checkEventType(GameEvent event, Game game) { return event.getType() == EventType.ZONE_CHANGE; } - + @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; Permanent LKIpermanent = game.getPermanentOrLKIBattlefield(zEvent.getTargetId()); Card card = game.getCard(zEvent.getTargetId()); - if (card != null && LKIpermanent != null && - card.getOwnerId().equals(this.controllerId) && - zEvent.getToZone() == Zone.GRAVEYARD && - zEvent.getFromZone() == Zone.BATTLEFIELD && - card.getCardType().contains(CardType.CREATURE) && - LKIpermanent.getPower().getValue() <= 1) { + if (card != null && LKIpermanent != null + && card.getOwnerId().equals(this.controllerId) + && zEvent.getToZone() == Zone.GRAVEYARD + && zEvent.getFromZone() == Zone.BATTLEFIELD + && card.getCardType().contains(CardType.CREATURE) + && LKIpermanent.getPower().getValue() <= 1) { for (Effect effect : this.getEffects()) { effect.setTargetPointer(new FixedTarget(zEvent.getTargetId())); } @@ -117,7 +117,7 @@ class ShireiShizosCaretakerTriggeredAbility extends TriggeredAbilityImpl { } return false; } - + @Override public String getRule() { return "Whenever a creature with power 1 or less is put into your graveyard from the battlefield, you may return that card to the battlefield at the beginning of the next end step if Shirei, Shizo's Caretaker is still on the battlefield."; @@ -125,25 +125,25 @@ class ShireiShizosCaretakerTriggeredAbility extends TriggeredAbilityImpl { } class ShireiShizosCaretakerEffect extends OneShotEffect { - + protected final UUID shireiId; - + ShireiShizosCaretakerEffect(UUID shireiId) { super(Outcome.PutCreatureInPlay); this.staticText = "you may return that card to the battlefield at the beginning of the next end step if {this} is still on the battlefield."; this.shireiId = shireiId; } - + ShireiShizosCaretakerEffect(final ShireiShizosCaretakerEffect effect) { super(effect); this.shireiId = effect.shireiId; } - + @Override public ShireiShizosCaretakerEffect copy() { return new ShireiShizosCaretakerEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Card card = game.getCard(this.getTargetPointer().getFirst(game, source)); @@ -151,11 +151,8 @@ class ShireiShizosCaretakerEffect extends OneShotEffect { Effect effect = new ShireiShizosCaretakerReturnEffect(shireiId); effect.setText("return that card to the battlefield if {this} is still on the battlefield"); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(card.getId())); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } return false; @@ -163,23 +160,23 @@ class ShireiShizosCaretakerEffect extends OneShotEffect { } class ShireiShizosCaretakerReturnEffect extends ReturnToBattlefieldUnderYourControlTargetEffect { - + protected final UUID shireiId; - + ShireiShizosCaretakerReturnEffect(UUID shireiId) { this.shireiId = shireiId; } - + ShireiShizosCaretakerReturnEffect(final ShireiShizosCaretakerReturnEffect effect) { super(effect); this.shireiId = effect.shireiId; } - + @Override public ShireiShizosCaretakerReturnEffect copy() { return new ShireiShizosCaretakerReturnEffect(this); } - + @Override public boolean apply(Game game, Ability source) { if (game.getBattlefield().containsPermanent(shireiId)) { diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/ShizukoCallerOfAutumn.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/ShizukoCallerOfAutumn.java index 078ac1c3e44..fc611e580d9 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/ShizukoCallerOfAutumn.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/ShizukoCallerOfAutumn.java @@ -56,7 +56,7 @@ public class ShizukoCallerOfAutumn extends CardImpl { this.toughness = new MageInt(3); // At the beginning of each player's upkeep, that player adds {G}{G}{G} to his or her mana pool. Until end of turn, this mana doesn't empty from that player's mana pool as steps and phases end. - Effect effect = new AddManaToManaPoolTargetControllerEffect(new Mana(0,3,0,0,0,0,0), "that player", true); + Effect effect = new AddManaToManaPoolTargetControllerEffect(new Mana(0,3,0,0,0,0,0, 0), "that player", true); effect.setText("that player adds {G}{G}{G} to his or her mana pool. Until end of turn, this mana doesn't empty from that player's mana pool as steps and phases end"); this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, effect, TargetController.ANY, false)); diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/Shuriken.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/Shuriken.java index 3ba3e2f8117..32d4148405e 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/Shuriken.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/Shuriken.java @@ -138,7 +138,7 @@ class ShurikenUnattachCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { for (UUID attachmentId :permanent.getAttachments()) { diff --git a/Mage.Sets/src/mage/sets/bornofthegods/AstralCornucopia.java b/Mage.Sets/src/mage/sets/bornofthegods/AstralCornucopia.java index 6d57185c284..de9013abcf2 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/AstralCornucopia.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/AstralCornucopia.java @@ -95,7 +95,7 @@ class AstralCornucopiaManaAbility extends ManaAbility { if (sourcePermanent != null) { int counters = sourcePermanent.getCounters().getCount(CounterType.CHARGE.getName()); if (counters > 0) { - netMana.add(new Mana(0, 0, 0, 0, 0, 0, counters)); + netMana.add(new Mana(0, 0, 0, 0, 0, 0, counters, 0)); } } return netMana; diff --git a/Mage.Sets/src/mage/sets/bornofthegods/FelhideSpiritbinder.java b/Mage.Sets/src/mage/sets/bornofthegods/FelhideSpiritbinder.java index 7d31be41b06..afff3afffbb 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/FelhideSpiritbinder.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/FelhideSpiritbinder.java @@ -113,10 +113,7 @@ class FelhideSpiritbinderEffect extends OneShotEffect { ExileTargetEffect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } return true; } diff --git a/Mage.Sets/src/mage/sets/bornofthegods/FloodtideSerpent.java b/Mage.Sets/src/mage/sets/bornofthegods/FloodtideSerpent.java index 16e5cd91835..c0924fe1e96 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/FloodtideSerpent.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/FloodtideSerpent.java @@ -109,7 +109,7 @@ class FloodtideSerpentReplacementEffect extends ReplacementEffectImpl { ReturnToHandChosenControlledPermanentCost attackCost = new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(filter)); if (attackCost.canPay(source, source.getSourceId(), event.getPlayerId(), game) && player.chooseUse(Outcome.Neutral, "Return an enchantment you control to hand to attack?", source, game)) { - if (attackCost.pay(source, game, source.getSourceId(), event.getPlayerId(), true)) { + if (attackCost.pay(source, game, source.getSourceId(), event.getPlayerId(), true, null)) { return false; } } diff --git a/Mage.Sets/src/mage/sets/bornofthegods/HeroOfLeinaTower.java b/Mage.Sets/src/mage/sets/bornofthegods/HeroOfLeinaTower.java index 7611a108558..b458d1b7aed 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/HeroOfLeinaTower.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/HeroOfLeinaTower.java @@ -98,7 +98,7 @@ class HeroOfLeinaTowerEffect extends OneShotEffect { if (you != null && you.chooseUse(Outcome.BoostCreature, "Do you want to to pay {X}?", source, game)) { int costX = you.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); cost.add(new GenericManaCost(costX)); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (sourcePermanent != null) { return new AddCountersSourceEffect(CounterType.P1P1.createInstance(costX), true).apply(game, source); diff --git a/Mage.Sets/src/mage/sets/bornofthegods/MarshmistTitan.java b/Mage.Sets/src/mage/sets/bornofthegods/MarshmistTitan.java index 1cc6f0f2df9..cda9024f4a0 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/MarshmistTitan.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/MarshmistTitan.java @@ -88,13 +88,13 @@ class MarshmistTitanCostReductionEffect extends CostModificationEffectImpl { public boolean apply(Game game, Ability source, Ability abilityToModify) { SpellAbility spellAbility = (SpellAbility)abilityToModify; Mana mana = spellAbility.getManaCostsToPay().getMana(); - if (mana.getColorless() > 0) { + if (mana.getGeneric() > 0) { int count = new DevotionCount(ColoredManaSymbol.B).calculate(game, source, this); - int newCount = mana.getColorless() - count; + int newCount = mana.getGeneric() - count; if (newCount < 0) { newCount = 0; } - mana.setColorless(newCount); + mana.setGeneric(newCount); spellAbility.getManaCostsToPay().load(mana.toString()); return true; } diff --git a/Mage.Sets/src/mage/sets/bornofthegods/MogisGodOfSlaughter.java b/Mage.Sets/src/mage/sets/bornofthegods/MogisGodOfSlaughter.java index d5bd22552ac..62207a504f5 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/MogisGodOfSlaughter.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/MogisGodOfSlaughter.java @@ -130,7 +130,7 @@ class DoUnlessTargetPaysCost extends OneShotEffect { message = CardUtil.replaceSourceName(message, mageObject.getLogName()); cost.clearPaid(); if (cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(executingEffect.getOutcome(), message, source, game)) { - cost.pay(source, game, source.getSourceId(), player.getId(), false); + cost.pay(source, game, source.getSourceId(), player.getId(), false, null); } if (!cost.isPaid()) { executingEffect.setTargetPointer(this.targetPointer); diff --git a/Mage.Sets/src/mage/sets/bornofthegods/SearingBlood.java b/Mage.Sets/src/mage/sets/bornofthegods/SearingBlood.java index c7e59facd09..e07a61984ee 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/SearingBlood.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/SearingBlood.java @@ -57,7 +57,6 @@ public class SearingBlood extends CardImpl { super(ownerId, 111, "Searing Blood", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{R}{R}"); this.expansionSetCode = "BNG"; - // Searing Blood deals 2 damage to target creature. When that creature dies this turn, Searing Blood deals 3 damage to that creature's controller. this.getSpellAbility().addEffect(new SearingBloodEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); @@ -92,10 +91,7 @@ class SearingBloodEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { DelayedTriggeredAbility delayedAbility = new SearingBloodDelayedTriggeredAbility(source.getFirstTarget()); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return new DamageTargetEffect(2).apply(game, source); } diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/BoseijuWhoSheltersAll.java b/Mage.Sets/src/mage/sets/championsofkamigawa/BoseijuWhoSheltersAll.java index 2e42ccfa63b..a303d567d89 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/BoseijuWhoSheltersAll.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/BoseijuWhoSheltersAll.java @@ -66,15 +66,15 @@ public class BoseijuWhoSheltersAll extends CardImpl { // Boseiju, Who Shelters All enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); - + // {tap}, Pay 2 life: Add {C} to your mana pool. If that mana is spent on an instant or sorcery spell, that spell can't be countered by spells or abilities. - Mana mana = new Mana(0, 0, 0, 0, 0, 1, 0); + Mana mana = new Mana(0, 0, 0, 0, 0, 0, 0, 1); mana.setFlag(true); // used to indicate this mana ability SimpleManaAbility ability = new SimpleManaAbility(Zone.BATTLEFIELD, mana, new TapSourceCost()); ability.addCost(new PayLifeCost(2)); ability.getEffects().get(0).setText("Add {C} to your mana pool. If that mana is spent on an instant or sorcery spell, that spell can't be countered by spells or abilities"); this.addAbility(ability); - + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoseijuWhoSheltersAllCantCounterEffect()), new BoseijuWhoSheltersAllWatcher()); } @@ -126,7 +126,7 @@ class BoseijuWhoSheltersAllWatcher extends Watcher { class BoseijuWhoSheltersAllCantCounterEffect extends ContinuousRuleModifyingEffectImpl { private static final FilterCard filter = new FilterInstantOrSorceryCard(); - + public BoseijuWhoSheltersAllCantCounterEffect() { super(Duration.WhileOnBattlefield, Outcome.Benefit); staticText = null; @@ -154,12 +154,12 @@ class BoseijuWhoSheltersAllCantCounterEffect extends ContinuousRuleModifyingEffe } return null; } - + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.COUNTER; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { BoseijuWhoSheltersAllWatcher watcher = (BoseijuWhoSheltersAllWatcher) game.getState().getWatchers().get("ManaPaidFromBoseijuWhoSheltersAllWatcher"); diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/CutTheTethers.java b/Mage.Sets/src/mage/sets/championsofkamigawa/CutTheTethers.java index 8b8bfd29f6d..a731607f13e 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/CutTheTethers.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/CutTheTethers.java @@ -98,7 +98,7 @@ class CutTheTethersEffect extends OneShotEffect { boolean paid = false; if (player.chooseUse(outcome, new StringBuilder("Pay {3} to keep ").append(creature.getName()).append(" on the battlefield?").toString(), source, game)) { Cost cost = new GenericManaCost(3); - if (!cost.pay(source, game, source.getSourceId(), creature.getControllerId(), false)) { + if (!cost.pay(source, game, source.getSourceId(), creature.getControllerId(), false, null)) { paid = true; } if (!paid) { diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/Hankyu.java b/Mage.Sets/src/mage/sets/championsofkamigawa/Hankyu.java index 37053638d27..cc32185da8d 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/Hankyu.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/Hankyu.java @@ -36,6 +36,7 @@ import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; @@ -184,7 +185,7 @@ class HankyuCountersSourceCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent equipment = game.getPermanent(this.effectGivingEquipmentId); if (equipment != null ) { this.removedCounters = equipment.getCounters().getCount(CounterType.AIM); diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/HikariTwilightGuardian.java b/Mage.Sets/src/mage/sets/championsofkamigawa/HikariTwilightGuardian.java index b6da86b62e9..1b64bc9ddc4 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/HikariTwilightGuardian.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/HikariTwilightGuardian.java @@ -31,7 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.Effect; -import mage.abilities.effects.common.ExileReturnToBattlefieldOwnerNextEndStepEffect; +import mage.abilities.effects.common.ExileReturnBattlefieldOwnerNextEndStepSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.constants.CardType; @@ -58,7 +58,7 @@ public class HikariTwilightGuardian extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever you cast a Spirit or Arcane spell, you may exile Hikari, Twilight Guardian. If you do, return it to the battlefield under its owner's control at the beginning of the next end step. - Effect effect = new ExileReturnToBattlefieldOwnerNextEndStepEffect(); + Effect effect = new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(); effect.setText("you may exile {this}. If you do, return it to the battlefield under its owner's control at the beginning of the next end step"); this.addAbility(new SpellCastControllerTriggeredAbility(effect, filter, true)); } diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/HisokaMinamoSensei.java b/Mage.Sets/src/mage/sets/championsofkamigawa/HisokaMinamoSensei.java index 9871ad87fea..0ff4bdfb5c7 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/HisokaMinamoSensei.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/HisokaMinamoSensei.java @@ -36,6 +36,7 @@ import mage.constants.Rarity; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; @@ -98,7 +99,7 @@ class HisokaMinamoSenseiDiscardTargetCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { if (targets.choose(Outcome.Discard, controllerId, sourceId, game)) { Player player = game.getPlayer(controllerId); for (UUID targetId: targets.get(0).getTargets()) { diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/JunkyoBell.java b/Mage.Sets/src/mage/sets/championsofkamigawa/JunkyoBell.java index da08e4cd46b..dd60c1b6d24 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/JunkyoBell.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/JunkyoBell.java @@ -98,10 +98,7 @@ public class JunkyoBell extends CardImpl { SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice boosted " + creature.getName(), source.getControllerId()); sacrificeEffect.setTargetPointer(new FixedTarget(creature, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/TatsumasaTheDragonsFang.java b/Mage.Sets/src/mage/sets/championsofkamigawa/TatsumasaTheDragonsFang.java index 1cd6c9b8a55..4e6d4c5ba7b 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/TatsumasaTheDragonsFang.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/TatsumasaTheDragonsFang.java @@ -117,10 +117,7 @@ class TatsumaTheDragonsFangEffect extends OneShotEffect { Effect returnEffect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(); returnEffect.setTargetPointer(new FixedTarget(source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId()))); DelayedTriggeredAbility delayedAbility = new TatsumaTheDragonsFangTriggeredAbility(fixedTarget, returnEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } } diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/ThroughTheBreach.java b/Mage.Sets/src/mage/sets/championsofkamigawa/ThroughTheBreach.java index f8510304312..b891c81dc80 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/ThroughTheBreach.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/ThroughTheBreach.java @@ -115,10 +115,7 @@ class ThroughTheBreachEffect extends OneShotEffect { SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice " + card.getName(), source.getControllerId()); sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } } diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/UntaidakeTheCloudKeeper.java b/Mage.Sets/src/mage/sets/championsofkamigawa/UntaidakeTheCloudKeeper.java index 368d39bd172..7b5f5a4d82b 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/UntaidakeTheCloudKeeper.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/UntaidakeTheCloudKeeper.java @@ -35,6 +35,7 @@ import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.condition.Condition; +import mage.abilities.costs.Cost; import mage.abilities.costs.common.PayLifeCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.mana.ConditionalColorlessManaAbility; @@ -62,7 +63,7 @@ public class UntaidakeTheCloudKeeper extends CardImpl { Ability ability = new ConditionalColorlessManaAbility(new TapSourceCost(), 2, new LegendarySpellManaBuilder()); ability.addCost(new PayLifeCost(2)); this.addAbility(ability); - + } public UntaidakeTheCloudKeeper(final UntaidakeTheCloudKeeper card) { @@ -76,6 +77,7 @@ public class UntaidakeTheCloudKeeper extends CardImpl { } class LegendarySpellManaBuilder extends ConditionalManaBuilder { + @Override public ConditionalMana build(Object... options) { return new LegendaryCastConditionalMana(this.mana); @@ -97,6 +99,7 @@ class LegendaryCastConditionalMana extends ConditionalMana { } class LegendaryCastManaCondition extends ManaCondition implements Condition { + @Override public boolean apply(Game game, Ability source) { if (source instanceof SpellAbility) { @@ -109,7 +112,7 @@ class LegendaryCastManaCondition extends ManaCondition implements Condition { } @Override - public boolean apply(Game game, Ability source, UUID originalId) { + public boolean apply(Game game, Ability source, UUID originalId, Cost costsToPay) { return apply(game, source); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/YamabushisStorm.java b/Mage.Sets/src/mage/sets/championsofkamigawa/YamabushisStorm.java index ad1ceef375e..3f116eaff4e 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/YamabushisStorm.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/YamabushisStorm.java @@ -1,5 +1,5 @@ /* - * + * * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -25,28 +25,18 @@ * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. - * + * */ package mage.sets.championsofkamigawa; import java.util.UUID; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Outcome; import mage.constants.Rarity; -import mage.abilities.Ability; -import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.replacement.DealtDamageToCreatureBySourceDies; import mage.cards.CardImpl; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; -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.players.Player; import mage.watchers.common.DamagedByWatcher; /** @@ -61,7 +51,7 @@ public class YamabushisStorm extends CardImpl { // Yamabushi's Storm deals 1 damage to each creature. this.getSpellAbility().addEffect(new DamageAllEffect(1, new FilterCreaturePermanent())); - + // If a creature dealt damage this way would die this turn, exile it instead. this.getSpellAbility().addEffect(new DealtDamageToCreatureBySourceDies(this, Duration.EndOfTurn)); this.getSpellAbility().addWatcher(new DamagedByWatcher()); diff --git a/Mage.Sets/src/mage/sets/coldsnap/AdarkarValkyrie.java b/Mage.Sets/src/mage/sets/coldsnap/AdarkarValkyrie.java index cf4356084d8..308322b2f25 100644 --- a/Mage.Sets/src/mage/sets/coldsnap/AdarkarValkyrie.java +++ b/Mage.Sets/src/mage/sets/coldsnap/AdarkarValkyrie.java @@ -60,6 +60,7 @@ import mage.target.targetpointer.FixedTarget; public class AdarkarValkyrie extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); + static { filter.add(new AnotherPredicate()); } @@ -113,15 +114,11 @@ class AdarkarValkyrieEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { DelayedTriggeredAbility delayedAbility = new AdarkarValkyrieDelayedTriggeredAbility(new FixedTarget(this.getTargetPointer().getFirst(game, source))); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return false; } } - class AdarkarValkyrieDelayedTriggeredAbility extends DelayedTriggeredAbility { protected FixedTarget fixedTarget; @@ -162,4 +159,3 @@ class AdarkarValkyrieDelayedTriggeredAbility extends DelayedTriggeredAbility { return "When target creature other than Adarkar Valkyrie dies this turn, " + super.getRule(); } } - diff --git a/Mage.Sets/src/mage/sets/coldsnap/BraidOfFire.java b/Mage.Sets/src/mage/sets/coldsnap/BraidOfFire.java index 7cd6701a5bf..126bb83dec1 100644 --- a/Mage.Sets/src/mage/sets/coldsnap/BraidOfFire.java +++ b/Mage.Sets/src/mage/sets/coldsnap/BraidOfFire.java @@ -30,6 +30,7 @@ package mage.sets.coldsnap; import java.util.UUID; import mage.Mana; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.keyword.CumulativeUpkeepAbility; import mage.cards.CardImpl; @@ -73,7 +74,7 @@ class BraidOfFireCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player player = game.getPlayer(controllerId); player.getManaPool().addMana(Mana.RedMana(1), game, ability); paid = true; diff --git a/Mage.Sets/src/mage/sets/coldsnap/FuryOfTheHorde.java b/Mage.Sets/src/mage/sets/coldsnap/FuryOfTheHorde.java index d672dfc494a..067a73b8272 100644 --- a/Mage.Sets/src/mage/sets/coldsnap/FuryOfTheHorde.java +++ b/Mage.Sets/src/mage/sets/coldsnap/FuryOfTheHorde.java @@ -57,7 +57,7 @@ import mage.watchers.common.AttackedThisTurnWatcher; * @author LevelX2 */ public class FuryOfTheHorde extends CardImpl { - + private static final FilterCard filter = new FilterCard("two red cards"); static { @@ -68,15 +68,14 @@ public class FuryOfTheHorde extends CardImpl { super(ownerId, 81, "Fury of the Horde", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{5}{R}{R}"); this.expansionSetCode = "CSP"; - // You may exile two red cards from your hand rather than pay Fury of the Horde's mana cost. this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(2, filter)))); - + // Untap all creatures that attacked this turn. After this main phase, there is an additional combat phase followed by an additional main phase. this.getSpellAbility().addEffect(new FuryOfTheHordeUntapEffect()); this.getSpellAbility().addEffect(new FuryOfTheHordeAddPhasesEffect()); this.getSpellAbility().addWatcher(new AttackedThisTurnWatcher()); - + } public FuryOfTheHorde(final FuryOfTheHorde card) { @@ -89,7 +88,6 @@ public class FuryOfTheHorde extends CardImpl { } } - class FuryOfTheHordeUntapEffect extends OneShotEffect { public FuryOfTheHordeUntapEffect() { @@ -110,7 +108,7 @@ class FuryOfTheHordeUntapEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Watcher watcher = game.getState().getWatchers().get("AttackedThisTurn"); if (watcher != null && watcher instanceof AttackedThisTurnWatcher) { - Set attackedThisTurn = ((AttackedThisTurnWatcher)watcher).getAttackedThisTurnCreatures(); + Set attackedThisTurn = ((AttackedThisTurnWatcher) watcher).getAttackedThisTurnCreatures(); for (UUID uuid : attackedThisTurn) { Permanent permanent = game.getPermanent(uuid); if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) { @@ -141,21 +139,19 @@ class FuryOfTheHordeAddPhasesEffect extends OneShotEffect { } @Override - public boolean apply(Game game, Ability source) { + public boolean apply(Game game, Ability source) { // 15.07.2006 If it's somehow not a main phase when Fury of the Horde resolves, all it does is untap all creatures that attacked that turn. No new phases are created. - if (TurnPhase.PRECOMBAT_MAIN.equals(game.getTurn().getPhaseType()) - || TurnPhase.POSTCOMBAT_MAIN.equals(game.getTurn().getPhaseType()) ) { + if (TurnPhase.PRECOMBAT_MAIN.equals(game.getTurn().getPhaseType()) + || TurnPhase.POSTCOMBAT_MAIN.equals(game.getTurn().getPhaseType())) { // we can't add two turn modes at once, will add additional post combat on delayed trigger resolution TurnMod combat = new TurnMod(source.getControllerId(), TurnPhase.COMBAT, TurnPhase.POSTCOMBAT_MAIN, false); game.getState().getTurnMods().add(combat); DelayedAddMainPhaseAbility delayedTriggeredAbility = new DelayedAddMainPhaseAbility(); - delayedTriggeredAbility.setSourceId(source.getSourceId()); - delayedTriggeredAbility.setControllerId(source.getControllerId()); delayedTriggeredAbility.setConnectedTurnMod(combat.getId()); - game.addDelayedTriggeredAbility(delayedTriggeredAbility); + game.addDelayedTriggeredAbility(delayedTriggeredAbility, source); return true; } - return false; + return false; } } @@ -164,7 +160,7 @@ class DelayedAddMainPhaseAbility extends DelayedTriggeredAbility { private UUID connectedTurnMod; private boolean enabled; - + public DelayedAddMainPhaseAbility() { super(null, Duration.EndOfTurn); this.usesStack = false; // don't show this to the user diff --git a/Mage.Sets/src/mage/sets/coldsnap/JotunGrunt.java b/Mage.Sets/src/mage/sets/coldsnap/JotunGrunt.java index ca95f1ef5f2..26e3e435bd7 100644 --- a/Mage.Sets/src/mage/sets/coldsnap/JotunGrunt.java +++ b/Mage.Sets/src/mage/sets/coldsnap/JotunGrunt.java @@ -30,6 +30,7 @@ package mage.sets.coldsnap; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.keyword.CumulativeUpkeepAbility; import mage.cards.Card; @@ -84,7 +85,7 @@ class JotunGruntCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { if (targets.choose(Outcome.Removal, controllerId, sourceId, game)) { diff --git a/Mage.Sets/src/mage/sets/coldsnap/ShelteringAncient.java b/Mage.Sets/src/mage/sets/coldsnap/ShelteringAncient.java index bd90329ff42..51c59336e95 100644 --- a/Mage.Sets/src/mage/sets/coldsnap/ShelteringAncient.java +++ b/Mage.Sets/src/mage/sets/coldsnap/ShelteringAncient.java @@ -30,6 +30,7 @@ package mage.sets.coldsnap; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.keyword.CumulativeUpkeepAbility; import mage.abilities.keyword.TrampleAbility; @@ -89,7 +90,7 @@ class ShelteringAncientCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { Target target = new TargetCreaturePermanent(1, 1, filter, true); diff --git a/Mage.Sets/src/mage/sets/commander/AllianceOfArms.java b/Mage.Sets/src/mage/sets/commander/AllianceOfArms.java index a9a20017a44..107b3b3d4bc 100644 --- a/Mage.Sets/src/mage/sets/commander/AllianceOfArms.java +++ b/Mage.Sets/src/mage/sets/commander/AllianceOfArms.java @@ -121,7 +121,7 @@ class AllianceOfArmsEffect extends OneShotEffect { xValue = player.announceXMana(0, Integer.MAX_VALUE, "How much mana will you pay?", game, source); if (xValue > 0) { Cost cost = new GenericManaCost(xValue); - payed = cost.pay(source, game, source.getSourceId(), player.getId(), false); + payed = cost.pay(source, game, source.getSourceId(), player.getId(), false, null); } else { payed = true; } diff --git a/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java b/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java index 4875d2aca7e..cf9c47623f3 100644 --- a/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java +++ b/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java @@ -147,7 +147,7 @@ class ChorusOfTheConclaveReplacementEffect extends ReplacementEffectImpl { xValue = player.announceXMana(0, Integer.MAX_VALUE, "How much mana will you pay?", game, source); if (xValue > 0) { Cost cost = new GenericManaCost(xValue); - payed = cost.pay(source, game, source.getSourceId(), player.getId(), false); + payed = cost.pay(source, game, source.getSourceId(), player.getId(), false, null); } else { payed = true; } diff --git a/Mage.Sets/src/mage/sets/commander/CollectiveVoyage.java b/Mage.Sets/src/mage/sets/commander/CollectiveVoyage.java index 4c90f57ebc3..b0a485f4df8 100644 --- a/Mage.Sets/src/mage/sets/commander/CollectiveVoyage.java +++ b/Mage.Sets/src/mage/sets/commander/CollectiveVoyage.java @@ -130,7 +130,7 @@ class CollectiveVoyageEffect extends OneShotEffect { xValue = player.announceXMana(0, Integer.MAX_VALUE, "How much mana will you pay?", game, source); if (xValue > 0) { Cost cost = new GenericManaCost(xValue); - payed = cost.pay(source, game, source.getSourceId(), player.getId(), false); + payed = cost.pay(source, game, source.getSourceId(), player.getId(), false, null); } else { payed = true; } diff --git a/Mage.Sets/src/mage/sets/commander/ManaChargedDragon.java b/Mage.Sets/src/mage/sets/commander/ManaChargedDragon.java index e12f2e8cbc0..81a21388da1 100644 --- a/Mage.Sets/src/mage/sets/commander/ManaChargedDragon.java +++ b/Mage.Sets/src/mage/sets/commander/ManaChargedDragon.java @@ -100,7 +100,7 @@ class ManaChargedDragonEffect extends OneShotEffect { xValue = player.announceXMana(0, Integer.MAX_VALUE, "How much mana will you pay?", game, source); if (xValue > 0) { Cost cost = new GenericManaCost(xValue); - payed = cost.pay(source, game, source.getSourceId(), player.getId(), false); + payed = cost.pay(source, game, source.getSourceId(), player.getId(), false, null); } else { payed = true; } diff --git a/Mage.Sets/src/mage/sets/commander/MindsAglow.java b/Mage.Sets/src/mage/sets/commander/MindsAglow.java index 5ba8d8bf439..70fb1b32591 100644 --- a/Mage.Sets/src/mage/sets/commander/MindsAglow.java +++ b/Mage.Sets/src/mage/sets/commander/MindsAglow.java @@ -119,7 +119,7 @@ class MindsAglowEffect extends OneShotEffect { xValue = player.announceXMana(0, Integer.MAX_VALUE, "How much mana will you pay?", game, source); if (xValue > 0) { Cost cost = new GenericManaCost(xValue); - payed = cost.pay(source, game, source.getSourceId(), player.getId(), false); + payed = cost.pay(source, game, source.getSourceId(), player.getId(), false, null); } else { payed = true; } diff --git a/Mage.Sets/src/mage/sets/commander/ScatteringStroke.java b/Mage.Sets/src/mage/sets/commander/ScatteringStroke.java index 7f7cdd7bccc..4e491d8a051 100644 --- a/Mage.Sets/src/mage/sets/commander/ScatteringStroke.java +++ b/Mage.Sets/src/mage/sets/commander/ScatteringStroke.java @@ -55,7 +55,6 @@ public class ScatteringStroke extends CardImpl { super(ownerId, 60, "Scattering Stroke", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{2}{U}{U}"); this.expansionSetCode = "CMD"; - // Counter target spell. Clash with an opponent. If you win, at the beginning of your next main phase, you may add {X} to your mana pool, where X is that spell's converted mana cost. this.getSpellAbility().addEffect(new ScatteringStrokeEffect()); this.getSpellAbility().addTarget(new TargetSpell()); @@ -71,7 +70,6 @@ public class ScatteringStroke extends CardImpl { } } - class ScatteringStrokeEffect extends OneShotEffect { public ScatteringStrokeEffect() { @@ -95,16 +93,13 @@ class ScatteringStrokeEffect extends OneShotEffect { if (controller != null && spell != null) { game.getStack().counter(spell.getId(), source.getSourceId(), game); if (ClashEffect.getInstance().apply(game, source)) { - Effect effect = new AddManaToManaPoolSourceControllerEffect(new Mana(0,0,0,0,0,spell.getConvertedManaCost(),0)); - AtTheBeginOfMainPhaseDelayedTriggeredAbility delayedAbility = - new AtTheBeginOfMainPhaseDelayedTriggeredAbility(effect, true, TargetController.YOU, AtTheBeginOfMainPhaseDelayedTriggeredAbility.PhaseSelection.NEXT_MAIN); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + Effect effect = new AddManaToManaPoolSourceControllerEffect(new Mana(0, 0, 0, 0, 0, 0, 0, spell.getConvertedManaCost())); + AtTheBeginOfMainPhaseDelayedTriggeredAbility delayedAbility + = new AtTheBeginOfMainPhaseDelayedTriggeredAbility(effect, true, TargetController.YOU, AtTheBeginOfMainPhaseDelayedTriggeredAbility.PhaseSelection.NEXT_MAIN); + game.addDelayedTriggeredAbility(delayedAbility, source); } return true; } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/commander/SharedTrauma.java b/Mage.Sets/src/mage/sets/commander/SharedTrauma.java index 79656863cff..b26fa0f05a3 100644 --- a/Mage.Sets/src/mage/sets/commander/SharedTrauma.java +++ b/Mage.Sets/src/mage/sets/commander/SharedTrauma.java @@ -120,7 +120,7 @@ class SharedTraumaEffect extends OneShotEffect { xValue = player.announceXMana(0, Integer.MAX_VALUE, "How much mana will you pay?", game, source); if (xValue > 0) { Cost cost = new GenericManaCost(xValue); - payed = cost.pay(source, game, source.getSourceId(), player.getId(), false); + payed = cost.pay(source, game, source.getSourceId(), player.getId(), false, null); } else { payed = true; } diff --git a/Mage.Sets/src/mage/sets/commander/VishKalBloodArbiter.java b/Mage.Sets/src/mage/sets/commander/VishKalBloodArbiter.java index 6e994197804..521799d7d47 100644 --- a/Mage.Sets/src/mage/sets/commander/VishKalBloodArbiter.java +++ b/Mage.Sets/src/mage/sets/commander/VishKalBloodArbiter.java @@ -120,7 +120,7 @@ class VishKalBloodArbiterCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { this.amount = permanent.getCounters().getCount(name); diff --git a/Mage.Sets/src/mage/sets/commander2013/ArcaneDenial.java b/Mage.Sets/src/mage/sets/commander2013/ArcaneDenial.java index 77a024adf5c..9b989a928f2 100644 --- a/Mage.Sets/src/mage/sets/commander2013/ArcaneDenial.java +++ b/Mage.Sets/src/mage/sets/commander2013/ArcaneDenial.java @@ -56,12 +56,11 @@ public class ArcaneDenial extends CardImpl { super(ownerId, 28, "Arcane Denial", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{U}"); this.expansionSetCode = "C13"; - // Counter target spell. Its controller may draw up to two cards at the beginning of the next turn's upkeep. this.getSpellAbility().addEffect(new ArcaneDenialEffect()); this.getSpellAbility().addTarget(new TargetSpell()); // You draw a card at the beginning of the next turn's upkeep. - this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)),false)); + this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false)); } public ArcaneDenial(final ArcaneDenial card) { @@ -78,7 +77,7 @@ class ArcaneDenialEffect extends OneShotEffect { public ArcaneDenialEffect() { super(Outcome.Detriment); - staticText ="Counter target spell. Its controller may draw up to two cards at the beginning of the next turn's upkeep"; + staticText = "Counter target spell. Its controller may draw up to two cards at the beginning of the next turn's upkeep"; } public ArcaneDenialEffect(final ArcaneDenialEffect effect) { @@ -107,9 +106,7 @@ class ArcaneDenialEffect extends OneShotEffect { effect.setTargetPointer(new FixedTarget(controller.getId())); effect.setText("Its controller may draw up to two cards"); DelayedTriggeredAbility ability = new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(effect); - ability.setSourceId(source.getSourceId()); - ability.setControllerId(controller.getId()); - game.addDelayedTriggeredAbility(ability); + game.addDelayedTriggeredAbility(ability, source); } return countered; } diff --git a/Mage.Sets/src/mage/sets/commander2013/Flickerform.java b/Mage.Sets/src/mage/sets/commander2013/Flickerform.java index f7dcc78fdaa..de4e89b9954 100644 --- a/Mage.Sets/src/mage/sets/commander2013/Flickerform.java +++ b/Mage.Sets/src/mage/sets/commander2013/Flickerform.java @@ -37,8 +37,6 @@ import mage.abilities.effects.common.AttachEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.Card; import mage.cards.CardImpl; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; @@ -67,7 +65,6 @@ public class Flickerform extends CardImpl { this.expansionSetCode = "C13"; this.subtype.add("Aura"); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); @@ -92,6 +89,7 @@ public class Flickerform extends CardImpl { class FlickerformEffect extends OneShotEffect { private static final FilterEnchantmentPermanent filter = new FilterEnchantmentPermanent(); + static { filter.add(new SubtypePredicate("Aura")); } @@ -122,7 +120,7 @@ class FlickerformEffect extends OneShotEffect { if (enchantedCreature != null) { UUID exileZoneId = UUID.randomUUID(); enchantedCreature.moveToExile(exileZoneId, enchantment.getName(), source.getSourceId(), game); - for (UUID attachementId: enchantedCreature.getAttachments()) { + for (UUID attachementId : enchantedCreature.getAttachments()) { Permanent attachment = game.getPermanent(attachementId); if (attachment != null && filter.match(attachment, game)) { attachment.moveToExile(exileZoneId, enchantment.getName(), source.getSourceId(), game); @@ -130,13 +128,10 @@ class FlickerformEffect extends OneShotEffect { } if (!(enchantedCreature instanceof Token)) { // At the beginning of the next end step, return that card to the battlefield under its owner's control. - // If you do, return the other cards exiled this way to the battlefield under their owners' control attached to that creature + // If you do, return the other cards exiled this way to the battlefield under their owners' control attached to that creature AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility( new FlickerformReturnEffect(enchantedCreature.getId(), exileZoneId)); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } return true; } @@ -149,6 +144,7 @@ class FlickerformEffect extends OneShotEffect { class FlickerformReturnEffect extends OneShotEffect { private static final FilterCard filterAura = new FilterCard(); + static { filterAura.add(new CardTypePredicate(CardType.ENCHANTMENT)); filterAura.add(new SubtypePredicate("Aura")); @@ -183,7 +179,7 @@ class FlickerformReturnEffect extends OneShotEffect { enchantedCard.putOntoBattlefield(game, Zone.EXILED, source.getSourceId(), enchantedCard.getOwnerId()); Permanent newPermanent = game.getPermanent(enchantedCardId); if (newPermanent != null) { - for(Card enchantment : exileZone.getCards(game)) { + for (Card enchantment : exileZone.getCards(game)) { if (filterAura.match(enchantment, game)) { boolean canTarget = false; for (Target target : enchantment.getSpellAbility().getTargets()) { diff --git a/Mage.Sets/src/mage/sets/commander2013/IllusionistsGambit.java b/Mage.Sets/src/mage/sets/commander2013/IllusionistsGambit.java index 255153050b7..f3ab23dea4e 100644 --- a/Mage.Sets/src/mage/sets/commander2013/IllusionistsGambit.java +++ b/Mage.Sets/src/mage/sets/commander2013/IllusionistsGambit.java @@ -30,9 +30,9 @@ package mage.sets.commander2013; import java.util.List; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.OnOpponentsTurnCondition; import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.RestrictionEffect; @@ -43,9 +43,7 @@ import mage.constants.Outcome; import mage.constants.PhaseStep; import mage.constants.Rarity; import mage.constants.TurnPhase; -import mage.constants.Zone; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.turn.Phase; import mage.game.turn.TurnMod; @@ -60,11 +58,9 @@ public class IllusionistsGambit extends CardImpl { super(ownerId, 47, "Illusionist's Gambit", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{2}{U}{U}"); this.expansionSetCode = "C13"; - // Cast Illusionist's Gambit only during the declare blockers step on an opponent's turn. - Ability ability = new SimpleStaticAbility(Zone.ALL, new IllusionistsGambitEffect()); - ability.setRuleAtTheTop(true); - this.addAbility(ability); + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(PhaseStep.DECLARE_BLOCKERS, OnOpponentsTurnCondition.getInstance())); + // Remove all attacking creatures from combat and untap them. After this phase, there is an additional combat phase. Each of those creatures attacks that combat if able. They can't attack you or a planeswalker you control that combat. this.getSpellAbility().addEffect(new IllusionistsGambitRemoveFromCombatEffect()); } @@ -79,38 +75,6 @@ public class IllusionistsGambit extends CardImpl { } } -class IllusionistsGambitEffect extends ContinuousRuleModifyingEffectImpl { - IllusionistsGambitEffect() { - super(Duration.EndOfGame, Outcome.Detriment); - staticText = "Cast {this} only during the declare blockers step on an opponent's turn"; - } - - IllusionistsGambitEffect(final IllusionistsGambitEffect effect) { - super(effect); - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType().equals(GameEvent.EventType.CAST_SPELL) && event.getSourceId().equals(source.getSourceId())) { - if (game.getTurn().getStepType().equals(PhaseStep.DECLARE_BLOCKERS)) { - return !game.getOpponents(source.getControllerId()).contains(game.getActivePlayerId()); - } - return true; - } - return false; - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public IllusionistsGambitEffect copy() { - return new IllusionistsGambitEffect(this); - } -} - class IllusionistsGambitRemoveFromCombatEffect extends OneShotEffect { public IllusionistsGambitRemoveFromCombatEffect() { @@ -130,7 +94,7 @@ class IllusionistsGambitRemoveFromCombatEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { List attackers = game.getCombat().getAttackers(); - for (UUID attackerId :attackers) { + for (UUID attackerId : attackers) { Permanent creature = game.getPermanent(attackerId); if (creature != null) { creature.removeFromCombat(game); @@ -237,13 +201,13 @@ class IllusionistsGambitRestrictionEffect extends RestrictionEffect { @Override public boolean canAttack(UUID defenderId, Ability source, Game game) { - if (defenderId.equals(source.getControllerId()) ) { + if (defenderId.equals(source.getControllerId())) { return false; } // planeswalker Permanent permanent = game.getPermanent(defenderId); if (permanent != null && permanent.getControllerId().equals(source.getControllerId()) - && permanent.getCardType().contains(CardType.PLANESWALKER)) { + && permanent.getCardType().contains(CardType.PLANESWALKER)) { return false; } return true; diff --git a/Mage.Sets/src/mage/sets/commander2013/MarathWillOfTheWild.java b/Mage.Sets/src/mage/sets/commander2013/MarathWillOfTheWild.java index 0b2662bd6cd..8d5f011877e 100644 --- a/Mage.Sets/src/mage/sets/commander2013/MarathWillOfTheWild.java +++ b/Mage.Sets/src/mage/sets/commander2013/MarathWillOfTheWild.java @@ -57,6 +57,7 @@ import mage.target.common.TargetCreatureOrPlayer; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; +import mage.abilities.costs.Cost; /** * @@ -200,7 +201,7 @@ class MarathWillOfTheWildRemoveCountersCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { int amount = new ManacostVariableValue().calculate(game, ability, null); Permanent permanent = game.getPermanent(sourceId); if (permanent != null && permanent.getCounters().getCount(CounterType.P1P1) >= amount) { diff --git a/Mage.Sets/src/mage/sets/commander2013/Reincarnation.java b/Mage.Sets/src/mage/sets/commander2013/Reincarnation.java index 2afdb2d69b1..2012423cf09 100644 --- a/Mage.Sets/src/mage/sets/commander2013/Reincarnation.java +++ b/Mage.Sets/src/mage/sets/commander2013/Reincarnation.java @@ -60,7 +60,6 @@ public class Reincarnation extends CardImpl { super(ownerId, 166, "Reincarnation", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{1}{G}{G}"); this.expansionSetCode = "C13"; - // Choose target creature. When that creature dies this turn, return a creature card from its owner's graveyard to the battlefield under the control of that creature's owner. this.getSpellAbility().addEffect(new ReincarnationEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); @@ -95,10 +94,7 @@ class ReincarnationEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { DelayedTriggeredAbility delayedAbility = new ReincarnationDelayedTriggeredAbility(targetPointer.getFirst(game, source)); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } } @@ -175,7 +171,7 @@ class ReincarnationDelayedEffect extends OneShotEffect { filter.add(new OwnerIdPredicate(player.getId())); Target targetCreature = new TargetCardInGraveyard(filter); if (targetCreature.canChoose(source.getSourceId(), controller.getId(), game) - && controller.chooseTarget(outcome, targetCreature, source, game)) { + && controller.chooseTarget(outcome, targetCreature, source, game)) { Card card = game.getCard(targetCreature.getFirstTarget()); if (card != null && game.getState().getZone(card.getId()).equals(Zone.GRAVEYARD)) { return card.putOntoBattlefield(game, Zone.GRAVEYARD, source.getSourceId(), player.getId()); diff --git a/Mage.Sets/src/mage/sets/commander2013/RoonOfTheHiddenRealm.java b/Mage.Sets/src/mage/sets/commander2013/RoonOfTheHiddenRealm.java index 1228928f8ae..0ac5d0f24f7 100644 --- a/Mage.Sets/src/mage/sets/commander2013/RoonOfTheHiddenRealm.java +++ b/Mage.Sets/src/mage/sets/commander2013/RoonOfTheHiddenRealm.java @@ -35,11 +35,11 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; 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.ReturnFromExileEffect; +import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.VigilanceAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -51,6 +51,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; /** * @@ -59,6 +60,7 @@ import mage.target.common.TargetCreaturePermanent; public class RoonOfTheHiddenRealm extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); + static { filter.add(new AnotherPredicate()); } @@ -118,22 +120,19 @@ class RoonOfTheHiddenRealmEffect extends OneShotEffect { if (controller != null && sourceObject != null) { if (getTargetPointer().getFirst(game, source) != null) { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (permanent != null) { - UUID exileId = UUID.randomUUID(); - if (controller.moveCardToExileWithInfo(permanent, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true)) { - if (card != null) { - AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnFromExileEffect(exileId, Zone.BATTLEFIELD)); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(card.getOwnerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); - } + int zcc = permanent.getZoneChangeCounter(game); + if (controller.moveCards(permanent, Zone.EXILED, source, game)) { + Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(); + effect.setTargetPointer(new FixedTarget(permanent.getId(), zcc + 1)); + AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility + = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); + game.addDelayedTriggeredAbility(delayedAbility, source); } } - } + } return true; - } + } return false; } } diff --git a/Mage.Sets/src/mage/sets/commander2013/SpringjackPasture.java b/Mage.Sets/src/mage/sets/commander2013/SpringjackPasture.java index dd13a0d9b80..7d443677289 100644 --- a/Mage.Sets/src/mage/sets/commander2013/SpringjackPasture.java +++ b/Mage.Sets/src/mage/sets/commander2013/SpringjackPasture.java @@ -115,15 +115,15 @@ class SpringjackPastureEffect extends OneShotEffect { if (you != null && choice != null) { int count = new GetXValue().calculate(game, source, this); if (choice.getColor().isBlack()) { - you.getManaPool().addMana(new Mana(0, 0, 0, 0, count, 0, 0), game, source); + you.getManaPool().addMana(new Mana(0, 0, 0, 0, count, 0, 0, 0), game, source); } else if (choice.getColor().isBlue()) { - you.getManaPool().addMana(new Mana(0, 0, count, 0, 0, 0, 0), game, source); + you.getManaPool().addMana(new Mana(0, 0, count, 0, 0, 0, 0, 0), game, source); } else if (choice.getColor().isRed()) { - you.getManaPool().addMana(new Mana(count, 0, 0, 0, 0, 0, 0), game, source); + you.getManaPool().addMana(new Mana(count, 0, 0, 0, 0, 0, 0, 0), game, source); } else if (choice.getColor().isGreen()) { - you.getManaPool().addMana(new Mana(0, count, 0, 0, 0, 0, 0), game, source); + you.getManaPool().addMana(new Mana(0, count, 0, 0, 0, 0, 0, 0), game, source); } else if (choice.getColor().isWhite()) { - you.getManaPool().addMana(new Mana(0, 0, 0, count, 0, 0, 0), game, source); + you.getManaPool().addMana(new Mana(0, 0, 0, count, 0, 0, 0, 0), game, source); } return true; diff --git a/Mage.Sets/src/mage/sets/commander2014/CoralAtoll.java b/Mage.Sets/src/mage/sets/commander2014/CoralAtoll.java index 6d16e8d86f3..64ce9d767bf 100644 --- a/Mage.Sets/src/mage/sets/commander2014/CoralAtoll.java +++ b/Mage.Sets/src/mage/sets/commander2014/CoralAtoll.java @@ -53,12 +53,11 @@ public class CoralAtoll extends CardImpl { private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent("an untapped Island"); - static{ + static { filter.add(new SubtypePredicate("Island")); filter.add(Predicates.not(new TappedPredicate())); } - public CoralAtoll(UUID ownerId) { super(ownerId, 287, "Coral Atoll", Rarity.UNCOMMON, new CardType[]{CardType.LAND}, ""); this.expansionSetCode = "C14"; @@ -68,9 +67,8 @@ public class CoralAtoll extends CardImpl { // When Coral Atoll enters the battlefield, sacrifice it unless you return an untapped Island you control to its owner's hand. this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(filter))))); // {tap}: Add {C}{U} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 0, 0, 1,0 ), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 0, 0, 0, 0, 1), new TapSourceCost())); - } public CoralAtoll(final CoralAtoll card) { diff --git a/Mage.Sets/src/mage/sets/commander2014/DormantVolcano.java b/Mage.Sets/src/mage/sets/commander2014/DormantVolcano.java index 67d9a874e6c..7302e4d58d8 100644 --- a/Mage.Sets/src/mage/sets/commander2014/DormantVolcano.java +++ b/Mage.Sets/src/mage/sets/commander2014/DormantVolcano.java @@ -53,7 +53,7 @@ public class DormantVolcano extends CardImpl { private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent("an untapped Mountain"); - static{ + static { filter.add(new SubtypePredicate("Mountain")); filter.add(Predicates.not(new TappedPredicate())); } @@ -69,7 +69,7 @@ public class DormantVolcano extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(filter))))); // {tap}: Add {C}{R} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 0, 0, 1,0 ), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 0, 0, 0, 0, 1), new TapSourceCost())); } diff --git a/Mage.Sets/src/mage/sets/commander2014/Everglades.java b/Mage.Sets/src/mage/sets/commander2014/Everglades.java index f85a283357a..57054b36d58 100644 --- a/Mage.Sets/src/mage/sets/commander2014/Everglades.java +++ b/Mage.Sets/src/mage/sets/commander2014/Everglades.java @@ -69,7 +69,7 @@ public class Everglades extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(1, 1, filter, true))))); // {tap}: Add {C}{B} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 0, 1, 1, 0), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 0, 0, 1, 0, 1), new TapSourceCost())); } diff --git a/Mage.Sets/src/mage/sets/commander2014/FeldonOfTheThirdPath.java b/Mage.Sets/src/mage/sets/commander2014/FeldonOfTheThirdPath.java index 77840101add..61a013653cc 100644 --- a/Mage.Sets/src/mage/sets/commander2014/FeldonOfTheThirdPath.java +++ b/Mage.Sets/src/mage/sets/commander2014/FeldonOfTheThirdPath.java @@ -110,10 +110,7 @@ class FeldonOfTheThirdPathEffect extends OneShotEffect { SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("Sacrifice the token at the beginning of the next end step", source.getControllerId()); sacrificeEffect.setTargetPointer(new FixedTarget(addedToken, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } return true; } diff --git a/Mage.Sets/src/mage/sets/commander2014/JungleBasin.java b/Mage.Sets/src/mage/sets/commander2014/JungleBasin.java index b64f47cee8b..21e1b907010 100644 --- a/Mage.Sets/src/mage/sets/commander2014/JungleBasin.java +++ b/Mage.Sets/src/mage/sets/commander2014/JungleBasin.java @@ -53,7 +53,7 @@ public class JungleBasin extends CardImpl { private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent("an untapped Forest"); - static{ + static { filter.add(new SubtypePredicate("Forest")); filter.add(Predicates.not(new TappedPredicate())); } @@ -69,8 +69,8 @@ public class JungleBasin extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(filter))))); // {tap}: Add {C}{G} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 0, 0, 1,0 ), new TapSourceCost())); - + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 0, 0, 0, 0, 1), new TapSourceCost())); + } public JungleBasin(final JungleBasin card) { diff --git a/Mage.Sets/src/mage/sets/commander2014/Karoo.java b/Mage.Sets/src/mage/sets/commander2014/Karoo.java index 319a92cb888..bf5581edc3b 100644 --- a/Mage.Sets/src/mage/sets/commander2014/Karoo.java +++ b/Mage.Sets/src/mage/sets/commander2014/Karoo.java @@ -53,7 +53,7 @@ public class Karoo extends CardImpl { private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent("an untapped Plains"); - static{ + static { filter.add(new SubtypePredicate("Plains")); filter.add(Predicates.not(new TappedPredicate())); } @@ -69,7 +69,7 @@ public class Karoo extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(filter))))); // {tap}: Add {C}{W} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 1, 0, 1,0 ), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 1, 0, 0, 0, 1), new TapSourceCost())); } diff --git a/Mage.Sets/src/mage/sets/commander2014/WakeTheDead.java b/Mage.Sets/src/mage/sets/commander2014/WakeTheDead.java index eb7e9438ae7..ba2ec303f92 100644 --- a/Mage.Sets/src/mage/sets/commander2014/WakeTheDead.java +++ b/Mage.Sets/src/mage/sets/commander2014/WakeTheDead.java @@ -27,13 +27,14 @@ */ package mage.sets.commander2014; +import java.util.ArrayList; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.SpellAbility; -import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; -import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.condition.common.OnOpponentsTurnCondition; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.SacrificeTargetEffect; @@ -41,18 +42,16 @@ import mage.cards.CardImpl; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.TurnPhase; import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; -import mage.target.targetpointer.FixedTarget; +import mage.target.targetpointer.FixedTargets; /** * @@ -65,9 +64,7 @@ public class WakeTheDead extends CardImpl { this.expansionSetCode = "C14"; // Cast Wake the Dead only during combat on an opponent's turn. - Ability ability = new SimpleStaticAbility(Zone.ALL, new WakeTheDeadEffect()); - ability.setRuleAtTheTop(true); - this.addAbility(ability); + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(TurnPhase.COMBAT, OnOpponentsTurnCondition.getInstance())); // Return X target creature cards from your graveyard to the battlefield. Sacrifice those creatures at the beginning of the next end step. this.getSpellAbility().addEffect(new WakeTheDeadReturnFromGraveyardToBattlefieldTargetEffect()); @@ -93,44 +90,6 @@ public class WakeTheDead extends CardImpl { } } -class WakeTheDeadEffect extends ContinuousRuleModifyingEffectImpl { - - WakeTheDeadEffect() { - super(Duration.EndOfGame, Outcome.Detriment); - staticText = "Cast {this} only during combat on an opponent's turn"; - } - - WakeTheDeadEffect(final WakeTheDeadEffect effect) { - super(effect); - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.CAST_SPELL; - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getSourceId().equals(source.getSourceId())) { - if (game.getPhase().getType().equals(TurnPhase.COMBAT)) { - return !game.getOpponents(source.getControllerId()).contains(game.getActivePlayerId()); - } - return true; - } - return false; - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public WakeTheDeadEffect copy() { - return new WakeTheDeadEffect(this); - } -} - class WakeTheDeadReturnFromGraveyardToBattlefieldTargetEffect extends OneShotEffect { public WakeTheDeadReturnFromGraveyardToBattlefieldTargetEffect() { @@ -153,19 +112,18 @@ class WakeTheDeadReturnFromGraveyardToBattlefieldTargetEffect extends OneShotEff if (controller != null) { Cards cards = new CardsImpl(getTargetPointer().getTargets(game, source)); controller.moveCards(cards, Zone.BATTLEFIELD, source, game); + ArrayList toSacrifice = new ArrayList<>(cards.size()); for (UUID targetId : cards) { Permanent creature = game.getPermanent(targetId); if (creature != null) { - Effect effect = new SacrificeTargetEffect("Sacrifice those creatures at the beginning of the next end step", source.getControllerId()); - effect.setTargetPointer(new FixedTarget(creature, game)); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + toSacrifice.add(creature); } } + Effect effect = new SacrificeTargetEffect("Sacrifice those creatures at the beginning of the next end step", source.getControllerId()); + effect.setTargetPointer(new FixedTargets(toSacrifice, game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/commander2015/GreatOakGuardian.java b/Mage.Sets/src/mage/sets/commander2015/GreatOakGuardian.java index 3ed072bed0c..53a1d2bf17d 100644 --- a/Mage.Sets/src/mage/sets/commander2015/GreatOakGuardian.java +++ b/Mage.Sets/src/mage/sets/commander2015/GreatOakGuardian.java @@ -35,6 +35,7 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.ReachAbility; import mage.cards.CardImpl; @@ -47,6 +48,7 @@ import mage.constants.SubLayer; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.players.Player; import mage.target.TargetPlayer; /** @@ -64,12 +66,13 @@ public class GreatOakGuardian extends CardImpl { // Flash this.addAbility(FlashAbility.getInstance()); - + // Reach this.addAbility(ReachAbility.getInstance()); - + // When Great Oak Guardian enters the battlefield, creatures target player controls get +2/+2 until end of turn. Untap them. Ability ability = new EntersBattlefieldTriggeredAbility(new GreatOakGuardianEffect(), false); + ability.addEffect(new GreatOakGuardianUntapEffect()); ability.addTarget(new TargetPlayer()); this.addAbility(ability); } @@ -118,7 +121,6 @@ class GreatOakGuardianEffect extends ContinuousEffectImpl { if (permanent != null) { permanent.addPower(2); permanent.addToughness(2); - permanent.untap(game); } else { it.remove(); } @@ -126,3 +128,32 @@ class GreatOakGuardianEffect extends ContinuousEffectImpl { return true; } } + +class GreatOakGuardianUntapEffect extends OneShotEffect { + + public GreatOakGuardianUntapEffect() { + super(Outcome.Benefit); + this.staticText = "untap them"; + } + + public GreatOakGuardianUntapEffect(final GreatOakGuardianUntapEffect effect) { + super(effect); + } + + @Override + public GreatOakGuardianUntapEffect copy() { + return new GreatOakGuardianUntapEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player targetPlayer = game.getPlayer(source.getControllerId()); + if (targetPlayer != null) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), targetPlayer.getId(), game)) { + permanent.untap(game); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/commander2015/MirrorMatch.java b/Mage.Sets/src/mage/sets/commander2015/MirrorMatch.java index dcff7fbe257..50a45aec65d 100644 --- a/Mage.Sets/src/mage/sets/commander2015/MirrorMatch.java +++ b/Mage.Sets/src/mage/sets/commander2015/MirrorMatch.java @@ -29,25 +29,22 @@ package mage.sets.commander2015; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; -import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.PutTokenOntoBattlefieldCopyTargetEffect; import mage.cards.CardImpl; import mage.constants.CardType; -import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.PhaseStep; import mage.constants.Rarity; -import mage.constants.Zone; import mage.game.Game; import mage.game.combat.CombatGroup; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.targetpointer.FixedTarget; +import mage.target.targetpointer.FixedTargets; /** * @@ -60,9 +57,7 @@ public class MirrorMatch extends CardImpl { this.expansionSetCode = "C15"; // Cast Mirror Match only during the declare blockers step. - Ability ability = new SimpleStaticAbility(Zone.ALL, new MirrorMatchRuleModifyingEffect()); - ability.setRuleAtTheTop(true); - this.addAbility(ability); + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(PhaseStep.DECLARE_BLOCKERS)); // For each creature attacking you or a planeswalker you control, put a token that's a copy of that creature onto the battlefield blocking that creature. Exile those tokens at end of combat. this.getSpellAbility().addEffect(new MirrorMatchEffect()); @@ -79,41 +74,6 @@ public class MirrorMatch extends CardImpl { } } -class MirrorMatchRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl { - - MirrorMatchRuleModifyingEffect() { - super(Duration.EndOfGame, Outcome.Detriment); - staticText = "Cast {this} only during the declare blockers step"; - } - - MirrorMatchRuleModifyingEffect(final MirrorMatchRuleModifyingEffect effect) { - super(effect); - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return GameEvent.EventType.CAST_SPELL.equals(event.getType()); - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getSourceId().equals(source.getSourceId())) { - return !game.getTurn().getStepType().equals(PhaseStep.DECLARE_BLOCKERS); - } - return false; - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public MirrorMatchRuleModifyingEffect copy() { - return new MirrorMatchRuleModifyingEffect(this); - } -} - class MirrorMatchEffect extends OneShotEffect { public MirrorMatchEffect() { @@ -149,10 +109,10 @@ class MirrorMatchEffect extends OneShotEffect { group.addBlockerToGroup(addedToken.getId(), attackerId, game); isCreature = true; } - ExileTargetEffect exileEffect = new ExileTargetEffect("Exile the token at end of combat"); - exileEffect.setTargetPointer(new FixedTarget(addedToken, game)); - game.addDelayedTriggeredAbility(new AtTheEndOfCombatDelayedTriggeredAbility(exileEffect), source); } + ExileTargetEffect exileEffect = new ExileTargetEffect("Exile those tokens at end of combat"); + exileEffect.setTargetPointer(new FixedTargets(effect.getAddedPermanent(), game)); + game.addDelayedTriggeredAbility(new AtTheEndOfCombatDelayedTriggeredAbility(exileEffect), source); if (isCreature) { group.pickBlockerOrder(attacker.getControllerId(), game); } diff --git a/Mage.Sets/src/mage/sets/conflux/ExoticOrchard.java b/Mage.Sets/src/mage/sets/conflux/ExoticOrchard.java index 04e515f8eff..977c34b21c3 100644 --- a/Mage.Sets/src/mage/sets/conflux/ExoticOrchard.java +++ b/Mage.Sets/src/mage/sets/conflux/ExoticOrchard.java @@ -28,10 +28,11 @@ package mage.sets.conflux; import java.util.UUID; -import mage.abilities.mana.AnyColorOpponentLandsProduceManaAbility; +import mage.abilities.mana.AnyColorLandsProduceManaAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; +import mage.constants.TargetController; /** * @@ -44,7 +45,7 @@ public class ExoticOrchard extends CardImpl { this.expansionSetCode = "CON"; // {T}: Add to your mana pool one mana of any color that a land an opponent controls could produce. - this.addAbility(new AnyColorOpponentLandsProduceManaAbility()); + this.addAbility(new AnyColorLandsProduceManaAbility(TargetController.OPPONENT)); } public ExoticOrchard(final ExoticOrchard card) { diff --git a/Mage.Sets/src/mage/sets/conflux/Kaleidostone.java b/Mage.Sets/src/mage/sets/conflux/Kaleidostone.java index b7936a0fa5a..0f16d54f870 100644 --- a/Mage.Sets/src/mage/sets/conflux/Kaleidostone.java +++ b/Mage.Sets/src/mage/sets/conflux/Kaleidostone.java @@ -54,7 +54,7 @@ public class Kaleidostone extends CardImpl { // When Kaleidostone enters the battlefield, draw a card. this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1))); // {5}, {tap}, Sacrifice Kaleidostone: Add {W}{U}{B}{R}{G} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 1, 1, 1, 0, 0), new GenericManaCost(5)); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 1, 1, 1, 0, 0, 0), new GenericManaCost(5)); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/conflux/KnotvineMystic.java b/Mage.Sets/src/mage/sets/conflux/KnotvineMystic.java index afe5461a9fa..8e45fa0aa23 100644 --- a/Mage.Sets/src/mage/sets/conflux/KnotvineMystic.java +++ b/Mage.Sets/src/mage/sets/conflux/KnotvineMystic.java @@ -75,8 +75,8 @@ public class KnotvineMystic extends CardImpl{ class KnotvineMysticManaAbility extends BasicManaAbility { public KnotvineMysticManaAbility() { - super(new BasicManaEffect(new Mana(1, 1, 0, 1, 0, 0, 0))); - this.netMana.add(new Mana(1, 1, 0, 1, 0, 0, 0)); + super(new BasicManaEffect(new Mana(1, 1, 0, 1, 0, 0, 0, 0))); + this.netMana.add(new Mana(1, 1, 0, 1, 0, 0, 0, 0)); } public KnotvineMysticManaAbility(final KnotvineMysticManaAbility ability) { diff --git a/Mage.Sets/src/mage/sets/conspiracy/Victimize.java b/Mage.Sets/src/mage/sets/conspiracy/Victimize.java index a49a512c2d3..07083fb2f41 100644 --- a/Mage.Sets/src/mage/sets/conspiracy/Victimize.java +++ b/Mage.Sets/src/mage/sets/conspiracy/Victimize.java @@ -90,7 +90,7 @@ class VictimizeEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { SacrificeTargetCost cost = new SacrificeTargetCost(new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("a creature"))); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { controller.moveCards(new CardsImpl(getTargetPointer().getTargets(game, source)).getCards(game), Zone.BATTLEFIELD, source, game, true, false, false, null); } diff --git a/Mage.Sets/src/mage/sets/darkascension/HavengulLich.java b/Mage.Sets/src/mage/sets/darkascension/HavengulLich.java index 2c0818761ef..0ca994d6c4e 100644 --- a/Mage.Sets/src/mage/sets/darkascension/HavengulLich.java +++ b/Mage.Sets/src/mage/sets/darkascension/HavengulLich.java @@ -116,9 +116,9 @@ class HavengulLichPlayEffect extends AsThoughEffectImpl { public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { UUID targetId = getTargetPointer().getFirst(game, source); if (targetId != null) { - return targetId.equals(objectId) && - source.getControllerId().equals(affectedControllerId) && - Zone.GRAVEYARD.equals(game.getState().getZone(objectId)); + return targetId.equals(objectId) + && source.getControllerId().equals(affectedControllerId) + && Zone.GRAVEYARD.equals(game.getState().getZone(objectId)); } else { // the target card has changed zone meanwhile, so the effect is no longer needed discard(); @@ -142,9 +142,7 @@ class HavengulLichPlayedEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { DelayedTriggeredAbility ability = new HavengulLichDelayedTriggeredAbility(getTargetPointer().getFirst(game, source)); - ability.setSourceId(source.getSourceId()); - ability.setControllerId(source.getControllerId()); - game.addDelayedTriggeredAbility(ability); + game.addDelayedTriggeredAbility(ability, source); return true; } @@ -160,7 +158,7 @@ class HavengulLichDelayedTriggeredAbility extends DelayedTriggeredAbility { private UUID cardId; - public HavengulLichDelayedTriggeredAbility (UUID cardId) { + public HavengulLichDelayedTriggeredAbility(UUID cardId) { super(new HavengulLichEffect(cardId), Duration.EndOfTurn); this.cardId = cardId; } @@ -216,7 +214,7 @@ class HavengulLichEffect extends ContinuousEffectImpl { Permanent permanent = game.getPermanent(source.getSourceId()); Card card = game.getCard(cardId); if (permanent != null && card != null) { - for (ActivatedAbility ability: card.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD)) { + for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD)) { permanent.addAbility(ability, source.getSourceId(), game); } } diff --git a/Mage.Sets/src/mage/sets/darkascension/JarOfEyeballs.java b/Mage.Sets/src/mage/sets/darkascension/JarOfEyeballs.java index d8a5d62eb25..bdb72be952d 100644 --- a/Mage.Sets/src/mage/sets/darkascension/JarOfEyeballs.java +++ b/Mage.Sets/src/mage/sets/darkascension/JarOfEyeballs.java @@ -145,7 +145,7 @@ class JarOfEyeballsCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(ability.getSourceId()); if (permanent != null) { this.removedCounters = permanent.getCounters().getCount(CounterType.EYEBALL); diff --git a/Mage.Sets/src/mage/sets/darkascension/LoyalCathar.java b/Mage.Sets/src/mage/sets/darkascension/LoyalCathar.java index 84eedf72fb4..65c083c681a 100644 --- a/Mage.Sets/src/mage/sets/darkascension/LoyalCathar.java +++ b/Mage.Sets/src/mage/sets/darkascension/LoyalCathar.java @@ -83,7 +83,7 @@ class LoyalCatharEffect extends OneShotEffect { private static final String effectText = "return it to the battlefield transformed under your control at the beginning of the next end step"; - LoyalCatharEffect ( ) { + LoyalCatharEffect() { super(Outcome.Benefit); staticText = effectText; } @@ -96,10 +96,7 @@ class LoyalCatharEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { //create delayed triggered ability AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnLoyalCatharEffect(source.getSourceId())); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } diff --git a/Mage.Sets/src/mage/sets/darkascension/Seance.java b/Mage.Sets/src/mage/sets/darkascension/Seance.java index 1b28fafa421..d64000dad6e 100644 --- a/Mage.Sets/src/mage/sets/darkascension/Seance.java +++ b/Mage.Sets/src/mage/sets/darkascension/Seance.java @@ -44,10 +44,10 @@ import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; import mage.target.targetpointer.FixedTarget; +import mage.target.targetpointer.FixedTargets; /** * @@ -96,20 +96,15 @@ class SeanceEffect extends OneShotEffect { Card card = game.getCard(source.getFirstTarget()); Player controller = game.getPlayer(source.getControllerId()); if (controller != null && card != null) { - if (controller.moveCards(card, null, Zone.EXILED, source, game)) { + if (controller.moveCards(card, Zone.EXILED, source, game)) { PutTokenOntoBattlefieldCopyTargetEffect effect = new PutTokenOntoBattlefieldCopyTargetEffect(source.getControllerId(), null, false); effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game))); effect.setAdditionalSubType("Spirit"); effect.apply(game, source); - for (Permanent addedToken : effect.getAddedPermanent()) { - ExileTargetEffect exileEffect = new ExileTargetEffect(); - exileEffect.setTargetPointer(new FixedTarget(addedToken, game)); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); - } + ExileTargetEffect exileEffect = new ExileTargetEffect(); + exileEffect.setTargetPointer(new FixedTargets(effect.getAddedPermanent(), game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); + game.addDelayedTriggeredAbility(delayedAbility, source); } return true; } diff --git a/Mage.Sets/src/mage/sets/darkascension/SuddenDisappearance.java b/Mage.Sets/src/mage/sets/darkascension/SuddenDisappearance.java index 1e1fce38f17..24138a5dd8e 100644 --- a/Mage.Sets/src/mage/sets/darkascension/SuddenDisappearance.java +++ b/Mage.Sets/src/mage/sets/darkascension/SuddenDisappearance.java @@ -55,7 +55,6 @@ public class SuddenDisappearance extends CardImpl { super(ownerId, 23, "Sudden Disappearance", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{5}{W}"); this.expansionSetCode = "DKA"; - // Exile all nonland permanents target player controls. Return the exiled cards to the battlefield under their owner's control at the beginning of the next end step. this.getSpellAbility().addEffect(new SuddenDisappearanceEffect()); this.getSpellAbility().addTarget(new TargetPlayer()); @@ -96,10 +95,7 @@ class SuddenDisappearanceEffect extends OneShotEffect { controller.moveCardToExileWithInfo(permanent, source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true); } AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnFromExileEffect(source.getSourceId(), Zone.BATTLEFIELD)); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } return true; diff --git a/Mage.Sets/src/mage/sets/darksteel/LeoninBola.java b/Mage.Sets/src/mage/sets/darksteel/LeoninBola.java index 8b3367d7257..8cb3ac1ddf5 100644 --- a/Mage.Sets/src/mage/sets/darksteel/LeoninBola.java +++ b/Mage.Sets/src/mage/sets/darksteel/LeoninBola.java @@ -33,6 +33,7 @@ import mage.constants.*; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; @@ -90,7 +91,7 @@ class UnattachCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { Permanent attachment = game.getPermanent(attachmentid); diff --git a/Mage.Sets/src/mage/sets/darksteel/MyrMoonvessel.java b/Mage.Sets/src/mage/sets/darksteel/MyrMoonvessel.java index d57eeb8560b..cb314e1bc3c 100644 --- a/Mage.Sets/src/mage/sets/darksteel/MyrMoonvessel.java +++ b/Mage.Sets/src/mage/sets/darksteel/MyrMoonvessel.java @@ -25,18 +25,16 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.darksteel; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.Mana; import mage.abilities.common.DiesTriggeredAbility; import mage.abilities.effects.common.BasicManaEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; /** * @author Loki @@ -49,7 +47,7 @@ public class MyrMoonvessel extends CardImpl { this.subtype.add("Myr"); this.power = new MageInt(1); this.toughness = new MageInt(1); - this.addAbility(new DiesTriggeredAbility(new BasicManaEffect(new Mana(0, 0, 0, 0, 0, 1, 0)))); + this.addAbility(new DiesTriggeredAbility(new BasicManaEffect(new Mana(0, 0, 0, 0, 0, 0, 0, 1)))); } public MyrMoonvessel(final MyrMoonvessel card) { diff --git a/Mage.Sets/src/mage/sets/darksteel/SavageBeating.java b/Mage.Sets/src/mage/sets/darksteel/SavageBeating.java index 8d6dd06c04c..38061bb2dca 100644 --- a/Mage.Sets/src/mage/sets/darksteel/SavageBeating.java +++ b/Mage.Sets/src/mage/sets/darksteel/SavageBeating.java @@ -30,8 +30,8 @@ package mage.sets.darksteel; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.UntapAllControllerEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -43,11 +43,9 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.TurnPhase; -import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.turn.TurnMod; /** @@ -60,21 +58,19 @@ public class SavageBeating extends CardImpl { super(ownerId, 67, "Savage Beating", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{3}{R}{R}"); this.expansionSetCode = "DST"; - // Cast Savage Beating only during your turn and only during combat. - Ability ability = new SimpleStaticAbility(Zone.ALL, new SavageBeatingTimingEffect()); - ability.setRuleAtTheTop(true); - this.addAbility(ability); - + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(TurnPhase.COMBAT, null, MyTurnCondition.getInstance(), + "Cast {this} only during your turn and only during combat")); + // Choose one - Creatures you control gain double strike until end of turn; this.getSpellAbility().addEffect(new GainAbilityControlledEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn, new FilterCreaturePermanent(), false)); - + // or untap all creatures you control and after this phase, there is an additional combat phase. Mode mode = new Mode(); mode.getEffects().add(new UntapAllControllerEffect(new FilterControlledCreaturePermanent(), "untap all creatures you control")); mode.getEffects().add(new AdditionalCombatPhaseEffect()); this.getSpellAbility().getModes().addMode(mode); - + // Entwine {1}{R} this.addAbility(new EntwineAbility("{1}{R}")); } @@ -89,56 +85,25 @@ public class SavageBeating extends CardImpl { } } -class SavageBeatingTimingEffect extends ContinuousRuleModifyingEffectImpl { - SavageBeatingTimingEffect() { - super(Duration.EndOfGame, Outcome.Detriment); - staticText = "Cast {this} only during your turn and only during combat"; +class AdditionalCombatPhaseEffect extends OneShotEffect { + + AdditionalCombatPhaseEffect() { + super(Outcome.Benefit); + staticText = "and after this phase, there is an additional combat phase"; } - SavageBeatingTimingEffect(final SavageBeatingTimingEffect effect) { + AdditionalCombatPhaseEffect(final AdditionalCombatPhaseEffect effect) { super(effect); } @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType().equals(GameEvent.EventType.CAST_SPELL) && event.getSourceId().equals(source.getSourceId())) { - if (!game.getActivePlayerId().equals(source.getControllerId()) || !TurnPhase.COMBAT.equals(game.getTurn().getPhaseType())) { - return true; - } - } - return false; + public AdditionalCombatPhaseEffect copy() { + return new AdditionalCombatPhaseEffect(this); } @Override public boolean apply(Game game, Ability source) { + game.getState().getTurnMods().add(new TurnMod(source.getControllerId(), TurnPhase.COMBAT, null, false)); return true; } - - @Override - public SavageBeatingTimingEffect copy() { - return new SavageBeatingTimingEffect(this); - } } - -class AdditionalCombatPhaseEffect extends OneShotEffect { - - AdditionalCombatPhaseEffect() { - super(Outcome.Benefit); - staticText = "and after this phase, there is an additional combat phase"; - } - - AdditionalCombatPhaseEffect(final AdditionalCombatPhaseEffect effect) { - super(effect); - } - - @Override - public AdditionalCombatPhaseEffect copy() { - return new AdditionalCombatPhaseEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - game.getState().getTurnMods().add(new TurnMod(source.getControllerId(), TurnPhase.COMBAT, null, false)); - return true; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/darksteel/SurestrikeTrident.java b/Mage.Sets/src/mage/sets/darksteel/SurestrikeTrident.java index b3606a11a03..c03fad1ba93 100644 --- a/Mage.Sets/src/mage/sets/darksteel/SurestrikeTrident.java +++ b/Mage.Sets/src/mage/sets/darksteel/SurestrikeTrident.java @@ -31,6 +31,7 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; @@ -104,7 +105,7 @@ class SurestrikeTridentUnattachCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { for (UUID attachmentId : permanent.getAttachments()) { diff --git a/Mage.Sets/src/mage/sets/darksteel/TearsOfRage.java b/Mage.Sets/src/mage/sets/darksteel/TearsOfRage.java new file mode 100644 index 00000000000..15e9c98986f --- /dev/null +++ b/Mage.Sets/src/mage/sets/darksteel/TearsOfRage.java @@ -0,0 +1,113 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.darksteel; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.dynamicvalue.common.AttackingCreatureCount; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.constants.Rarity; +import mage.filter.common.FilterAttackingCreature; +import mage.game.Game; +import mage.players.Player; +import mage.target.targetpointer.FixedTargets; + +/** + * + * @author LevelX2 + */ +public class TearsOfRage extends CardImpl { + + public TearsOfRage(UUID ownerId) { + super(ownerId, 70, "Tears of Rage", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{2}{R}{R}"); + this.expansionSetCode = "DST"; + + // Cast Tears of Rage only during the declare attackers step. + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(PhaseStep.DECLARE_ATTACKERS)); + + // Attacking creatures you control get +X/+0 until end of turn, where X is the number of attacking creatures. Sacrifice those creatures at the beginning of the next end step. + getSpellAbility().addEffect(new BoostControlledEffect(new AttackingCreatureCount("the number of attacking creatures"), new StaticValue(0), + Duration.EndOfTurn, new FilterAttackingCreature("Attacking creatures"), false)); + getSpellAbility().addEffect(new TearsOfRageEffect()); + } + + public TearsOfRage(final TearsOfRage card) { + super(card); + } + + @Override + public TearsOfRage copy() { + return new TearsOfRage(this); + } +} + +class TearsOfRageEffect extends OneShotEffect { + + public TearsOfRageEffect() { + super(Outcome.Sacrifice); + this.staticText = "Sacrifice those creatures at the beginning of the next end step"; + } + + public TearsOfRageEffect(final TearsOfRageEffect effect) { + super(effect); + } + + @Override + public TearsOfRageEffect copy() { + return new TearsOfRageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Effect effect = new SacrificeTargetEffect("Sacrifice those creatures at the beginning of the next end step", source.getControllerId()); + effect.setTargetPointer(new FixedTargets(game.getBattlefield().getAllActivePermanents(new FilterAttackingCreature(), controller.getId(), game), game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); + delayedAbility.setSourceId(source.getSourceId()); + delayedAbility.setControllerId(source.getControllerId()); + delayedAbility.setSourceObject(source.getSourceObject(game), game); + game.addDelayedTriggeredAbility(delayedAbility); + return true; + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/sets/darksteel/UrGolemsEye.java b/Mage.Sets/src/mage/sets/darksteel/UrGolemsEye.java index c5599a8d824..55137d9643b 100644 --- a/Mage.Sets/src/mage/sets/darksteel/UrGolemsEye.java +++ b/Mage.Sets/src/mage/sets/darksteel/UrGolemsEye.java @@ -25,17 +25,15 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.darksteel; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.Mana; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.mana.SimpleManaAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.constants.Zone; /** @@ -44,15 +42,15 @@ import mage.constants.Zone; */ public class UrGolemsEye extends CardImpl { - public UrGolemsEye (UUID ownerId) { + public UrGolemsEye(UUID ownerId) { super(ownerId, 155, "Ur-Golem's Eye", Rarity.COMMON, new CardType[]{CardType.ARTIFACT}, "{4}"); this.expansionSetCode = "DST"; - + // {tap}: Add {C}{C} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0,0,0,0,0,2,0), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 0, 0, 0, 0, 2), new TapSourceCost())); } - public UrGolemsEye (final UrGolemsEye card) { + public UrGolemsEye(final UrGolemsEye card) { super(card); } @@ -62,4 +60,3 @@ public class UrGolemsEye extends CardImpl { } } - diff --git a/Mage.Sets/src/mage/sets/dissension/AzoriusChancery.java b/Mage.Sets/src/mage/sets/dissension/AzoriusChancery.java index b7df79e90d1..acadac38666 100644 --- a/Mage.Sets/src/mage/sets/dissension/AzoriusChancery.java +++ b/Mage.Sets/src/mage/sets/dissension/AzoriusChancery.java @@ -58,7 +58,7 @@ public class AzoriusChancery extends CardImpl { // When Azorius Chancery enters the battlefield, return a land you control to its owner's hand. this.addAbility(new EntersBattlefieldTriggeredAbility(new ReturnToHandChosenControlledPermanentEffect(filter), false)); // {tap}: Add {W}{U} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 1, 0, 0, 0), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 1, 0, 0, 0, 0), new TapSourceCost())); } public AzoriusChancery(final AzoriusChancery card) { diff --git a/Mage.Sets/src/mage/sets/dissension/AzoriusSignet.java b/Mage.Sets/src/mage/sets/dissension/AzoriusSignet.java index 514c19fdad5..d970c8302f0 100644 --- a/Mage.Sets/src/mage/sets/dissension/AzoriusSignet.java +++ b/Mage.Sets/src/mage/sets/dissension/AzoriusSignet.java @@ -50,7 +50,7 @@ public class AzoriusSignet extends CardImpl { this.expansionSetCode = "DIS"; // {1}, {tap}: Add {W}{U} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 1, 0, 0, 0), new GenericManaCost(1)); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 1, 0, 0, 0, 0), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/dissension/Carom.java b/Mage.Sets/src/mage/sets/dissension/Carom.java new file mode 100644 index 00000000000..97569b0e97c --- /dev/null +++ b/Mage.Sets/src/mage/sets/dissension/Carom.java @@ -0,0 +1,120 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.dissension; + +import java.util.UUID; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.effects.RedirectionEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.TargetSource; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author Skyler Sell + */ +public class Carom extends CardImpl { + + public Carom(UUID ownerId) { + super(ownerId, 6, "Carom", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{W}"); + this.expansionSetCode = "DIS"; + + // 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().addEffect(new DrawCardSourceControllerEffect(1)); + } + + public Carom(final Carom card) { + super(card); + } + + @Override + public Carom copy() { + return new Carom(this); + } +} + +class CaromEffect extends RedirectionEffect { + + protected MageObjectReference redirectToObject; + + public CaromEffect(Duration duration, int amount) { + super(duration, amount, true); + staticText = "The next " + amount + " damage that would be dealt to target creature this turn is dealt to another target creature instead"; + } + + public CaromEffect(final CaromEffect effect) { + super(effect); + } + + @Override + public CaromEffect copy() { + return new CaromEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + redirectToObject = new MageObjectReference(source.getTargets().get(1).getFirstTarget(), game); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getTargetId().equals(getTargetPointer().getFirst(game, source))) { + if (game.getControllerId(redirectToObject.getSourceId()) != null) { + if (redirectToObject.equals(new MageObjectReference(source.getTargets().get(1).getFirstTarget(), game))) { + redirectTarget = source.getTargets().get(1); + return true; + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/dissension/RakdosCarnarium.java b/Mage.Sets/src/mage/sets/dissension/RakdosCarnarium.java index 12530374921..a76be1d3bb7 100644 --- a/Mage.Sets/src/mage/sets/dissension/RakdosCarnarium.java +++ b/Mage.Sets/src/mage/sets/dissension/RakdosCarnarium.java @@ -61,7 +61,7 @@ public class RakdosCarnarium extends CardImpl { // When Rakdos Carnarium enters the battlefield, return a land you control to its owner's hand. this.addAbility(new EntersBattlefieldTriggeredAbility(new ReturnToHandChosenControlledPermanentEffect(filter), false)); // {tap}: Add {B}{R} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 0, 1, 0, 0), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 0, 1, 0, 0, 0), new TapSourceCost())); } public RakdosCarnarium(final RakdosCarnarium card) { diff --git a/Mage.Sets/src/mage/sets/dissension/RakdosSignet.java b/Mage.Sets/src/mage/sets/dissension/RakdosSignet.java index f7371aa3d16..d98733450c7 100644 --- a/Mage.Sets/src/mage/sets/dissension/RakdosSignet.java +++ b/Mage.Sets/src/mage/sets/dissension/RakdosSignet.java @@ -50,7 +50,7 @@ public class RakdosSignet extends CardImpl { this.expansionSetCode = "DIS"; // {1}, {tap}: Add {B}{R} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 0, 1, 0, 0), new GenericManaCost(1)); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 0, 1, 0, 0, 0), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/dissension/SimicGrowthChamber.java b/Mage.Sets/src/mage/sets/dissension/SimicGrowthChamber.java index 74e7dd1c3fa..f2d877e10fd 100644 --- a/Mage.Sets/src/mage/sets/dissension/SimicGrowthChamber.java +++ b/Mage.Sets/src/mage/sets/dissension/SimicGrowthChamber.java @@ -58,7 +58,7 @@ public class SimicGrowthChamber extends CardImpl { // When Simic Growth Chamber enters the battlefield, return a land you control to its owner's hand. this.addAbility(new EntersBattlefieldTriggeredAbility(new ReturnToHandChosenControlledPermanentEffect(filter), false)); // {tap}: Add {G}{U} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 1, 0, 0, 0, 0), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 1, 0, 0, 0, 0, 0), new TapSourceCost())); } public SimicGrowthChamber(final SimicGrowthChamber card) { diff --git a/Mage.Sets/src/mage/sets/dissension/SimicSignet.java b/Mage.Sets/src/mage/sets/dissension/SimicSignet.java index 9f241798ffa..c4dc7b90400 100644 --- a/Mage.Sets/src/mage/sets/dissension/SimicSignet.java +++ b/Mage.Sets/src/mage/sets/dissension/SimicSignet.java @@ -50,7 +50,7 @@ public class SimicSignet extends CardImpl { this.expansionSetCode = "DIS"; // {1}, {tap}: Add {G}{U} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 1, 0, 0, 0, 0), new GenericManaCost(1)); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 1, 0, 0, 0, 0, 0), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/AEtherling.java b/Mage.Sets/src/mage/sets/dragonsmaze/AEtherling.java index a6b07bc4f1a..1bca2d23e79 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/AEtherling.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/AEtherling.java @@ -31,7 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ExileReturnToBattlefieldOwnerNextEndStepEffect; +import mage.abilities.effects.common.ExileReturnBattlefieldOwnerNextEndStepSourceEffect; import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; @@ -55,7 +55,7 @@ public class AEtherling extends CardImpl { this.toughness = new MageInt(5); // {U}: Exile AEtherling. Return it to the battlefield under its owner's control at the beginning of the next end step. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileReturnToBattlefieldOwnerNextEndStepEffect(true), new ManaCostsImpl("{U}"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(true), new ManaCostsImpl("{U}"))); // {U}: AEtherling can't be blocked this turn this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new CantBeBlockedSourceEffect(Duration.EndOfTurn), new ManaCostsImpl("{U}"))); // {1}: AEtherling gets +1/-1 until end of turn. diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/LegionsInitiative.java b/Mage.Sets/src/mage/sets/dragonsmaze/LegionsInitiative.java index 6931273054a..970a5c3afb3 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/LegionsInitiative.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/LegionsInitiative.java @@ -28,12 +28,6 @@ package mage.sets.dragonsmaze; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -48,7 +42,12 @@ import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.HasteAbility; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.TargetController; +import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -67,6 +66,7 @@ public class LegionsInitiative extends CardImpl { private static final FilterCreaturePermanent filterRedCreature = new FilterCreaturePermanent("Red creatures"); private static final FilterCreaturePermanent filterWhiteCreature = new FilterCreaturePermanent("White creatures"); + static { filterRedCreature.add(new ColorPredicate(ObjectColor.RED)); filterWhiteCreature.add(new ColorPredicate(ObjectColor.WHITE)); @@ -76,13 +76,12 @@ public class LegionsInitiative extends CardImpl { super(ownerId, 81, "Legion's Initiative", Rarity.MYTHIC, new CardType[]{CardType.ENCHANTMENT}, "{R}{W}"); this.expansionSetCode = "DGM"; - // Red creatures you control get +1/+0. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 0, Duration.WhileOnBattlefield, filterRedCreature))); // White creatures you control get +0/+1. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(0, 1, Duration.WhileOnBattlefield, filterWhiteCreature))); - + // {R}{W}, Exile Legion's Initiative: Exile all creatures you control. At the beginning of the next combat, return those cards to the battlefield under their owner's control and those creatures gain haste until end of turn. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LegionsInitiativeExileEffect(), new ManaCostsImpl("{R}{W}")); ability.addCost(new ExileSourceCost()); @@ -102,6 +101,7 @@ public class LegionsInitiative extends CardImpl { class LegionsInitiativeExileEffect extends OneShotEffect { private static final FilterPermanent filter = new FilterPermanent("all creatures you control"); + static { filter.add(new ControllerPredicate(TargetController.YOU)); filter.add(new CardTypePredicate(CardType.CREATURE)); @@ -129,10 +129,7 @@ class LegionsInitiativeExileEffect extends OneShotEffect { if (creatureExiled) { //create delayed triggered ability AtTheBeginOfCombatDelayedTriggeredAbility delayedAbility = new AtTheBeginOfCombatDelayedTriggeredAbility(new LegionsInitiativeReturnFromExileEffect()); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } return true; @@ -165,7 +162,7 @@ class LegionsInitiativeReturnFromExileEffect extends OneShotEffect { ExileZone exile = game.getExile().getExileZone(source.getSourceId()); if (exile != null) { exile = exile.copy(); - for (UUID cardId: exile) { + for (UUID cardId : exile) { Card card = game.getCard(cardId); card.moveToZone(Zone.BATTLEFIELD, source.getSourceId(), game, false); Permanent returnedCreature = game.getPermanent(cardId); diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/PlasmCapture.java b/Mage.Sets/src/mage/sets/dragonsmaze/PlasmCapture.java index ae7f5f64f05..c7c7e1f167d 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/PlasmCapture.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/PlasmCapture.java @@ -28,11 +28,6 @@ package mage.sets.dragonsmaze; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.TargetController; import mage.Mana; import mage.abilities.Ability; import mage.abilities.common.delayed.AtTheBeginOfMainPhaseDelayedTriggeredAbility; @@ -41,6 +36,10 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ManaEffect; import mage.cards.CardImpl; import mage.choices.ChoiceColor; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.TargetController; import mage.game.Game; import mage.game.stack.Spell; import mage.players.Player; @@ -56,7 +55,6 @@ public class PlasmCapture extends CardImpl { super(ownerId, 91, "Plasm Capture", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{G}{G}{U}{U}"); this.expansionSetCode = "DGM"; - // Counter target spell. At the beginning of your next precombat main phase, add X mana in any combination of colors to your mana pool, where X is that spell's converted mana cost. this.getSpellAbility().addTarget(new TargetSpell()); this.getSpellAbility().addEffect(new PlasmCaptureCounterEffect()); @@ -95,12 +93,9 @@ class PlasmCaptureCounterEffect extends OneShotEffect { game.getStack().counter(getTargetPointer().getFirst(game, source), source.getSourceId(), game); // mana gets added also if counter is not successful int mana = spell.getConvertedManaCost(); - AtTheBeginOfMainPhaseDelayedTriggeredAbility delayedAbility = - new AtTheBeginOfMainPhaseDelayedTriggeredAbility(new PlasmCaptureManaEffect(mana), false, TargetController.YOU, PhaseSelection.NEXT_PRECOMBAT_MAIN); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + AtTheBeginOfMainPhaseDelayedTriggeredAbility delayedAbility + = new AtTheBeginOfMainPhaseDelayedTriggeredAbility(new PlasmCaptureManaEffect(mana), false, TargetController.YOU, PhaseSelection.NEXT_PRECOMBAT_MAIN); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } return false; @@ -130,9 +125,9 @@ class PlasmCaptureManaEffect extends ManaEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if(player != null){ + if (player != null) { Mana mana = new Mana(); - for(int i = 0; i < amountOfMana; i++){ + for (int i = 0; i < amountOfMana; i++) { ChoiceColor choiceColor = new ChoiceColor(); while (!player.choose(Outcome.Benefit, choiceColor, game)) { if (!player.canRespond()) { diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/CircleOfElders.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/CircleOfElders.java index 5b9929053b8..3f698ec14ab 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/CircleOfElders.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/CircleOfElders.java @@ -62,7 +62,7 @@ public class CircleOfElders extends CardImpl { // Formidable - {T}: Add {C}{C}{C} to your mana pool. Activate this only if creatures you control have total power 8 or greater. Ability ability = new ActivateIfConditionManaAbility( Zone.BATTLEFIELD, - new BasicManaEffect(new Mana(0,0,0,0,0,3,0)), + new BasicManaEffect(new Mana(0, 0, 0, 0, 0, 0, 0, 3)), new TapSourceCost(), FormidableCondition.getInstance()); ability.setAbilityWord(AbilityWord.FORMIDABLE); diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/HavenOfTheSpiritDragon.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/HavenOfTheSpiritDragon.java index d426f75a336..8e7a0c3a87c 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/HavenOfTheSpiritDragon.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/HavenOfTheSpiritDragon.java @@ -33,6 +33,7 @@ import mage.MageObject; import mage.Mana; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -120,7 +121,7 @@ class HavenOfTheSpiritConditionalMana extends ConditionalMana { class HavenOfTheSpiritManaCondition extends CreatureCastManaCondition { @Override - public boolean apply(Game game, Ability source, UUID manaProducer) { + public boolean apply(Game game, Ability source, UUID manaProducer, Cost costToPay) { if (super.apply(game, source)) { MageObject object = game.getObject(source.getSourceId()); if (object.hasSubtype("Dragon") diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/MysticMeditation.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/MysticMeditation.java index 46b1afc78a8..21791062e75 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/MysticMeditation.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/MysticMeditation.java @@ -95,7 +95,7 @@ class MysticMeditationEffect extends OneShotEffect { && controller.chooseUse(Outcome.Discard, "Do you want to discard a creature card? If you don't, you must discard 2 cards", source, game)) { Cost cost = new DiscardTargetCost(new TargetCardInHand(filter)); if (cost.canPay(source, source.getSourceId(), controller.getId(), game)) { - if (cost.pay(source, game, source.getSourceId(), controller.getId(), false)) { + if (cost.pay(source, game, source.getSourceId(), controller.getId(), false, null)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/SavageVentmaw.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/SavageVentmaw.java index fec5afbe04f..d6138c64ec8 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/SavageVentmaw.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/SavageVentmaw.java @@ -58,7 +58,7 @@ public class SavageVentmaw extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever Savage Ventmaw attacks, add {R}{R}{R}{G}{G}{G} to your mana pool. Until end of turn, this mana doesn't empty from your mana pool as steps and phases end. - Effect effect = new SavageVentmawManaEffect(new Mana(3, 3, 0, 0, 0, 0, 0), "your", true); + Effect effect = new SavageVentmawManaEffect(new Mana(3, 3, 0, 0, 0, 0, 0, 0), "your", true); effect.setText("add {R}{R}{R}{G}{G}{G} to your mana pool. Until end of turn, this mana doesn't empty from your mana pool as steps and phases end"); this.addAbility(new AttacksTriggeredAbility(effect, false)); diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/SwiftWarkite.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/SwiftWarkite.java index bfd5b48ff0d..38921920331 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/SwiftWarkite.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/SwiftWarkite.java @@ -131,10 +131,7 @@ class SwiftWarkiteEffect extends OneShotEffect { Effect effect2 = new ReturnToHandTargetEffect(); effect2.setTargetPointer(new FixedTarget(creature.getId(), creature.getZoneChangeCounter(game))); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect2); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } } } @@ -152,10 +149,7 @@ class SwiftWarkiteEffect extends OneShotEffect { Effect effect2 = new ReturnToHandTargetEffect(); effect2.setTargetPointer(new FixedTarget(creature.getId(), creature.getZoneChangeCounter(game))); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect2); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } } } diff --git a/Mage.Sets/src/mage/sets/eighthedition/StarCompass.java b/Mage.Sets/src/mage/sets/eighthedition/StarCompass.java index dad4627b46a..5f48b37b296 100644 --- a/Mage.Sets/src/mage/sets/eighthedition/StarCompass.java +++ b/Mage.Sets/src/mage/sets/eighthedition/StarCompass.java @@ -80,7 +80,7 @@ public class StarCompass extends CardImpl { class StarCompassManaAbility extends ManaAbility { public StarCompassManaAbility() { - super(Zone.BATTLEFIELD, new StarCompassManaEffect(),new TapSourceCost()); + super(Zone.BATTLEFIELD, new StarCompassManaEffect(), new TapSourceCost()); } public StarCompassManaAbility(final StarCompassManaAbility ability) { @@ -94,14 +94,14 @@ class StarCompassManaAbility extends ManaAbility { @Override public List getNetMana(Game game) { - return ((StarCompassManaEffect)getEffects().get(0)).getNetMana(game, this); + return ((StarCompassManaEffect) getEffects().get(0)).getNetMana(game, this); } } class StarCompassManaEffect extends ManaEffect { private static final FilterControlledPermanent filter = new FilterControlledLandPermanent(); - + static { filter.add(new SupertypePredicate("Basic")); } @@ -184,7 +184,7 @@ class StarCompassManaEffect extends ManaEffect { return true; } - public List getNetMana(Game game, Ability source) { + public List getNetMana(Game game, Ability source) { List netManas = new ArrayList<>(); Mana types = getManaTypes(game, source); if (types.getBlack() > 0) { @@ -202,8 +202,8 @@ class StarCompassManaEffect extends ManaEffect { if (types.getWhite() > 0) { netManas.add(new Mana(ColoredManaSymbol.W)); } - if (types.getColorless() > 0) { - netManas.add(new Mana(0,0,0,0,0,1,0)); + if (types.getGeneric() > 0) { + netManas.add(new Mana(0, 0, 0, 0, 0, 0, 0, 1)); } return netManas; } @@ -215,7 +215,7 @@ class StarCompassManaEffect extends ManaEffect { Abilities manaAbilities = land.getAbilities().getManaAbilities(Zone.BATTLEFIELD); for (ManaAbility ability : manaAbilities) { if (!ability.equals(source) && ability.definesMana()) { - for (Mana netMana: ability.getNetMana(game)) { + for (Mana netMana : ability.getNetMana(game)) { types.add(netMana); } } @@ -233,4 +233,4 @@ class StarCompassManaEffect extends ManaEffect { public StarCompassManaEffect copy() { return new StarCompassManaEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/eventide/CascadeBluffs.java b/Mage.Sets/src/mage/sets/eventide/CascadeBluffs.java index deda0137e10..eb57785692c 100644 --- a/Mage.Sets/src/mage/sets/eventide/CascadeBluffs.java +++ b/Mage.Sets/src/mage/sets/eventide/CascadeBluffs.java @@ -57,7 +57,7 @@ public class CascadeBluffs extends CardImpl { ability.addCost(new TapSourceCost()); this.addAbility(ability); - ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 1, 0, 0, 0, 0), new ManaCostsImpl("{U/R}")); + ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 1, 0, 0, 0, 0, 0), new ManaCostsImpl("{U/R}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/eventide/DreamFracture.java b/Mage.Sets/src/mage/sets/eventide/DreamFracture.java index 2b4de1ba5eb..2641de664bb 100644 --- a/Mage.Sets/src/mage/sets/eventide/DreamFracture.java +++ b/Mage.Sets/src/mage/sets/eventide/DreamFracture.java @@ -49,7 +49,6 @@ public class DreamFracture extends CardImpl { super(ownerId, 19, "Dream Fracture", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{1}{U}{U}"); this.expansionSetCode = "EVE"; - // Counter target spell. Its controller draws a card. this.getSpellAbility().addEffect(new DreamFractureEffect()); this.getSpellAbility().addTarget(new TargetSpell()); @@ -73,7 +72,7 @@ class DreamFractureEffect extends OneShotEffect { public DreamFractureEffect() { super(Outcome.Neutral); - this.staticText = "Counter target spell. Its controller draws a card"; + this.staticText = "Counter target spell. Its controller draws a card"; } public DreamFractureEffect(final DreamFractureEffect effect) { @@ -102,4 +101,4 @@ class DreamFractureEffect extends OneShotEffect { } return countered; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/eventide/FetidHeath.java b/Mage.Sets/src/mage/sets/eventide/FetidHeath.java index 17b91c2a6a6..22c527249c6 100644 --- a/Mage.Sets/src/mage/sets/eventide/FetidHeath.java +++ b/Mage.Sets/src/mage/sets/eventide/FetidHeath.java @@ -59,7 +59,7 @@ public class FetidHeath extends CardImpl { ability.addCost(new TapSourceCost()); this.addAbility(ability); - ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 1, 1, 0, 0), new ManaCostsImpl("{W/B}")); + ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 1, 1, 0, 0, 0), new ManaCostsImpl("{W/B}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/eventide/FloodedGrove.java b/Mage.Sets/src/mage/sets/eventide/FloodedGrove.java index 8179e60230f..bc2965aed77 100644 --- a/Mage.Sets/src/mage/sets/eventide/FloodedGrove.java +++ b/Mage.Sets/src/mage/sets/eventide/FloodedGrove.java @@ -57,7 +57,7 @@ public class FloodedGrove extends CardImpl { ability.addCost(new TapSourceCost()); this.addAbility(ability); - ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 1, 0, 0, 0, 0), new ManaCostsImpl("{G/U}")); + ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 1, 0, 0, 0, 0, 0), new ManaCostsImpl("{G/U}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/eventide/HatchetBully.java b/Mage.Sets/src/mage/sets/eventide/HatchetBully.java index 5f8404c6bdc..93f9b9f86fb 100644 --- a/Mage.Sets/src/mage/sets/eventide/HatchetBully.java +++ b/Mage.Sets/src/mage/sets/eventide/HatchetBully.java @@ -31,6 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -101,7 +102,7 @@ class HatchetBullyCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(ability.getTargets().get(1).getFirstTarget()); if (permanent != null) { permanent.addCounters(CounterType.M1M1.createInstance(), game); diff --git a/Mage.Sets/src/mage/sets/eventide/ImpelledGiant.java b/Mage.Sets/src/mage/sets/eventide/ImpelledGiant.java index ceb04da2360..8f901fc0f40 100644 --- a/Mage.Sets/src/mage/sets/eventide/ImpelledGiant.java +++ b/Mage.Sets/src/mage/sets/eventide/ImpelledGiant.java @@ -34,6 +34,7 @@ import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -111,7 +112,7 @@ class ImpelledGiantCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { if (target.choose(Outcome.Tap, controllerId, sourceId, game)) { for (UUID targetId: (List)target.getTargets()) { Permanent permanent = game.getPermanent(targetId); diff --git a/Mage.Sets/src/mage/sets/eventide/RiseOfTheHobgoblins.java b/Mage.Sets/src/mage/sets/eventide/RiseOfTheHobgoblins.java index a168f001040..4b33b497b23 100644 --- a/Mage.Sets/src/mage/sets/eventide/RiseOfTheHobgoblins.java +++ b/Mage.Sets/src/mage/sets/eventide/RiseOfTheHobgoblins.java @@ -119,7 +119,7 @@ class RiseOfTheHobgoblinsEffect extends OneShotEffect { if (you != null && you.chooseUse(Outcome.Neutral, "Do you want to to pay {X}?", source, game)) { int costX = you.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); cost.add(new GenericManaCost(costX)); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { Token token = new GoblinSoldierToken(); return token.putOntoBattlefield(costX, game, source.getSourceId(), source.getControllerId()); } diff --git a/Mage.Sets/src/mage/sets/eventide/RuggedPrairie.java b/Mage.Sets/src/mage/sets/eventide/RuggedPrairie.java index 1a0c6f0c1dd..2af353c465a 100644 --- a/Mage.Sets/src/mage/sets/eventide/RuggedPrairie.java +++ b/Mage.Sets/src/mage/sets/eventide/RuggedPrairie.java @@ -56,7 +56,7 @@ public class RuggedPrairie extends CardImpl { ability.addCost(new TapSourceCost()); this.addAbility(ability); - ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 1, 0, 0, 0), new ManaCostsImpl("{R/W}")); + ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 1, 0, 0, 0, 0), new ManaCostsImpl("{R/W}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/eventide/SoulReap.java b/Mage.Sets/src/mage/sets/eventide/SoulReap.java index 3bb073a7dbf..815682cd9ce 100644 --- a/Mage.Sets/src/mage/sets/eventide/SoulReap.java +++ b/Mage.Sets/src/mage/sets/eventide/SoulReap.java @@ -39,7 +39,6 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.WatcherScope; -import mage.constants.Zone; import mage.filter.FilterSpell; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; @@ -165,7 +164,7 @@ class SoulReapEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent creature = (Permanent) game.getLastKnownInformation(source.getFirstTarget(), Zone.BATTLEFIELD); + Permanent creature = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); if (creature != null) { Player controller = game.getPlayer(creature.getControllerId()); if (controller != null) { diff --git a/Mage.Sets/src/mage/sets/eventide/Thunderblust.java b/Mage.Sets/src/mage/sets/eventide/Thunderblust.java index c74a0cafec0..8bbf6ce6b82 100644 --- a/Mage.Sets/src/mage/sets/eventide/Thunderblust.java +++ b/Mage.Sets/src/mage/sets/eventide/Thunderblust.java @@ -48,8 +48,8 @@ import mage.counters.CounterType; * @author jeffwadsworth */ public class Thunderblust extends CardImpl { - - private String rule = "Thunderblust has trample as long as it has a -1/-1 counter on it"; + + private final String rule = "{this} has trample as long as it has a -1/-1 counter on it"; public Thunderblust(UUID ownerId) { super(ownerId, 63, "Thunderblust", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{R}{R}{R}"); @@ -61,11 +61,11 @@ public class Thunderblust extends CardImpl { // Haste this.addAbility(HasteAbility.getInstance()); - + // Thunderblust has trample as long as it has a -1/-1 counter on it. Effect effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(TrampleAbility.getInstance()), new SourceHasCounterCondition(CounterType.M1M1), rule); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); - + // Persist this.addAbility(new PersistAbility()); } diff --git a/Mage.Sets/src/mage/sets/eventide/TwilightMire.java b/Mage.Sets/src/mage/sets/eventide/TwilightMire.java index df41bac3c7d..8113376b38a 100644 --- a/Mage.Sets/src/mage/sets/eventide/TwilightMire.java +++ b/Mage.Sets/src/mage/sets/eventide/TwilightMire.java @@ -57,7 +57,7 @@ public class TwilightMire extends CardImpl { ability.addCost(new TapSourceCost()); this.addAbility(ability); - ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 0, 1, 0, 0), new ManaCostsImpl("{B/G}")); + ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 0, 1, 0, 0, 0), new ManaCostsImpl("{B/G}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/eventide/WavesOfAggression.java b/Mage.Sets/src/mage/sets/eventide/WavesOfAggression.java index 8b0ee765545..cc934abeb3f 100644 --- a/Mage.Sets/src/mage/sets/eventide/WavesOfAggression.java +++ b/Mage.Sets/src/mage/sets/eventide/WavesOfAggression.java @@ -60,7 +60,7 @@ public class WavesOfAggression extends CardImpl { // Untap all creatures that attacked this turn. After this main phase, there is an additional combat phase followed by an additional main phase. this.getSpellAbility().addWatcher(new AttackedThisTurnWatcher()); this.getSpellAbility().addEffect(new WavesOfAggressionUntapEffect()); - this.getSpellAbility().addEffect(new WavesOfAggressionAddPhasesEffect()); + this.getSpellAbility().addEffect(new WavesOfAggressionAddPhasesEffect()); // Retrace this.addAbility(new RetraceAbility(this)); } @@ -132,10 +132,8 @@ class WavesOfAggressionAddPhasesEffect extends OneShotEffect { TurnMod combat = new TurnMod(source.getControllerId(), TurnPhase.COMBAT, TurnPhase.POSTCOMBAT_MAIN, false); game.getState().getTurnMods().add(combat); WavesOfAggressionDelayedAddMainPhaseAbility delayedTriggeredAbility = new WavesOfAggressionDelayedAddMainPhaseAbility(); - delayedTriggeredAbility.setSourceId(source.getSourceId()); - delayedTriggeredAbility.setControllerId(source.getControllerId()); delayedTriggeredAbility.setConnectedTurnMod(combat.getId()); - game.addDelayedTriggeredAbility(delayedTriggeredAbility); + game.addDelayedTriggeredAbility(delayedTriggeredAbility, source); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/exodus/CullingTheWeak.java b/Mage.Sets/src/mage/sets/exodus/CullingTheWeak.java index 80bb18a0270..8fbae381f78 100644 --- a/Mage.Sets/src/mage/sets/exodus/CullingTheWeak.java +++ b/Mage.Sets/src/mage/sets/exodus/CullingTheWeak.java @@ -52,7 +52,7 @@ public class CullingTheWeak extends CardImpl { this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("a creature")))); // Add {B}{B}{B}{B} to your mana pool. - this.getSpellAbility().addEffect(new BasicManaEffect(new Mana(0, 0, 0, 0, 4, 0, 0))); + this.getSpellAbility().addEffect(new BasicManaEffect(new Mana(0, 0, 0, 0, 4, 0, 0, 0))); } public CullingTheWeak(final CullingTheWeak card) { diff --git a/Mage.Sets/src/mage/sets/exodus/ErraticPortal.java b/Mage.Sets/src/mage/sets/exodus/ErraticPortal.java index 66f16ccb7c3..0447546e4f1 100644 --- a/Mage.Sets/src/mage/sets/exodus/ErraticPortal.java +++ b/Mage.Sets/src/mage/sets/exodus/ErraticPortal.java @@ -103,7 +103,7 @@ class ErraticPortalEffect extends OneShotEffect { if (player != null) { cost.clearPaid(); if (player.chooseUse(Outcome.Benefit, "Pay {1}? (Otherwise " + targetCreature.getLogName() +" will be returned to its owner's hand)", source, game)) { - cost.pay(source, game, targetCreature.getControllerId(), targetCreature.getControllerId(), false); + cost.pay(source, game, targetCreature.getControllerId(), targetCreature.getControllerId(), false, null); } if (!cost.isPaid()) { controller.moveCards(targetCreature, Zone.BATTLEFIELD, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/sets/exodus/Workhorse.java b/Mage.Sets/src/mage/sets/exodus/Workhorse.java index ac3c4701a3c..5dca1b48425 100644 --- a/Mage.Sets/src/mage/sets/exodus/Workhorse.java +++ b/Mage.Sets/src/mage/sets/exodus/Workhorse.java @@ -55,10 +55,10 @@ public class Workhorse extends CardImpl { // Workhorse enters the battlefield with four +1/+1 counters on it. this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(4)), "with four +1/+1 counters on it")); - + // Remove a +1/+1 counter from Workhorse: Add {C} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, - new Mana(new Mana(0, 0, 0, 0, 0, 1, 0)), + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, + new Mana(new Mana(0, 0, 0, 0, 0, 0, 0, 1)), new RemoveCountersSourceCost(CounterType.P1P1.createInstance()))); } diff --git a/Mage.Sets/src/mage/sets/fallenempires/BasalThrull1.java b/Mage.Sets/src/mage/sets/fallenempires/BasalThrull1.java index efef91c76aa..211f991881c 100644 --- a/Mage.Sets/src/mage/sets/fallenempires/BasalThrull1.java +++ b/Mage.Sets/src/mage/sets/fallenempires/BasalThrull1.java @@ -54,7 +54,7 @@ public class BasalThrull1 extends CardImpl { this.toughness = new MageInt(2); // {T}, Sacrifice Basal Thrull: Add {B}{B} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new BasicManaEffect(new Mana(0, 0, 0, 0, 2, 0, 0)), new TapSourceCost()); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new BasicManaEffect(new Mana(0, 0, 0, 0, 2, 0, 0, 0)), new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/fallenempires/TidalInfluence.java b/Mage.Sets/src/mage/sets/fallenempires/TidalInfluence.java index 5de52d6b938..5f92d4ced1a 100644 --- a/Mage.Sets/src/mage/sets/fallenempires/TidalInfluence.java +++ b/Mage.Sets/src/mage/sets/fallenempires/TidalInfluence.java @@ -35,6 +35,7 @@ import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.dynamicvalue.common.CountersCount; @@ -127,7 +128,7 @@ class TidalInfluenceCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { this.paid = true; return paid; } diff --git a/Mage.Sets/src/mage/sets/fatereforged/FrontierSiege.java b/Mage.Sets/src/mage/sets/fatereforged/FrontierSiege.java index 1a98c5c215c..5c5d1c62d01 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/FrontierSiege.java +++ b/Mage.Sets/src/mage/sets/fatereforged/FrontierSiege.java @@ -108,7 +108,7 @@ public class FrontierSiege extends CardImpl { class FrontierSiegeKhansTriggeredAbility extends TriggeredAbilityImpl { public FrontierSiegeKhansTriggeredAbility() { - super(Zone.BATTLEFIELD, new AddManaToManaPoolSourceControllerEffect(new Mana(0, 2, 0, 0, 0, 0, 0)), false); + super(Zone.BATTLEFIELD, new AddManaToManaPoolSourceControllerEffect(new Mana(0, 2, 0, 0, 0, 0, 0, 0)), false); } diff --git a/Mage.Sets/src/mage/sets/fatereforged/RallyTheAncestors.java b/Mage.Sets/src/mage/sets/fatereforged/RallyTheAncestors.java index 564996f1e27..d7fecbf4064 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/RallyTheAncestors.java +++ b/Mage.Sets/src/mage/sets/fatereforged/RallyTheAncestors.java @@ -27,6 +27,7 @@ */ package mage.sets.fatereforged; +import java.util.ArrayList; import java.util.Set; import java.util.UUID; import mage.abilities.Ability; @@ -48,7 +49,7 @@ import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.targetpointer.FixedTarget; +import mage.target.targetpointer.FixedTargets; /** * @@ -101,20 +102,19 @@ class RallyTheAncestorsEffect extends OneShotEffect { filter.add(new ConvertedManaCostPredicate(ComparisonType.LessThan, xValue + 1)); Set cards = player.getGraveyard().getCards(filter, game); player.moveCards(cards, Zone.BATTLEFIELD, source, game); + ArrayList toExile = new ArrayList<>(cards.size()); for (Card card : cards) { if (card != null) { Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { - Effect exileEffect = new ExileTargetEffect("Exile those creatures at the beginning of your next upkeep"); - exileEffect.setTargetPointer(new FixedTarget(permanent, game)); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + toExile.add(permanent); } } } + Effect exileEffect = new ExileTargetEffect("Exile those creatures at the beginning of your next upkeep"); + exileEffect.setTargetPointer(new FixedTargets(toExile, game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility(exileEffect); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/fatereforged/Vaultbreaker.java b/Mage.Sets/src/mage/sets/fatereforged/Vaultbreaker.java index 4f6840806bc..86fa4b0b56e 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/Vaultbreaker.java +++ b/Mage.Sets/src/mage/sets/fatereforged/Vaultbreaker.java @@ -1,104 +1,72 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ -package mage.sets.fatereforged; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.keyword.DashAbility; -import mage.cards.CardImpl; -import mage.cards.Cards; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.game.Game; -import mage.players.Player; - -/** - * - * @author jeffwadsworth - */ -public class Vaultbreaker extends CardImpl { - - public Vaultbreaker(UUID ownerId) { - super(ownerId, 117, "Vaultbreaker", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{R}"); - this.expansionSetCode = "FRF"; - this.subtype.add("Orc"); - this.subtype.add("Rogue"); - this.power = new MageInt(4); - this.toughness = new MageInt(2); - - // Whenever Vaultbreaker attacks, you may discard a card. If you do, draw a card. - this.addAbility(new AttacksTriggeredAbility(new VaultbreakerEffect(), true)); - - // Dash {2}{R} - this.addAbility(new DashAbility(this, "{2}{R}")); - - } - - public Vaultbreaker(final Vaultbreaker card) { - super(card); - } - - @Override - public Vaultbreaker copy() { - return new Vaultbreaker(this); - } -} - -class VaultbreakerEffect extends OneShotEffect { - - VaultbreakerEffect() { - super(Outcome.Neutral); - staticText = "you may discard a card. If you do, draw a card"; - } - - VaultbreakerEffect(final VaultbreakerEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Cards discardedCard = controller.discard(1, false, source, game); - if (discardedCard != null) { - controller.drawCards(1, game); - return true; - } - } - return false; - } - - @Override - public VaultbreakerEffect copy() { - return new VaultbreakerEffect(this); - } -} +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fatereforged; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.DashAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author jeffwadsworth + */ +public class Vaultbreaker extends CardImpl { + + public Vaultbreaker(UUID ownerId) { + super(ownerId, 117, "Vaultbreaker", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{R}"); + this.expansionSetCode = "FRF"; + this.subtype.add("Orc"); + this.subtype.add("Rogue"); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // Whenever Vaultbreaker attacks, you may discard a card. If you do, draw a card. + this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new DrawCardSourceControllerEffect(1), + new DiscardCardCost()), false, "Whenever {this} attacks, you may discard a card. If you do, draw a card")); + + // Dash {2}{R} + this.addAbility(new DashAbility(this, "{2}{R}")); + + } + + public Vaultbreaker(final Vaultbreaker card) { + super(card); + } + + @Override + public Vaultbreaker copy() { + return new Vaultbreaker(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fifthdawn/ChannelTheSuns.java b/Mage.Sets/src/mage/sets/fifthdawn/ChannelTheSuns.java index 099b9cb6203..5d126de1ae5 100644 --- a/Mage.Sets/src/mage/sets/fifthdawn/ChannelTheSuns.java +++ b/Mage.Sets/src/mage/sets/fifthdawn/ChannelTheSuns.java @@ -48,7 +48,7 @@ public class ChannelTheSuns extends CardImpl { // Add {W}{U}{B}{R}{G} to your mana pool. - Effect effect = new AddManaToManaPoolSourceControllerEffect(new Mana(1, 1, 1, 1, 1, 0, 0)); + Effect effect = new AddManaToManaPoolSourceControllerEffect(new Mana(1, 1, 1, 1, 1, 0, 0, 0)); this.getSpellAbility().addEffect(effect); } diff --git a/Mage.Sets/src/mage/sets/fifthdawn/DisruptionAura.java b/Mage.Sets/src/mage/sets/fifthdawn/DisruptionAura.java index 9cb5e3fcf4a..a9515adb19c 100644 --- a/Mage.Sets/src/mage/sets/fifthdawn/DisruptionAura.java +++ b/Mage.Sets/src/mage/sets/fifthdawn/DisruptionAura.java @@ -112,7 +112,7 @@ class DisruptionAuraEffect extends OneShotEffect { Cost cost = permanent.getManaCost().copy(); if (player.chooseUse(Outcome.Benefit, message, source, game)) { cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/fifthdawn/MagneticTheft.java b/Mage.Sets/src/mage/sets/fifthdawn/MagneticTheft.java index 613dbe9b47f..37d9aac1d88 100644 --- a/Mage.Sets/src/mage/sets/fifthdawn/MagneticTheft.java +++ b/Mage.Sets/src/mage/sets/fifthdawn/MagneticTheft.java @@ -29,22 +29,16 @@ package mage.sets.fifthdawn; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.Zone; import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; -import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -58,7 +52,7 @@ public class MagneticTheft extends CardImpl { static { filter.add(new SubtypePredicate("Equipment")); } - + public MagneticTheft(UUID ownerId) { super(ownerId, 74, "Magnetic Theft", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{R}"); this.expansionSetCode = "5DN"; diff --git a/Mage.Sets/src/mage/sets/fifthdawn/PlungeIntoDarkness.java b/Mage.Sets/src/mage/sets/fifthdawn/PlungeIntoDarkness.java index f43581055ab..a0f0ecbc3b5 100644 --- a/Mage.Sets/src/mage/sets/fifthdawn/PlungeIntoDarkness.java +++ b/Mage.Sets/src/mage/sets/fifthdawn/PlungeIntoDarkness.java @@ -148,7 +148,7 @@ class PlungeIntoDarknessSearchEffect extends OneShotEffect { if (player != null) { VariableCost cost = new PayVariableLifeCost(); int xValue = cost.announceXValue(source, game); - cost.getFixedCostsFromAnnouncedValue(xValue).pay(source, game, source.getSourceId(), source.getControllerId(), false); + cost.getFixedCostsFromAnnouncedValue(xValue).pay(source, game, source.getSourceId(), source.getControllerId(), false, null); Cards cards = new CardsImpl(); int count = Math.min(player.getLibrary().size(), xValue); diff --git a/Mage.Sets/src/mage/sets/fifthdawn/PossessedPortal.java b/Mage.Sets/src/mage/sets/fifthdawn/PossessedPortal.java index 246be1f7596..fe1db00019a 100644 --- a/Mage.Sets/src/mage/sets/fifthdawn/PossessedPortal.java +++ b/Mage.Sets/src/mage/sets/fifthdawn/PossessedPortal.java @@ -130,11 +130,11 @@ class PossessedPortalEffect extends OneShotEffect { Cost discardCost = new DiscardCardCost(); if (discardCost.canPay(source, source.getSourceId(), playerId, game) && player.chooseUse(Outcome.Discard, "Discard a card? (Otherwise sacrifice a permanent)", source, game)) { - discardCost.pay(source, game, source.getSourceId(), playerId, true); + discardCost.pay(source, game, source.getSourceId(), playerId, true, null); } else { Cost sacrificeCost = new SacrificeTargetCost(new TargetControlledPermanent()); - sacrificeCost.pay(source, game, source.getSourceId(), playerId, true); + sacrificeCost.pay(source, game, source.getSourceId(), playerId, true, null); } } return true; diff --git a/Mage.Sets/src/mage/sets/fifthdawn/SylvokExplorer.java b/Mage.Sets/src/mage/sets/fifthdawn/SylvokExplorer.java index 0db79cfb655..22cb1c616c8 100644 --- a/Mage.Sets/src/mage/sets/fifthdawn/SylvokExplorer.java +++ b/Mage.Sets/src/mage/sets/fifthdawn/SylvokExplorer.java @@ -29,10 +29,11 @@ package mage.sets.fifthdawn; import java.util.UUID; import mage.MageInt; -import mage.abilities.mana.AnyColorOpponentLandsProduceManaAbility; +import mage.abilities.mana.AnyColorLandsProduceManaAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; +import mage.constants.TargetController; /** * @@ -50,7 +51,7 @@ public class SylvokExplorer extends CardImpl { this.toughness = new MageInt(1); // {T}: Add to your mana pool one mana of any color that a land an opponent controls could produce. - this.addAbility(new AnyColorOpponentLandsProduceManaAbility()); + this.addAbility(new AnyColorLandsProduceManaAbility(TargetController.OPPONENT)); } public SylvokExplorer(final SylvokExplorer card) { diff --git a/Mage.Sets/src/mage/sets/fifthedition/EternalWarrior.java b/Mage.Sets/src/mage/sets/fifthedition/EternalWarrior.java new file mode 100644 index 00000000000..87f177c9a04 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fifthedition/EternalWarrior.java @@ -0,0 +1,77 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fifthedition; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author icetc + */ +public class EternalWarrior extends CardImpl { + + public EternalWarrior(UUID ownerId) { + super(ownerId, 225, "Eternal Warrior", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{R}"); + this.expansionSetCode = "5ED"; + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchant creature has vigilance + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(VigilanceAbility.getInstance(), AttachmentType.AURA))); + } + + public EternalWarrior(final EternalWarrior card) { + super(card); + } + + @Override + public EternalWarrior copy() { + return new EternalWarrior(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/fifthedition/LibraryOfLeng.java b/Mage.Sets/src/mage/sets/fifthedition/LibraryOfLeng.java new file mode 100644 index 00000000000..a6dc94c1875 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fifthedition/LibraryOfLeng.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fifthedition; + +import java.util.UUID; + +/** + * + * @author LevelX2 + */ +public class LibraryOfLeng extends mage.sets.limitedbeta.LibraryOfLeng { + + public LibraryOfLeng(UUID ownerId) { + super(ownerId); + this.cardNumber = 387; + this.expansionSetCode = "5ED"; + } + + public LibraryOfLeng(final LibraryOfLeng card) { + super(card); + } + + @Override + public LibraryOfLeng copy() { + return new LibraryOfLeng(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fifthedition/Portent.java b/Mage.Sets/src/mage/sets/fifthedition/Portent.java new file mode 100644 index 00000000000..cd0e30a64a5 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fifthedition/Portent.java @@ -0,0 +1,130 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fifthedition; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPlayer; + +/** + * + * @author Plopman + */ +public class Portent extends CardImpl { + + public Portent(UUID ownerId) { + super(ownerId, 110, "Portent", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{U}"); + this.expansionSetCode = "5ED"; + + // Look at the top three cards of target player's library, then put them back in any order. You may have that player shuffle his or her library. + this.getSpellAbility().addEffect(new PortentEffect()); + this.getSpellAbility().addTarget(new TargetPlayer()); + // Draw a card at the beginning of the next turn's upkeep. + this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false)); + } + + public Portent(final Portent card) { + super(card); + } + + @Override + public Portent copy() { + return new Portent(this); + } +} + +class PortentEffect extends OneShotEffect { + + public PortentEffect() { + super(Outcome.DrawCard); + this.staticText = "look at the top three cards of target player's library, then put them back in any order. You may have that player shuffle his or her library."; + } + + public PortentEffect(final PortentEffect effect) { + super(effect); + } + + @Override + public PortentEffect copy() { + return new PortentEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player you = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(source.getFirstTarget()); + if (player == null || you == null) { + return false; + } + Cards cards = new CardsImpl(); + int count = Math.min(player.getLibrary().size(), 3); + for (int i = 0; i < count; i++) { + Card card = player.getLibrary().removeFromTop(game); + if (card != null) { + cards.add(card); + } + } + + you.lookAtCards("Portent", cards, game); + + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put on the top of target player's library")); + while (player.canRespond() && cards.size() > 1) { + you.choose(Outcome.Neutral, cards, target, game); + Card card = cards.get(target.getFirstTarget(), game); + if (card != null) { + cards.remove(card); + card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + } + target.clearChosen(); + } + if (cards.size() == 1) { + Card card = cards.get(cards.iterator().next(), game); + card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + } + if (you.chooseUse(Outcome.Neutral, "You may have that player shuffle his or her library", source, game)){ + player.shuffleLibrary(game); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java b/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java index 89b3e1445f8..bdf3615c080 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java +++ b/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java @@ -45,13 +45,11 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.WatcherScope; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; -import mage.target.TargetCard; import mage.target.common.TargetCardInHand; import mage.watchers.Watcher; @@ -135,26 +133,7 @@ class SylvanLibraryEffect extends OneShotEffect { } } } - int numberOfCardsToPutBack = cardsPutBack.size(); - if (numberOfCardsToPutBack > 1) { - TargetCard target2 = new TargetCard(Zone.HAND, new FilterCard("card to put on the top of your library (last chosen will be on top)")); - while (controller.canRespond() && cardsPutBack.size() > 1) { - controller.choose(Outcome.Benefit, cardsPutBack, target2, game); - Card card = cardsPutBack.get(target2.getFirstTarget(), game); - if (card != null) { - cardsPutBack.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - target2.clearChosen(); - } - } - if (cardsPutBack.size() == 1) { - Card card = cardsPutBack.get(cardsPutBack.iterator().next(), game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - if (numberOfCardsToPutBack > 0) { - game.informPlayers(controller.getLogName() + " puts " + numberOfCardsToPutBack + " card(s) back to library"); - } + controller.putCardsOnTopOfLibrary(cardsPutBack, game, source, applyEffectsAfter); } } return true; diff --git a/Mage.Sets/src/mage/sets/fifthedition/UrzasBauble.java b/Mage.Sets/src/mage/sets/fifthedition/UrzasBauble.java new file mode 100644 index 00000000000..c584f91a0b2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fifthedition/UrzasBauble.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fifthedition; + +import java.util.UUID; + +/** + * + * @author Plopman + */ +public class UrzasBauble extends mage.sets.mastersedition.UrzasBauble { + + public UrzasBauble(UUID ownerId) { + super(ownerId); + this.cardNumber = 406; + this.expansionSetCode = "5ED"; + } + + public UrzasBauble(final UrzasBauble card) { + super(card); + } + + @Override + public UrzasBauble copy() { + return new UrzasBauble(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fourthedition/EternalWarrior.java b/Mage.Sets/src/mage/sets/fourthedition/EternalWarrior.java new file mode 100644 index 00000000000..9aa9432187b --- /dev/null +++ b/Mage.Sets/src/mage/sets/fourthedition/EternalWarrior.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fourthedition; + +import java.util.UUID; + +/** + * + * @author icetc + */ +public class EternalWarrior extends mage.sets.fifthedition.EternalWarrior { + + public EternalWarrior(UUID ownerId) { + super(ownerId); + this.cardNumber = 208; + this.expansionSetCode = "4ED"; + } + + public EternalWarrior(final EternalWarrior card) { + super(card); + } + + @Override + public EternalWarrior copy() { + return new EternalWarrior(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fourthedition/ForceOfNature.java b/Mage.Sets/src/mage/sets/fourthedition/ForceOfNature.java index 49ae48923a3..a16192b11f0 100644 --- a/Mage.Sets/src/mage/sets/fourthedition/ForceOfNature.java +++ b/Mage.Sets/src/mage/sets/fourthedition/ForceOfNature.java @@ -97,7 +97,7 @@ class ForceOfNatureEffect extends OneShotEffect { Cost cost = new ManaCostsImpl("{G}{G}{G}{G}"); String message = "Would you like to pay {G}{G}{G}{G} to prevent taking 8 damage from {this}?"; if (!(controller.chooseUse(Outcome.Benefit, message, source, game) - && cost.pay(source, game, source.getSourceId(), controller.getId(), false))) { + && cost.pay(source, game, source.getSourceId(), controller.getId(), false, null))) { controller.damage(8, source.getSourceId(), game, false, true); } return true; diff --git a/Mage.Sets/src/mage/sets/fourthedition/LibraryOfLeng.java b/Mage.Sets/src/mage/sets/fourthedition/LibraryOfLeng.java new file mode 100644 index 00000000000..5cd8b91f3b2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fourthedition/LibraryOfLeng.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fourthedition; + +import java.util.UUID; + +/** + * + * @author LevelX2 + */ +public class LibraryOfLeng extends mage.sets.limitedbeta.LibraryOfLeng { + + public LibraryOfLeng(UUID ownerId) { + super(ownerId); + this.cardNumber = 351; + this.expansionSetCode = "4ED"; + } + + public LibraryOfLeng(final LibraryOfLeng card) { + super(card); + } + + @Override + public LibraryOfLeng copy() { + return new LibraryOfLeng(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fourthedition/SirensCall.java b/Mage.Sets/src/mage/sets/fourthedition/SirensCall.java index 2c3825ff87e..867118db72f 100644 --- a/Mage.Sets/src/mage/sets/fourthedition/SirensCall.java +++ b/Mage.Sets/src/mage/sets/fourthedition/SirensCall.java @@ -29,9 +29,11 @@ package mage.sets.fourthedition; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; -import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.condition.CompoundCondition; +import mage.abilities.condition.common.BeforeAttackersAreDeclaredCondition; +import mage.abilities.condition.common.OnOpponentsTurnCondition; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; @@ -39,12 +41,8 @@ import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; -import mage.constants.PhaseStep; import mage.constants.Rarity; -import mage.constants.TurnPhase; -import mage.constants.Zone; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.watchers.common.AttackedThisTurnWatcher; @@ -60,13 +58,13 @@ public class SirensCall extends CardImpl { this.expansionSetCode = "4ED"; // Cast Siren's Call only during an opponent's turn, before attackers are declared. - Ability ability = new SimpleStaticAbility(Zone.ALL, new SirensCallTimingEffect()); - ability.setRuleAtTheTop(true); - this.addAbility(ability); - + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, null, + new CompoundCondition(OnOpponentsTurnCondition.getInstance(), BeforeAttackersAreDeclaredCondition.getInstance()), + "Cast {this} only during an opponent's turn, before attackers are declared")); + // Creatures the active player controls attack this turn if able. this.getSpellAbility().addEffect(new SirensCallMustAttackEffect()); - + // At the beginning of the next end step, destroy all non-Wall creatures that player controls that didn't attack this turn. Ignore this effect for each creature the player didn't control continuously since the beginning of the turn. this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new SirensCallDestroyEffect()))); this.getSpellAbility().addWatcher(new AttackedThisTurnWatcher()); @@ -82,44 +80,6 @@ public class SirensCall extends CardImpl { } } -class SirensCallTimingEffect extends ContinuousRuleModifyingEffectImpl { - - SirensCallTimingEffect() { - super(Duration.EndOfGame, Outcome.Detriment); - staticText = "Cast {this} only during an opponent's turn, before attackers are declared"; - } - - SirensCallTimingEffect(final SirensCallTimingEffect effect) { - super(effect); - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.CAST_SPELL; - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getSourceId().equals(source.getSourceId())) { - if (game.getPhase().getType().equals(TurnPhase.BEGINNING) || game.getStep().getType().equals(PhaseStep.BEGIN_COMBAT)) { - return !game.getOpponents(source.getControllerId()).contains(game.getActivePlayerId()); - } - return true; - } - return false; - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public SirensCallTimingEffect copy() { - return new SirensCallTimingEffect(this); - } -} - class SirensCallMustAttackEffect extends RequirementEffect { SirensCallMustAttackEffect() { @@ -154,21 +114,21 @@ class SirensCallMustAttackEffect extends RequirementEffect { } class SirensCallDestroyEffect extends OneShotEffect { - + SirensCallDestroyEffect() { super(Outcome.DestroyPermanent); this.staticText = "destroy all non-Wall creatures that player controls that didn't attack this turn. Ignore this effect for each creature the player didn't control continuously since the beginning of the turn"; } - + SirensCallDestroyEffect(final SirensCallDestroyEffect effect) { super(effect); } - + @Override public SirensCallDestroyEffect copy() { return new SirensCallDestroyEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(game.getActivePlayerId()); diff --git a/Mage.Sets/src/mage/sets/fridaynightmagic/Anticipate.java b/Mage.Sets/src/mage/sets/fridaynightmagic/Anticipate.java index b526917ea2a..407e8e35a32 100644 --- a/Mage.Sets/src/mage/sets/fridaynightmagic/Anticipate.java +++ b/Mage.Sets/src/mage/sets/fridaynightmagic/Anticipate.java @@ -37,7 +37,7 @@ public class Anticipate extends mage.sets.dragonsoftarkir.Anticipate { public Anticipate(UUID ownerId) { super(ownerId); - this.cardNumber = 186; + this.cardNumber = 187; this.expansionSetCode = "FNMP"; } diff --git a/Mage.Sets/src/mage/sets/fridaynightmagic/ClashOfWills.java b/Mage.Sets/src/mage/sets/fridaynightmagic/ClashOfWills.java index c618d297558..7436107c493 100644 --- a/Mage.Sets/src/mage/sets/fridaynightmagic/ClashOfWills.java +++ b/Mage.Sets/src/mage/sets/fridaynightmagic/ClashOfWills.java @@ -37,7 +37,7 @@ public class ClashOfWills extends mage.sets.magicorigins.ClashOfWills { public ClashOfWills(UUID ownerId) { super(ownerId); - this.cardNumber = 188; + this.cardNumber = 189; this.expansionSetCode = "FNMP"; } diff --git a/Mage.Sets/src/mage/sets/fridaynightmagic/NissasPilgrimage.java b/Mage.Sets/src/mage/sets/fridaynightmagic/NissasPilgrimage.java index 5607bc55a65..e5c2c2ac77d 100644 --- a/Mage.Sets/src/mage/sets/fridaynightmagic/NissasPilgrimage.java +++ b/Mage.Sets/src/mage/sets/fridaynightmagic/NissasPilgrimage.java @@ -37,7 +37,7 @@ public class NissasPilgrimage extends mage.sets.magicorigins.NissasPilgrimage { public NissasPilgrimage(UUID ownerId) { super(ownerId); - this.cardNumber = 187; + this.cardNumber = 188; this.expansionSetCode = "FNMP"; } diff --git a/Mage.Sets/src/mage/sets/fridaynightmagic/SmashToSmithereens.java b/Mage.Sets/src/mage/sets/fridaynightmagic/SmashToSmithereens.java new file mode 100644 index 00000000000..f7713432a21 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fridaynightmagic/SmashToSmithereens.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fridaynightmagic; + +import java.util.UUID; + +/** + * + * @author fireshoes + */ +public class SmashToSmithereens extends mage.sets.shadowmoor.SmashToSmithereens { + + public SmashToSmithereens(UUID ownerId) { + super(ownerId); + this.cardNumber = 190; + this.expansionSetCode = "FNMP"; + } + + public SmashToSmithereens(final SmashToSmithereens card) { + super(card); + } + + @Override + public SmashToSmithereens copy() { + return new SmashToSmithereens(this); + } +} diff --git a/Mage.Sets/src/mage/sets/futuresight/GlitteringWish.java b/Mage.Sets/src/mage/sets/futuresight/GlitteringWish.java index 102dbe5da1c..37741655d59 100644 --- a/Mage.Sets/src/mage/sets/futuresight/GlitteringWish.java +++ b/Mage.Sets/src/mage/sets/futuresight/GlitteringWish.java @@ -29,9 +29,9 @@ package mage.sets.futuresight; import java.util.Set; import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileSpellEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; @@ -41,7 +41,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.predicate.Predicate; +import mage.filter.predicate.mageobject.MulticoloredPredicate; import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; @@ -56,9 +56,9 @@ public class GlitteringWish extends CardImpl { super(ownerId, 156, "Glittering Wish", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{G}{W}"); this.expansionSetCode = "FUT"; - // You may choose a multicolored card you own from outside the game, reveal that card, and put it into your hand. Exile Glittering Wish. this.getSpellAbility().addEffect(new GlitteringWishEffect()); + this.getSpellAbility().addEffect(ExileSpellEffect.getInstance()); } public GlitteringWish(final GlitteringWish card) { @@ -73,27 +73,17 @@ public class GlitteringWish extends CardImpl { class GlitteringWishEffect extends OneShotEffect { - private static final String choiceText = "Choose a multicolored card you own from outside the game, and put it into your hand"; + private static final String choiceText = "Choose a multicolored card you own from outside the game (sideboard), and put it into your hand?"; - private static final FilterCard filter = new FilterCard("multicolored card"); - static{ - filter.add(new Predicate() { + private static final FilterCard filter = new FilterCard("multicolored cards"); - @Override - public boolean apply(MageObject input, Game game) { - return input.getColor(game).isMulticolored(); - } - - @Override - public String toString() { - return "Multicolored"; - } - }); + static { + filter.add(new MulticoloredPredicate()); } public GlitteringWishEffect() { super(Outcome.Benefit); - this.staticText = "You may choose a multicolored card you own from outside the game, reveal that card, and put it into your hand. Exile Glittering Wish"; + this.staticText = "You may choose a multicolored card you own from outside the game, reveal that card, and put it into your hand"; } public GlitteringWishEffect(final GlitteringWishEffect effect) { @@ -107,18 +97,18 @@ class GlitteringWishEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - while (player.chooseUse(Outcome.Benefit, choiceText, source, game)) { - Cards cards = player.getSideboard(); - if(cards.isEmpty()) { - game.informPlayer(player, "You have no cards outside the game."); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + while (controller.chooseUse(Outcome.Benefit, choiceText, source, game)) { + Cards cards = controller.getSideboard(); + if (cards.isEmpty()) { + game.informPlayer(controller, "You have no cards outside the game."); break; } Set filtered = cards.getCards(filter, game); if (filtered.isEmpty()) { - game.informPlayer(player, "You have no " + filter.getMessage() + " outside the game."); + game.informPlayer(controller, "You have no " + filter.getMessage() + " outside the game (your sideboard)."); break; } @@ -128,25 +118,21 @@ class GlitteringWishEffect extends OneShotEffect { } TargetCard target = new TargetCard(Zone.OUTSIDE, filter); - if (player.choose(Outcome.Benefit, filteredCards, target, game)) { - Card card = player.getSideboard().get(target.getFirstTarget(), game); + if (controller.choose(Outcome.Benefit, filteredCards, target, game)) { + Card card = controller.getSideboard().get(target.getFirstTarget(), game); if (card != null) { card.moveToZone(Zone.HAND, source.getSourceId(), game, false); Cards revealCard = new CardsImpl(); revealCard.add(card); - player.revealCards("Glittering Wish", revealCard, game); + controller.revealCards("Glittering Wish", revealCard, game); break; } } } - Card cardToExile = game.getCard(source.getSourceId()); - if(cardToExile != null) - { - cardToExile.moveToExile(null, "", source.getSourceId(), game); - } + } return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/futuresight/NimbusMaze.java b/Mage.Sets/src/mage/sets/futuresight/NimbusMaze.java index c842eee5936..9c5bc771a6e 100644 --- a/Mage.Sets/src/mage/sets/futuresight/NimbusMaze.java +++ b/Mage.Sets/src/mage/sets/futuresight/NimbusMaze.java @@ -31,6 +31,7 @@ import java.util.UUID; import mage.Mana; import mage.abilities.Ability; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.common.BasicManaEffect; @@ -114,7 +115,7 @@ class FilterPermanentCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { this.paid = true; return paid; } diff --git a/Mage.Sets/src/mage/sets/futuresight/Saltskitter.java b/Mage.Sets/src/mage/sets/futuresight/Saltskitter.java index f4e73a800f7..49653205457 100644 --- a/Mage.Sets/src/mage/sets/futuresight/Saltskitter.java +++ b/Mage.Sets/src/mage/sets/futuresight/Saltskitter.java @@ -30,7 +30,7 @@ package mage.sets.futuresight; import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; -import mage.abilities.effects.common.ExileReturnToBattlefieldOwnerNextEndStepEffect; +import mage.abilities.effects.common.ExileReturnBattlefieldOwnerNextEndStepSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; @@ -58,7 +58,7 @@ public class Saltskitter extends CardImpl { this.toughness = new MageInt(4); // Whenever another creature enters the battlefield, exile Saltskitter. Return Saltskitter to the battlefield under its owner's control at the beginning of the next end step. - this.addAbility(new EntersBattlefieldAllTriggeredAbility(new ExileReturnToBattlefieldOwnerNextEndStepEffect(true), filter)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility(new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(true), filter)); } public Saltskitter(final Saltskitter card) { diff --git a/Mage.Sets/src/mage/sets/gatecrash/Bioshift.java b/Mage.Sets/src/mage/sets/gatecrash/Bioshift.java index 9bed435422f..bef3060278d 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/Bioshift.java +++ b/Mage.Sets/src/mage/sets/gatecrash/Bioshift.java @@ -56,7 +56,7 @@ public class Bioshift extends CardImpl { // Move any number of +1/+1 counters from target creature onto another target creature with the same controller. getSpellAbility().addEffect(new MoveCounterFromTargetToTargetEffect()); getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature (you take counters from)"))); - getSpellAbility().addTarget(new BioshiftSecondTargetPermanent()); + getSpellAbility().addTarget(new BioshiftSecondTargetCreaturePermanent()); } @@ -113,14 +113,15 @@ class MoveCounterFromTargetToTargetEffect extends OneShotEffect { } } -class BioshiftSecondTargetPermanent extends TargetPermanent { +class BioshiftSecondTargetCreaturePermanent extends TargetCreaturePermanent { - BioshiftSecondTargetPermanent() { - super(); - this.filter = new FilterCreaturePermanent("another target creature with the same controller (counters go to)"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature with the same controller (counters go to)"); + + BioshiftSecondTargetCreaturePermanent() { + super(filter); } - BioshiftSecondTargetPermanent(final BioshiftSecondTargetPermanent target) { + BioshiftSecondTargetCreaturePermanent(final BioshiftSecondTargetCreaturePermanent target) { super(target); } @@ -137,7 +138,7 @@ class BioshiftSecondTargetPermanent extends TargetPermanent { } @Override - public BioshiftSecondTargetPermanent copy() { - return new BioshiftSecondTargetPermanent(this); + public BioshiftSecondTargetCreaturePermanent copy() { + return new BioshiftSecondTargetCreaturePermanent(this); } } diff --git a/Mage.Sets/src/mage/sets/gatecrash/BurningTreeEmissary.java b/Mage.Sets/src/mage/sets/gatecrash/BurningTreeEmissary.java index 5f3cb1626fe..43a304130e7 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/BurningTreeEmissary.java +++ b/Mage.Sets/src/mage/sets/gatecrash/BurningTreeEmissary.java @@ -52,7 +52,7 @@ public class BurningTreeEmissary extends CardImpl { this.toughness = new MageInt(2); // When Burning-Tree Emissary enters the battlefield, add {R}{G} to your mana pool. - this.addAbility(new EntersBattlefieldTriggeredAbility(new BasicManaEffect(new Mana(1,1,0,0,0,0,0)))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new BasicManaEffect(new Mana(1,1,0,0,0,0,0, 0)))); } public BurningTreeEmissary(final BurningTreeEmissary card) { diff --git a/Mage.Sets/src/mage/sets/gatecrash/GrislySpectacle.java b/Mage.Sets/src/mage/sets/gatecrash/GrislySpectacle.java index 700cc889663..c2fe2c4229e 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/GrislySpectacle.java +++ b/Mage.Sets/src/mage/sets/gatecrash/GrislySpectacle.java @@ -53,15 +53,15 @@ import mage.target.targetpointer.FixedTarget; public class GrislySpectacle extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonartifact creature"); + static { filter.add(Predicates.not(new CardTypePredicate(CardType.ARTIFACT))); } - public GrislySpectacle (UUID ownerId) { + public GrislySpectacle(UUID ownerId) { super(ownerId, 66, "Grisly Spectacle", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{2}{B}{B}"); this.expansionSetCode = "GTC"; - // Destroy target nonartifact creature. Its controller puts a number of cards equal to that creature's power from the top of his or her library into his or her graveyard. this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addEffect(new GrislySpectacleEffect()); @@ -73,7 +73,7 @@ public class GrislySpectacle extends CardImpl { } @Override - public GrislySpectacle copy() { + public GrislySpectacle copy() { return new GrislySpectacle(this); } } @@ -96,7 +96,6 @@ class GrislySpectacleEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - // the mill effect works also if creature is indestructible or regenerated Permanent creature = game.getPermanentOrLKIBattlefield(this.getTargetPointer().getFirst(game, source)); if (creature != null) { Player controller = game.getPlayer(creature.getControllerId()); diff --git a/Mage.Sets/src/mage/sets/gatecrash/IncursionSpecialist.java b/Mage.Sets/src/mage/sets/gatecrash/IncursionSpecialist.java index 915acc973a2..e6e49c66bd3 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/IncursionSpecialist.java +++ b/Mage.Sets/src/mage/sets/gatecrash/IncursionSpecialist.java @@ -1,151 +1,110 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ -package mage.sets.gatecrash; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; -import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.cards.CardImpl; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Rarity; -import mage.constants.WatcherScope; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.stack.Spell; -import mage.watchers.Watcher; - -/** - * - * @author jeffwadsworth - */ -public class IncursionSpecialist extends CardImpl { - - public IncursionSpecialist(UUID ownerId) { - super(ownerId, 38, "Incursion Specialist", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{U}"); - this.expansionSetCode = "GTC"; - this.subtype.add("Human"); - this.subtype.add("Wizard"); - - this.power = new MageInt(1); - this.toughness = new MageInt(3); - - // Whenever you cast your second spell each turn, Incursion Specialist gets +2/+0 until end of turn and can't be blocked this turn. - this.addAbility(new IncursionTriggeredAbility(), new IncursionWatcher()); - } - - public IncursionSpecialist(final IncursionSpecialist card) { - super(card); - } - - @Override - public IncursionSpecialist copy() { - return new IncursionSpecialist(this); - } -} - -class IncursionTriggeredAbility extends TriggeredAbilityImpl { - - public IncursionTriggeredAbility() { - super(Zone.BATTLEFIELD, new BoostSourceEffect(2, 0, Duration.EndOfTurn)); - this.addEffect(new CantBeBlockedSourceEffect(Duration.EndOfTurn)); - } - - public IncursionTriggeredAbility(final IncursionTriggeredAbility ability) { - super(ability); - } - - @Override - public IncursionTriggeredAbility copy() { - return new IncursionTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == EventType.SPELL_CAST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getPlayerId().equals(controllerId)) { - Watcher watcher = game.getState().getWatchers().get("SecondSpellCast", controllerId); - if (watcher != null && watcher.conditionMet()) { - return true; - } - } - return false; - } - - @Override - public String getRule() { - return "Whenever you cast your second spell each turn, Incursion Specialist gets +2/+0 until end of turn and can't be blocked this turn."; - } -} - -class IncursionWatcher extends Watcher { - - int spellCount = 0; - - public IncursionWatcher() { - super("SecondSpellCast", WatcherScope.PLAYER); - } - - public IncursionWatcher(final IncursionWatcher watcher) { - super(watcher); - this.spellCount = watcher.spellCount; - } - - @Override - public IncursionWatcher copy() { - return new IncursionWatcher(this); - } - - @Override - public void watch(GameEvent event, Game game) { - condition = false; - if (event.getType() == GameEvent.EventType.SPELL_CAST && event.getPlayerId().equals(controllerId)) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null) { - spellCount++; - if (spellCount == 2) { - condition = true; - } - } - } - } - - @Override - public void reset() { - super.reset(); - spellCount = 0; - } -} \ No newline at end of file +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.gatecrash; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.watchers.common.CastSpellLastTurnWatcher; + +/** + * + * @author jeffwadsworth + */ +public class IncursionSpecialist extends CardImpl { + + public IncursionSpecialist(UUID ownerId) { + super(ownerId, 38, "Incursion Specialist", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{U}"); + this.expansionSetCode = "GTC"; + this.subtype.add("Human"); + this.subtype.add("Wizard"); + + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Whenever you cast your second spell each turn, Incursion Specialist gets +2/+0 until end of turn and can't be blocked this turn. + this.addAbility(new IncursionTriggeredAbility(), new CastSpellLastTurnWatcher()); + } + + public IncursionSpecialist(final IncursionSpecialist card) { + super(card); + } + + @Override + public IncursionSpecialist copy() { + return new IncursionSpecialist(this); + } +} + +class IncursionTriggeredAbility extends TriggeredAbilityImpl { + + public IncursionTriggeredAbility() { + super(Zone.BATTLEFIELD, new BoostSourceEffect(2, 0, Duration.EndOfTurn)); + this.addEffect(new CantBeBlockedSourceEffect(Duration.EndOfTurn)); + } + + public IncursionTriggeredAbility(final IncursionTriggeredAbility ability) { + super(ability); + } + + @Override + public IncursionTriggeredAbility copy() { + return new IncursionTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.SPELL_CAST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getPlayerId().equals(controllerId)) { + CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get("CastSpellLastTurnWatcher"); + if (watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) == 2) { + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever you cast your second spell each turn, Incursion Specialist gets +2/+0 until end of turn and can't be blocked this turn."; + } +} diff --git a/Mage.Sets/src/mage/sets/guildpact/Castigate.java b/Mage.Sets/src/mage/sets/guildpact/Castigate.java index b21755aab2f..b0a9aa10912 100644 --- a/Mage.Sets/src/mage/sets/guildpact/Castigate.java +++ b/Mage.Sets/src/mage/sets/guildpact/Castigate.java @@ -28,17 +28,13 @@ package mage.sets.guildpact; import java.util.UUID; - import mage.abilities.effects.common.ExileCardYouChooseTargetOpponentEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; -import mage.filter.Filter; import mage.filter.FilterCard; -import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; -import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.target.common.TargetOpponent; /** @@ -57,7 +53,6 @@ public class Castigate extends CardImpl { super(ownerId, 106, "Castigate", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{W}{B}"); this.expansionSetCode = "GPT"; - // Target opponent reveals his or her hand. You choose a nonland card from it and exile that card. this.getSpellAbility().addEffect(new ExileCardYouChooseTargetOpponentEffect(filter)); this.getSpellAbility().addTarget(new TargetOpponent()); diff --git a/Mage.Sets/src/mage/sets/guildpact/DjinnIlluminatus.java b/Mage.Sets/src/mage/sets/guildpact/DjinnIlluminatus.java new file mode 100644 index 00000000000..541d05d366e --- /dev/null +++ b/Mage.Sets/src/mage/sets/guildpact/DjinnIlluminatus.java @@ -0,0 +1,54 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.guildpact; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LevelX2 + */ +public class DjinnIlluminatus extends mage.sets.prereleaseevents.DjinnIlluminatus { + + public DjinnIlluminatus(UUID ownerId) { + super(ownerId); + this.cardNumber = 142; + this.expansionSetCode = "GPT"; + this.rarity = Rarity.RARE; + } + + public DjinnIlluminatus(final DjinnIlluminatus card) { + super(card); + } + + @Override + public DjinnIlluminatus copy() { + return new DjinnIlluminatus(this); + } +} diff --git a/Mage.Sets/src/mage/sets/guildpact/GhostCouncilOfOrzhova.java b/Mage.Sets/src/mage/sets/guildpact/GhostCouncilOfOrzhova.java index d3e22b9121b..92cf1d94667 100644 --- a/Mage.Sets/src/mage/sets/guildpact/GhostCouncilOfOrzhova.java +++ b/Mage.Sets/src/mage/sets/guildpact/GhostCouncilOfOrzhova.java @@ -35,7 +35,7 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ExileReturnToBattlefieldOwnerNextEndStepEffect; +import mage.abilities.effects.common.ExileReturnBattlefieldOwnerNextEndStepSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -67,7 +67,7 @@ public class GhostCouncilOfOrzhova extends CardImpl { this.addAbility(ability); // {1}, Sacrifice a creature: Exile Ghost Council of Orzhova. Return it to the battlefield under its owner's control at the beginning of the next end step. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileReturnToBattlefieldOwnerNextEndStepEffect(), new GenericManaCost(1)); + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(), new GenericManaCost(1)); ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent())); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/guildpact/Ghostway.java b/Mage.Sets/src/mage/sets/guildpact/Ghostway.java index ab0e57b2cc7..1b347e4d97e 100644 --- a/Mage.Sets/src/mage/sets/guildpact/Ghostway.java +++ b/Mage.Sets/src/mage/sets/guildpact/Ghostway.java @@ -27,6 +27,8 @@ */ package mage.sets.guildpact; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; @@ -34,19 +36,21 @@ import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbil 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.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.TargetController; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.targetpointer.FixedTarget; +import mage.target.targetpointer.FixedTargets; import mage.util.CardUtil; /** @@ -96,23 +100,21 @@ class GhostwayEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (sourceObject != null && controller != null) { + Set toExile = new HashSet<>(); + toExile.addAll(game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)); UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); - for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { - if (creature != null) { - int zcc = game.getState().getZoneChangeCounter(creature.getId()); - controller.moveCardToExileWithInfo(creature, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true); - if (zcc == game.getState().getZoneChangeCounter(creature.getId()) - 1) { - Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(); - effect.setTargetPointer(new FixedTarget(creature.getId(), zcc + 1)); - AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); + controller.moveCardsToExile(toExile, source, game, true, exileId, sourceObject.getIdName()); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); - } + Cards cardsToReturn = new CardsImpl(); + for (Card exiled : toExile) { + if (((Permanent) exiled).getZoneChangeCounter(game) == game.getState().getZoneChangeCounter(exiled.getId()) - 1) { + cardsToReturn.add(exiled); } } + Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(); + effect.setTargetPointer(new FixedTargets(cardsToReturn, game)); + AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/guildpact/GruulSignet.java b/Mage.Sets/src/mage/sets/guildpact/GruulSignet.java index 1bdaefefae5..6dbb3bac462 100644 --- a/Mage.Sets/src/mage/sets/guildpact/GruulSignet.java +++ b/Mage.Sets/src/mage/sets/guildpact/GruulSignet.java @@ -48,7 +48,7 @@ public class GruulSignet extends CardImpl { public GruulSignet(UUID ownerId) { super(ownerId, 150, "Gruul Signet", Rarity.COMMON, new CardType[]{CardType.ARTIFACT}, "{2}"); this.expansionSetCode = "GPT"; - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 0, 0, 0, 0, 0), new GenericManaCost(1)); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 0, 0, 0, 0, 0, 0), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/guildpact/IzzetBoilerworks.java b/Mage.Sets/src/mage/sets/guildpact/IzzetBoilerworks.java index e28721fdfbd..7b8e4e5ddc0 100644 --- a/Mage.Sets/src/mage/sets/guildpact/IzzetBoilerworks.java +++ b/Mage.Sets/src/mage/sets/guildpact/IzzetBoilerworks.java @@ -58,7 +58,7 @@ public class IzzetBoilerworks extends CardImpl { // When Izzet Boilerworks enters the battlefield, return a land you control to its owner's hand. this.addAbility(new EntersBattlefieldTriggeredAbility(new ReturnToHandChosenControlledPermanentEffect(filter), false)); // {T}: Add {U}{R} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 1, 0, 0, 0, 0), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 1, 0, 0, 0, 0, 0), new TapSourceCost())); } public IzzetBoilerworks(final IzzetBoilerworks card) { diff --git a/Mage.Sets/src/mage/sets/guildpact/IzzetSignet.java b/Mage.Sets/src/mage/sets/guildpact/IzzetSignet.java index 47bd30b3872..6648dfc9a2c 100644 --- a/Mage.Sets/src/mage/sets/guildpact/IzzetSignet.java +++ b/Mage.Sets/src/mage/sets/guildpact/IzzetSignet.java @@ -48,7 +48,7 @@ public class IzzetSignet extends CardImpl { public IzzetSignet(UUID ownerId) { super(ownerId, 152, "Izzet Signet", Rarity.COMMON, new CardType[]{CardType.ARTIFACT}, "{2}"); this.expansionSetCode = "GPT"; - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 1, 0, 0, 0, 0), new GenericManaCost(1)); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 1, 0, 0, 0, 0, 0), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/guildpact/LeylineOfLightning.java b/Mage.Sets/src/mage/sets/guildpact/LeylineOfLightning.java index 7a32bf2d730..ceecd7a6fe9 100644 --- a/Mage.Sets/src/mage/sets/guildpact/LeylineOfLightning.java +++ b/Mage.Sets/src/mage/sets/guildpact/LeylineOfLightning.java @@ -92,7 +92,7 @@ class LeylineOfLightningEffect extends DamageTargetEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null) { Cost cost = new GenericManaCost(1); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { super.apply(game, source); } return true; diff --git a/Mage.Sets/src/mage/sets/guildpact/OrzhovBasilica.java b/Mage.Sets/src/mage/sets/guildpact/OrzhovBasilica.java index 2ccb117762f..6039ffcbabf 100644 --- a/Mage.Sets/src/mage/sets/guildpact/OrzhovBasilica.java +++ b/Mage.Sets/src/mage/sets/guildpact/OrzhovBasilica.java @@ -60,7 +60,7 @@ public class OrzhovBasilica extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new ReturnToHandChosenControlledPermanentEffect(filter), false)); // {T}: Add {W}{B} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 1, 1, 0, 0), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 1, 1, 0, 0, 0), new TapSourceCost())); } public OrzhovBasilica(final OrzhovBasilica card) { diff --git a/Mage.Sets/src/mage/sets/guildpact/OrzhovSignet.java b/Mage.Sets/src/mage/sets/guildpact/OrzhovSignet.java index 069d2b43874..4cb0fb3805f 100644 --- a/Mage.Sets/src/mage/sets/guildpact/OrzhovSignet.java +++ b/Mage.Sets/src/mage/sets/guildpact/OrzhovSignet.java @@ -48,7 +48,7 @@ public class OrzhovSignet extends CardImpl { public OrzhovSignet(UUID ownerId) { super(ownerId, 155, "Orzhov Signet", Rarity.COMMON, new CardType[]{CardType.ARTIFACT}, "{2}"); this.expansionSetCode = "GPT"; - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 1, 1, 0, 0), new GenericManaCost(1)); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 1, 1, 0, 0, 0), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/guildpact/Schismotivate.java b/Mage.Sets/src/mage/sets/guildpact/Schismotivate.java index 4a1b7ac9ecb..ab92114de1d 100644 --- a/Mage.Sets/src/mage/sets/guildpact/Schismotivate.java +++ b/Mage.Sets/src/mage/sets/guildpact/Schismotivate.java @@ -37,6 +37,8 @@ import mage.constants.Layer; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.SubLayer; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; @@ -53,7 +55,17 @@ public class Schismotivate extends CardImpl { // Target creature gets +4/+0 until end of turn. Another target creature gets -4/-0 until end of turn. this.getSpellAbility().addEffect(new SchismotivateEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(2)); + + 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); } public Schismotivate(final Schismotivate card) { @@ -88,7 +100,7 @@ class SchismotivateEffect extends ContinuousEffectImpl { if (permanent != null) { permanent.addPower(4); } - permanent = game.getPermanent(source.getTargets().get(0).getTargets().get(1)); + permanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); if (permanent != null) { permanent.addPower(-4); } diff --git a/Mage.Sets/src/mage/sets/iceage/ChubToad.java b/Mage.Sets/src/mage/sets/iceage/ChubToad.java index 5b7cbdb0526..8d642896737 100644 --- a/Mage.Sets/src/mage/sets/iceage/ChubToad.java +++ b/Mage.Sets/src/mage/sets/iceage/ChubToad.java @@ -52,7 +52,7 @@ public class ChubToad extends CardImpl { this.toughness = new MageInt(1); // Whenever Chub Toad blocks or becomes blocked, it gets +2/+2 until end of turn. - Effect effect = new BoostSourceEffect(+1, +1, Duration.EndOfTurn); + Effect effect = new BoostSourceEffect(+2, +2, Duration.EndOfTurn); effect.setText("it gets +2/+2 until end of turn"); Ability ability = new BlocksOrBecomesBlockedTriggeredAbility(effect, false); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/iceage/ElementalAugury.java b/Mage.Sets/src/mage/sets/iceage/ElementalAugury.java new file mode 100644 index 00000000000..2dd332e0332 --- /dev/null +++ b/Mage.Sets/src/mage/sets/iceage/ElementalAugury.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.iceage; + +import java.util.UUID; + +/** + * + * @author Plopman + */ +public class ElementalAugury extends mage.sets.masterseditionii.ElementalAugury { + + public ElementalAugury(UUID ownerId) { + super(ownerId); + this.cardNumber = 364; + this.expansionSetCode = "ICE"; + } + + public ElementalAugury(final ElementalAugury card) { + super(card); + } + + @Override + public ElementalAugury copy() { + return new ElementalAugury(this); + } +} diff --git a/Mage.Sets/src/mage/sets/iceage/FyndhornElder.java b/Mage.Sets/src/mage/sets/iceage/FyndhornElder.java index 0d83d21f4b1..c98a70bca44 100644 --- a/Mage.Sets/src/mage/sets/iceage/FyndhornElder.java +++ b/Mage.Sets/src/mage/sets/iceage/FyndhornElder.java @@ -54,7 +54,7 @@ public class FyndhornElder extends CardImpl { this.toughness = new MageInt(1); // {tap}: Add {G}{G} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 2, 0, 0, 0, 0, 0), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 2, 0, 0, 0, 0, 0, 0), new TapSourceCost())); } public FyndhornElder(final FyndhornElder card) { diff --git a/Mage.Sets/src/mage/sets/iceage/MysticRemora.java b/Mage.Sets/src/mage/sets/iceage/MysticRemora.java index c3db8986718..79a08d7a1c0 100644 --- a/Mage.Sets/src/mage/sets/iceage/MysticRemora.java +++ b/Mage.Sets/src/mage/sets/iceage/MysticRemora.java @@ -145,7 +145,7 @@ class MysticRemoraTriggeredAbility extends TriggeredAbilityImpl { if (controller != null && opponent != null && sourceObject != null) { Cost cost = new GenericManaCost(4); String message = "Would you like to pay {4} to prevent the opponent to draw a card?"; - if (!(opponent.chooseUse(Outcome.Benefit, message, source, game) && cost.pay(source, game, source.getSourceId(), opponent.getId(), false))) { + if (!(opponent.chooseUse(Outcome.Benefit, message, source, game) && cost.pay(source, game, source.getSourceId(), opponent.getId(), false, null))) { if(controller.chooseUse(Outcome.DrawCard, "Draw a card (" + sourceObject.getLogName() +")", source, game)) { controller.drawCards(1, game); } diff --git a/Mage.Sets/src/mage/sets/iceage/Portent.java b/Mage.Sets/src/mage/sets/iceage/Portent.java new file mode 100644 index 00000000000..ff17da89fa8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/iceage/Portent.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.iceage; + +import java.util.UUID; + +/** + * + * @author Plopman + */ +public class Portent extends mage.sets.fifthedition.Portent { + + public Portent(UUID ownerId) { + super(ownerId); + this.cardNumber = 90; + this.expansionSetCode = "ICE"; + } + + public Portent(final Portent card) { + super(card); + } + + @Override + public Portent copy() { + return new Portent(this); + } +} diff --git a/Mage.Sets/src/mage/sets/iceage/Seizures.java b/Mage.Sets/src/mage/sets/iceage/Seizures.java index df24823b79e..7d2cb8b989d 100644 --- a/Mage.Sets/src/mage/sets/iceage/Seizures.java +++ b/Mage.Sets/src/mage/sets/iceage/Seizures.java @@ -109,7 +109,7 @@ class SeizuresEffect extends OneShotEffect { if(cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + " to avoid damage?", source, game)) { cost.clearPaid(); - if(cost.pay(source, game, source.getSourceId(), player.getId(), false)) { + if(cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/iceage/ThunderWall.java b/Mage.Sets/src/mage/sets/iceage/ThunderWall.java new file mode 100644 index 00000000000..9f8141ed0e8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/iceage/ThunderWall.java @@ -0,0 +1,74 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.iceage; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author icetc + */ +public class ThunderWall extends CardImpl { + + public ThunderWall(UUID ownerId) { + super(ownerId, 104, "Thunder Wall", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); + this.expansionSetCode = "ICE"; + this.subtype.add("Wall"); + this.power = new MageInt(0); + this.toughness = new MageInt(2); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {U}: Thunder Wall gets +1/+1 until end of turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 1, Duration.EndOfTurn), new ManaCostsImpl("{U}"))); + } + + public ThunderWall(final ThunderWall card) { + super(card); + } + + @Override + public ThunderWall copy() { + return new ThunderWall(this); + } +} diff --git a/Mage.Sets/src/mage/sets/iceage/UrzasBauble.java b/Mage.Sets/src/mage/sets/iceage/UrzasBauble.java new file mode 100644 index 00000000000..d5fa89ec47c --- /dev/null +++ b/Mage.Sets/src/mage/sets/iceage/UrzasBauble.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.iceage; + +import java.util.UUID; + +/** + * + * @author Plopman + */ +public class UrzasBauble extends mage.sets.mastersedition.UrzasBauble { + + public UrzasBauble(UUID ownerId) { + super(ownerId); + this.cardNumber = 318; + this.expansionSetCode = "ICE"; + } + + public UrzasBauble(final UrzasBauble card) { + super(card); + } + + @Override + public UrzasBauble copy() { + return new UrzasBauble(this); + } +} diff --git a/Mage.Sets/src/mage/sets/innistrad/BackFromTheBrink.java b/Mage.Sets/src/mage/sets/innistrad/BackFromTheBrink.java index 4565580087f..d78a21eb103 100644 --- a/Mage.Sets/src/mage/sets/innistrad/BackFromTheBrink.java +++ b/Mage.Sets/src/mage/sets/innistrad/BackFromTheBrink.java @@ -30,6 +30,7 @@ package mage.sets.innistrad; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.common.PutTokenOntoBattlefieldCopyTargetEffect; @@ -97,7 +98,7 @@ class BackFromTheBrinkCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { if (targets.choose(Outcome.Exile, controllerId, sourceId, game)) { Player controller = game.getPlayer(controllerId); if (controller != null) { diff --git a/Mage.Sets/src/mage/sets/innistrad/FrightfulDelusion.java b/Mage.Sets/src/mage/sets/innistrad/FrightfulDelusion.java index 12077bfd759..11c88ba6528 100644 --- a/Mage.Sets/src/mage/sets/innistrad/FrightfulDelusion.java +++ b/Mage.Sets/src/mage/sets/innistrad/FrightfulDelusion.java @@ -95,7 +95,7 @@ class FrightfulDelusionEffect extends OneShotEffect { game.getPlayer(spell.getControllerId()).discard( 1, false, source, game); if (!cost.pay(source, game, spell.getControllerId(), - spell.getControllerId(), false)) { + spell.getControllerId(), false, null)) { return game.getStack().counter(source.getFirstTarget(), source.getSourceId(), game); } diff --git a/Mage.Sets/src/mage/sets/innistrad/GhostQuarter.java b/Mage.Sets/src/mage/sets/innistrad/GhostQuarter.java index cad64ff772c..4b9c6107dff 100644 --- a/Mage.Sets/src/mage/sets/innistrad/GhostQuarter.java +++ b/Mage.Sets/src/mage/sets/innistrad/GhostQuarter.java @@ -96,7 +96,7 @@ class GhostQuarterEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) game.getPermanentOrLKIBattlefield(source.getFirstTarget()); // if indestructible effect should work also + Permanent permanent = game.getPermanentOrLKIBattlefield(source.getFirstTarget()); if (permanent != null) { Player controller = game.getPlayer(permanent.getControllerId()); if (controller.chooseUse(Outcome.PutLandInPlay, "Do you wish to search for a basic land, put it onto the battlefield and then shuffle your library?", source, game)) { diff --git a/Mage.Sets/src/mage/sets/innistrad/ScreechingBat.java b/Mage.Sets/src/mage/sets/innistrad/ScreechingBat.java index b3453bcd2e6..6ee01fb9cea 100644 --- a/Mage.Sets/src/mage/sets/innistrad/ScreechingBat.java +++ b/Mage.Sets/src/mage/sets/innistrad/ScreechingBat.java @@ -133,7 +133,7 @@ class ScreechingBatTransformSourceEffect extends OneShotEffect { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { Cost cost = new ManaCostsImpl("{2}{B}{B}"); - if (cost.pay(source, game, permanent.getControllerId(), permanent.getControllerId(), false)) { + if (cost.pay(source, game, permanent.getControllerId(), permanent.getControllerId(), false, null)) { if (permanent.canTransform()) { permanent.setTransformed(!permanent.isTransformed()); } diff --git a/Mage.Sets/src/mage/sets/innistrad/TributeToHunger.java b/Mage.Sets/src/mage/sets/innistrad/TributeToHunger.java index e7bd142dee3..97c8a7d2dc0 100644 --- a/Mage.Sets/src/mage/sets/innistrad/TributeToHunger.java +++ b/Mage.Sets/src/mage/sets/innistrad/TributeToHunger.java @@ -28,16 +28,13 @@ package mage.sets.innistrad; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.TargetController; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.mageobject.CardTypePredicate; -import mage.filter.predicate.permanent.ControllerPredicate; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -87,20 +84,17 @@ class TributeToHungerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getTargets().getFirstTarget()); + Player opponent = game.getPlayer(source.getTargets().getFirstTarget()); Player controller = game.getPlayer(source.getControllerId()); - - FilterControlledPermanent filter = new FilterControlledPermanent("creature"); - filter.add(new CardTypePredicate(CardType.CREATURE)); - filter.add(new ControllerPredicate(TargetController.YOU)); - TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, false); - - if (target.canChoose(player.getId(), game)) { - player.chooseTarget(Outcome.Sacrifice, target, source, game); - Permanent permanent = game.getPermanent(target.getFirstTarget()); - if (permanent != null) { - permanent.sacrifice(source.getSourceId(), game); - controller.gainLife(permanent.getToughness().getValue(), game); + if (controller != null && opponent != null) { + TargetControlledPermanent target = new TargetControlledPermanent(1, 1, new FilterControlledCreaturePermanent(), true); + if (target.canChoose(opponent.getId(), game)) { + opponent.chooseTarget(Outcome.Sacrifice, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + permanent.sacrifice(source.getSourceId(), game); + controller.gainLife(permanent.getToughness().getValue(), game); + } } return true; } diff --git a/Mage.Sets/src/mage/sets/invasion/AncientSpring.java b/Mage.Sets/src/mage/sets/invasion/AncientSpring.java index 024083280e8..9f9cefc3ce6 100644 --- a/Mage.Sets/src/mage/sets/invasion/AncientSpring.java +++ b/Mage.Sets/src/mage/sets/invasion/AncientSpring.java @@ -55,7 +55,7 @@ public class AncientSpring extends CardImpl { // {tap}: Add {U} to your mana pool. this.addAbility(new BlueManaAbility()); // {tap}, Sacrifice Ancient Spring: Add {W}{B} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 1, 1, 0, 0), new TapSourceCost()); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 1, 1, 0, 0, 0), new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/invasion/ChaoticStrike.java b/Mage.Sets/src/mage/sets/invasion/ChaoticStrike.java index b7724a2bdc0..7c904e7aa90 100644 --- a/Mage.Sets/src/mage/sets/invasion/ChaoticStrike.java +++ b/Mage.Sets/src/mage/sets/invasion/ChaoticStrike.java @@ -29,8 +29,8 @@ package mage.sets.invasion; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.AfterBlockersAreDeclaredCondition; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; @@ -38,12 +38,9 @@ import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; -import mage.constants.PhaseStep; import mage.constants.Rarity; import mage.constants.TurnPhase; -import mage.constants.Zone; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; @@ -59,14 +56,12 @@ public class ChaoticStrike extends CardImpl { this.expansionSetCode = "INV"; // Cast Chaotic Strike only during combat after blockers are declared. - Ability ability = new SimpleStaticAbility(Zone.ALL, new ChaoticStrikeRuleModifyingEffect()); - ability.setRuleAtTheTop(true); - this.addAbility(ability); - + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(TurnPhase.COMBAT, AfterBlockersAreDeclaredCondition.getInstance())); + // Flip a coin. If you win the flip, target creature gets +1/+1 until end of turn. this.getSpellAbility().addEffect(new ChaoticStrikeEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - + // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); } @@ -81,43 +76,6 @@ public class ChaoticStrike extends CardImpl { } } -class ChaoticStrikeRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl { - - ChaoticStrikeRuleModifyingEffect() { - super(Duration.EndOfGame, Outcome.Detriment); - staticText = "Cast {this} only during combat after blockers are declared"; - } - - ChaoticStrikeRuleModifyingEffect(final ChaoticStrikeRuleModifyingEffect effect) { - super(effect); - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType().equals(GameEvent.EventType.CAST_SPELL); - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getSourceId().equals(source.getSourceId())) { - return !game.getPhase().getType().equals(TurnPhase.COMBAT) || - game.getStep().getType().equals(PhaseStep.BEGIN_COMBAT) || - game.getStep().getType().equals(PhaseStep.DECLARE_ATTACKERS); - } - return false; - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public ChaoticStrikeRuleModifyingEffect copy() { - return new ChaoticStrikeRuleModifyingEffect(this); - } -} - class ChaoticStrikeEffect extends OneShotEffect { public ChaoticStrikeEffect() { @@ -137,8 +95,8 @@ class ChaoticStrikeEffect extends OneShotEffect { if (controller.flipCoin(game)) { game.addEffect(new BoostTargetEffect(1, 1, Duration.EndOfTurn), source); return true; - } } + } return false; } diff --git a/Mage.Sets/src/mage/sets/invasion/CrosissAttendant.java b/Mage.Sets/src/mage/sets/invasion/CrosissAttendant.java index 69a954c5964..afc878a98f8 100644 --- a/Mage.Sets/src/mage/sets/invasion/CrosissAttendant.java +++ b/Mage.Sets/src/mage/sets/invasion/CrosissAttendant.java @@ -54,7 +54,7 @@ public class CrosissAttendant extends CardImpl { this.toughness = new MageInt(3); // {1}, Sacrifice Crosis's Attendant: Add {U}{B}{R} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 1, 0, 1, 0, 0), new ManaCostsImpl("{1}")); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 1, 0, 1, 0, 0, 0), new ManaCostsImpl("{1}")); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/invasion/DarigaazsAttendant.java b/Mage.Sets/src/mage/sets/invasion/DarigaazsAttendant.java index dbaaf070443..488f79b1570 100644 --- a/Mage.Sets/src/mage/sets/invasion/DarigaazsAttendant.java +++ b/Mage.Sets/src/mage/sets/invasion/DarigaazsAttendant.java @@ -54,7 +54,7 @@ public class DarigaazsAttendant extends CardImpl { this.toughness = new MageInt(3); // {1}, Sacrifice Darigaaz's Attendant: Add {B}{R}{G} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 0, 0, 1, 0, 0), new ManaCostsImpl("{1}")); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 0, 0, 1, 0, 0, 0), new ManaCostsImpl("{1}")); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/invasion/DromarsAttendant.java b/Mage.Sets/src/mage/sets/invasion/DromarsAttendant.java index 183d0723041..27a482fbc9c 100644 --- a/Mage.Sets/src/mage/sets/invasion/DromarsAttendant.java +++ b/Mage.Sets/src/mage/sets/invasion/DromarsAttendant.java @@ -54,7 +54,7 @@ public class DromarsAttendant extends CardImpl { this.toughness = new MageInt(3); // {1}, Sacrifice Dromar's Attendant: Add {W}{U}{B} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 1, 1, 0, 0), new ManaCostsImpl("{1}")); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 1, 1, 0, 0, 0), new ManaCostsImpl("{1}")); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/invasion/GeothermalCrevice.java b/Mage.Sets/src/mage/sets/invasion/GeothermalCrevice.java index 9b29ec0ccb3..9d3efb862b7 100644 --- a/Mage.Sets/src/mage/sets/invasion/GeothermalCrevice.java +++ b/Mage.Sets/src/mage/sets/invasion/GeothermalCrevice.java @@ -57,7 +57,7 @@ public class GeothermalCrevice extends CardImpl { // {tap}: Add {R} to your mana pool. this.addAbility(new RedManaAbility()); // {tap}, Sacrifice Geothermal Crevice: Add {B}{G} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new BasicManaEffect(new Mana(0, 1, 0, 0, 1, 0, 0)), new TapSourceCost()); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new BasicManaEffect(new Mana(0, 1, 0, 0, 1, 0, 0, 0)), new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/invasion/IrrigationDitch.java b/Mage.Sets/src/mage/sets/invasion/IrrigationDitch.java index 6a6f5ac57ea..7ae6ec0e6a0 100644 --- a/Mage.Sets/src/mage/sets/invasion/IrrigationDitch.java +++ b/Mage.Sets/src/mage/sets/invasion/IrrigationDitch.java @@ -55,7 +55,7 @@ public class IrrigationDitch extends CardImpl { // {tap}: Add {W} to your mana pool. this.addAbility(new WhiteManaAbility()); // {tap}, Sacrifice Irrigation Ditch: Add {G}{U} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 1, 0, 0, 0, 0), new TapSourceCost()); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 1, 0, 0, 0, 0, 0), new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/invasion/Liberate.java b/Mage.Sets/src/mage/sets/invasion/Liberate.java index 9543953f2da..80c62589ced 100644 --- a/Mage.Sets/src/mage/sets/invasion/Liberate.java +++ b/Mage.Sets/src/mage/sets/invasion/Liberate.java @@ -45,7 +45,7 @@ import mage.target.common.TargetControlledCreaturePermanent; /** * * @author LoneFox - + * */ public class Liberate extends CardImpl { @@ -83,13 +83,10 @@ class LiberateEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getFirstTarget()); MageObject sourceObject = game.getObject(source.getSourceId()); - if(permanent != null && sourceObject != null) { - if(permanent.moveToExile(source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game)) { + if (permanent != null && sourceObject != null) { + if (permanent.moveToExile(source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game)) { AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnFromExileEffect(source.getSourceId(), Zone.BATTLEFIELD, false)); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } } diff --git a/Mage.Sets/src/mage/sets/invasion/RithsAttendant.java b/Mage.Sets/src/mage/sets/invasion/RithsAttendant.java index 0224f36a1cb..7785201c157 100644 --- a/Mage.Sets/src/mage/sets/invasion/RithsAttendant.java +++ b/Mage.Sets/src/mage/sets/invasion/RithsAttendant.java @@ -54,7 +54,7 @@ public class RithsAttendant extends CardImpl { this.toughness = new MageInt(3); // {1}, Sacrifice Rith's Attendant: Add {R}{G}{W} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 0, 1, 0, 0, 0), new ManaCostsImpl("{1}")); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 0, 1, 0, 0, 0, 0), new ManaCostsImpl("{1}")); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/invasion/SpinalEmbrace.java b/Mage.Sets/src/mage/sets/invasion/SpinalEmbrace.java index 70df654b48c..7e945c4c869 100644 --- a/Mage.Sets/src/mage/sets/invasion/SpinalEmbrace.java +++ b/Mage.Sets/src/mage/sets/invasion/SpinalEmbrace.java @@ -30,9 +30,8 @@ package mage.sets.invasion; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; -import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.UntapTargetEffect; @@ -46,11 +45,9 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.TurnPhase; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; @@ -63,6 +60,7 @@ import mage.target.targetpointer.FixedTarget; public class SpinalEmbrace extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you don't control"); + static { filter.add(new ControllerPredicate(TargetController.NOT_YOU)); } @@ -71,11 +69,9 @@ public class SpinalEmbrace extends CardImpl { super(ownerId, 276, "Spinal Embrace", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{3}{U}{U}{B}"); this.expansionSetCode = "INV"; - // Cast Spinal Embrace only during combat. - Ability ability = new SimpleStaticAbility(Zone.ALL, new SpinalEmbraceEffect()); - ability.setRuleAtTheTop(true); - this.addAbility(ability); + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(TurnPhase.COMBAT)); + // Untap target creature you don't control and gain control of it. It gains haste until end of turn. At the beginning of the next end step, sacrifice it. If you do, you gain life equal to its toughness. this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new UntapTargetEffect()); @@ -96,40 +92,6 @@ public class SpinalEmbrace extends CardImpl { } } -class SpinalEmbraceEffect extends ContinuousRuleModifyingEffectImpl { - SpinalEmbraceEffect() { - super(Duration.EndOfGame, Outcome.Detriment); - staticText = "Cast {this} only during combat"; - } - - SpinalEmbraceEffect(final SpinalEmbraceEffect effect) { - super(effect); - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType().equals(GameEvent.EventType.CAST_SPELL); - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getSourceId().equals(source.getSourceId())) { - return !TurnPhase.COMBAT.equals(game.getTurn().getPhaseType()); - } - return false; - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public SpinalEmbraceEffect copy() { - return new SpinalEmbraceEffect(this); - } -} - class SpinalEmbraceAddDelayedEffect extends OneShotEffect { public SpinalEmbraceAddDelayedEffect() { @@ -151,10 +113,7 @@ class SpinalEmbraceAddDelayedEffect extends OneShotEffect { SpinalEmbraceSacrificeEffect sacrificeEffect = new SpinalEmbraceSacrificeEffect(); sacrificeEffect.setTargetPointer(new FixedTarget(source.getFirstTarget())); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } } diff --git a/Mage.Sets/src/mage/sets/invasion/SulfurVent.java b/Mage.Sets/src/mage/sets/invasion/SulfurVent.java index 4f416284069..72f4f9e3ec2 100644 --- a/Mage.Sets/src/mage/sets/invasion/SulfurVent.java +++ b/Mage.Sets/src/mage/sets/invasion/SulfurVent.java @@ -55,7 +55,7 @@ public class SulfurVent extends CardImpl { // {tap}: Add {B} to your mana pool. this.addAbility(new BlackManaAbility()); // {tap}, Sacrifice Sulfur Vent: Add {U}{R} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 1, 0, 0, 0, 0), new TapSourceCost()); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 1, 0, 0, 0, 0, 0), new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/invasion/TinderFarm.java b/Mage.Sets/src/mage/sets/invasion/TinderFarm.java index 7a353d46f15..68b7eb05c0f 100644 --- a/Mage.Sets/src/mage/sets/invasion/TinderFarm.java +++ b/Mage.Sets/src/mage/sets/invasion/TinderFarm.java @@ -55,7 +55,7 @@ public class TinderFarm extends CardImpl { // {tap}: Add {G} to your mana pool. this.addAbility(new GreenManaAbility()); // {tap}, Sacrifice Tinder Farm: Add {R}{W} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 1, 0, 0, 0), new TapSourceCost()); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 1, 0, 0, 0, 0), new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/invasion/TrevasAttendant.java b/Mage.Sets/src/mage/sets/invasion/TrevasAttendant.java index ba5cd76f688..152798c0782 100644 --- a/Mage.Sets/src/mage/sets/invasion/TrevasAttendant.java +++ b/Mage.Sets/src/mage/sets/invasion/TrevasAttendant.java @@ -54,7 +54,7 @@ public class TrevasAttendant extends CardImpl { this.toughness = new MageInt(3); // {1}, Sacrifice Treva's Attendant: Add {G}{W}{U} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 1, 1, 0, 0, 0), new ManaCostsImpl("{1}")); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 1, 1, 0, 0, 0, 0), new ManaCostsImpl("{1}")); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/izzetvsgolgari/DjinnIlluminatus.java b/Mage.Sets/src/mage/sets/izzetvsgolgari/DjinnIlluminatus.java new file mode 100644 index 00000000000..0bf6697e383 --- /dev/null +++ b/Mage.Sets/src/mage/sets/izzetvsgolgari/DjinnIlluminatus.java @@ -0,0 +1,54 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.izzetvsgolgari; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LevelX2 + */ +public class DjinnIlluminatus extends mage.sets.prereleaseevents.DjinnIlluminatus { + + public DjinnIlluminatus(UUID ownerId) { + super(ownerId); + this.cardNumber = 12; + this.expansionSetCode = "DDJ"; + this.rarity = Rarity.RARE; + } + + public DjinnIlluminatus(final DjinnIlluminatus card) { + super(card); + } + + @Override + public DjinnIlluminatus copy() { + return new DjinnIlluminatus(this); + } +} diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/AthreosGodOfPassage.java b/Mage.Sets/src/mage/sets/journeyintonyx/AthreosGodOfPassage.java index 788102604eb..b700e7276e0 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/AthreosGodOfPassage.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/AthreosGodOfPassage.java @@ -131,7 +131,7 @@ class AthreosGodOfPassageReturnEffect extends OneShotEffect { Cost cost = new PayLifeCost(3); if (cost.canPay(source, source.getSourceId(), opponent.getId(), game) && opponent.chooseUse(outcome, new StringBuilder("Pay 3 live to prevent that ").append(creature.getLogName()).append(" returns to ").append(controller.getLogName()).append("'s hand?").toString(), source, game)) { - if (cost.pay(source, game, source.getSourceId(), opponent.getId(), false)) { + if (cost.pay(source, game, source.getSourceId(), opponent.getId(), false, null)) { paid = true; } } diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/DiscipleOfDeceit.java b/Mage.Sets/src/mage/sets/journeyintonyx/DiscipleOfDeceit.java index e5e87c1bbcc..49c62307c68 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/DiscipleOfDeceit.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/DiscipleOfDeceit.java @@ -105,7 +105,7 @@ class DiscipleOfDeceitEffect extends OneShotEffect { String message = "Discard a nonland card to search your library?"; if (cost.canPay(source, source.getSourceId(), source.getControllerId(), game) && player.chooseUse(Outcome.Detriment, message, source, game)) { - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { Card card = game.getCard(cost.getTargets().getFirstTarget()); if (card == null) { return false; diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/Godsend.java b/Mage.Sets/src/mage/sets/journeyintonyx/Godsend.java index bb0f16bed26..fc2f115706a 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/Godsend.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/Godsend.java @@ -75,9 +75,8 @@ public class Godsend extends CardImpl { this.supertype.add("Legendary"); this.subtype.add("Equipment"); - // Equipped creature gets +3/+3. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(3,3,Duration.WhileOnBattlefield))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(3, 3, Duration.WhileOnBattlefield))); // Whenever equipped creature blocks or becomes blocked by one or more creatures, you may exile one of those creatures. this.addAbility(new GodsendTriggeredAbility()); // Opponents can't cast cards with the same name as cards exiled with Godsend. @@ -99,7 +98,7 @@ public class Godsend extends CardImpl { class GodsendTriggeredAbility extends TriggeredAbilityImpl { private Set possibleTargets = new HashSet<>(); - + GodsendTriggeredAbility() { super(Zone.BATTLEFIELD, new GodsendExileEffect(), true); } @@ -121,29 +120,29 @@ class GodsendTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent equipment = game.getPermanentOrLKIBattlefield((this.getSourceId())); - if (equipment != null && equipment.getAttachedTo()!= null) { + if (equipment != null && equipment.getAttachedTo() != null) { Permanent equippedPermanent = game.getPermanentOrLKIBattlefield((equipment.getAttachedTo())); if (equippedPermanent != null) { possibleTargets.clear(); String targetName = ""; - if (equippedPermanent.isAttacking()) { - for (CombatGroup group: game.getCombat().getGroups()) { + if (equippedPermanent.isAttacking()) { + for (CombatGroup group : game.getCombat().getGroups()) { if (group.getAttackers().contains(equippedPermanent.getId())) { possibleTargets.addAll(group.getBlockers()); } } targetName = "a creature blocking attacker "; } else if (equippedPermanent.getBlocking() > 0) { - for (CombatGroup group: game.getCombat().getGroups()) { + for (CombatGroup group : game.getCombat().getGroups()) { if (group.getBlockers().contains(equippedPermanent.getId())) { possibleTargets.addAll(group.getAttackers()); } } targetName = "a creature blocked by creature "; - } - if (possibleTargets.size() > 0) { + } + if (possibleTargets.size() > 0) { this.getTargets().clear(); - if (possibleTargets.size() == 1) { + if (possibleTargets.size() == 1) { this.getEffects().get(0).setTargetPointer(new FixedTarget(possibleTargets.iterator().next())); } else { this.getEffects().get(0).setTargetPointer(new FirstTargetPointer()); @@ -170,21 +169,21 @@ class GodsendTriggeredAbility extends TriggeredAbilityImpl { } class GodsendExileEffect extends OneShotEffect { - + public GodsendExileEffect() { super(Outcome.Exile); this.staticText = "you may exile one of those creatures"; } - + public GodsendExileEffect(final GodsendExileEffect effect) { super(effect); } - + @Override public GodsendExileEffect copy() { return new GodsendExileEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Permanent creature = game.getPermanent(this.getTargetPointer().getFirst(game, source)); @@ -192,10 +191,9 @@ class GodsendExileEffect extends OneShotEffect { Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (creature != null && controller != null && sourcePermanent != null) { UUID exileId = CardUtil.getCardExileZoneId(game, source); - controller.moveCardToExileWithInfo(creature, exileId, - sourcePermanent.getIdName() + " (" + sourcePermanent.getZoneChangeCounter(game) + ")" - , source.getSourceId(), game, Zone.BATTLEFIELD, true); - + controller.moveCardToExileWithInfo(creature, exileId, + sourcePermanent.getIdName() + " (" + sourcePermanent.getZoneChangeCounter(game) + ")", source.getSourceId(), game, Zone.BATTLEFIELD, true); + } return false; } @@ -212,11 +210,6 @@ class GodsendRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl { super(effect); } - @Override - public boolean apply(Game game, Ability source) { - return true; - } - @Override public GodsendRuleModifyingEffect copy() { return new GodsendRuleModifyingEffect(this); @@ -238,11 +231,11 @@ class GodsendRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl { if (object != null) { ExileZone exileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)); if ((exileZone != null)) { - for(Card card:exileZone.getCards(game)) { + for (Card card : exileZone.getCards(game)) { if ((card.getName().equals(object.getName()))) { return true; } - } + } } } } diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/SageOfHours.java b/Mage.Sets/src/mage/sets/journeyintonyx/SageOfHours.java index 533f233b829..d29765a5759 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/SageOfHours.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/SageOfHours.java @@ -101,7 +101,7 @@ class SageOfHoursCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(ability.getSourceId()); if (permanent != null) { this.removedCounters = permanent.getCounters().getCount(CounterType.P1P1); diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/Skybind.java b/Mage.Sets/src/mage/sets/journeyintonyx/Skybind.java index 7bcf210b7fa..bb490687ee9 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/Skybind.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/Skybind.java @@ -61,7 +61,6 @@ public class Skybind extends CardImpl { super(ownerId, 25, "Skybind", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}{W}"); this.expansionSetCode = "JOU"; - // Constellation — When Skybind or another enchantment enters the battlefield under your control, exile target nonenchantment permanent. Return that card to the battlefield under its owner's control at the beginning of the next end step. Ability ability = new ConstellationAbility(new SkybindEffect(), false); ability.addTarget(new TargetPermanent(filter)); @@ -97,10 +96,7 @@ class SkybindEffect extends OneShotEffect { if (permanent.moveToExile(source.getSourceId(), sourcePermanent.getName(), source.getSourceId(), game)) { //create delayed triggered ability AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnFromExileEffect(source.getSourceId(), Zone.BATTLEFIELD)); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } } diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/Twinflame.java b/Mage.Sets/src/mage/sets/journeyintonyx/Twinflame.java index da065db84d5..3ab024ff6e6 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/Twinflame.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/Twinflame.java @@ -27,6 +27,7 @@ */ package mage.sets.journeyintonyx; +import java.util.ArrayList; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; @@ -45,6 +46,7 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import mage.target.targetpointer.FixedTargets; /** * @@ -94,23 +96,20 @@ class TwinflameCopyEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { + ArrayList toExile = new ArrayList<>(); for (UUID creatureId : this.getTargetPointer().getTargets(game, source)) { Permanent creature = game.getPermanentOrLKIBattlefield(creatureId); if (creature != null) { PutTokenOntoBattlefieldCopyTargetEffect effect = new PutTokenOntoBattlefieldCopyTargetEffect(source.getControllerId(), null, true); effect.setTargetPointer(new FixedTarget(creature, game)); effect.apply(game, source); - for (Permanent addedToken : effect.getAddedPermanent()) { - ExileTargetEffect exileEffect = new ExileTargetEffect(); - exileEffect.setTargetPointer(new FixedTarget(addedToken, game)); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); - } + toExile.addAll(effect.getAddedPermanent()); } } + ExileTargetEffect exileEffect = new ExileTargetEffect(); + exileEffect.setTargetPointer(new FixedTargets(toExile, game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/judgment/AnuridBrushhopper.java b/Mage.Sets/src/mage/sets/judgment/AnuridBrushhopper.java index d3be1aaddbb..e3151949e03 100644 --- a/Mage.Sets/src/mage/sets/judgment/AnuridBrushhopper.java +++ b/Mage.Sets/src/mage/sets/judgment/AnuridBrushhopper.java @@ -31,7 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.DiscardTargetCost; -import mage.abilities.effects.common.ExileReturnToBattlefieldOwnerNextEndStepEffect; +import mage.abilities.effects.common.ExileReturnBattlefieldOwnerNextEndStepSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; @@ -55,7 +55,7 @@ public class AnuridBrushhopper extends CardImpl { // Discard two cards: Exile Anurid Brushhopper. Return it to the battlefield under its owner's control at the beginning of the next end step. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, - new ExileReturnToBattlefieldOwnerNextEndStepEffect(true), + new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(true), new DiscardTargetCost(new TargetCardInHand(2, new FilterCard("two cards"))))); } diff --git a/Mage.Sets/src/mage/sets/judgment/AnuridSwarmsnapper.java b/Mage.Sets/src/mage/sets/judgment/AnuridSwarmsnapper.java new file mode 100644 index 00000000000..e53d5a6221d --- /dev/null +++ b/Mage.Sets/src/mage/sets/judgment/AnuridSwarmsnapper.java @@ -0,0 +1,70 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.judgment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.combat.CanBlockAdditionalCreatureEffect; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class AnuridSwarmsnapper extends CardImpl { + + public AnuridSwarmsnapper(UUID ownerId) { + super(ownerId, 105, "Anurid Swarmsnapper", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{G}"); + this.expansionSetCode = "JUD"; + this.subtype.add("Frog"); + this.subtype.add("Beast"); + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // Reach + this.addAbility(ReachAbility.getInstance()); + // {1}{G}: Anurid Swarmsnapper can block an additional creature this turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new CanBlockAdditionalCreatureEffect(Duration.EndOfTurn, 1), new ManaCostsImpl("{1}{G}"))); + } + + public AnuridSwarmsnapper(final AnuridSwarmsnapper card) { + super(card); + } + + @Override + public AnuridSwarmsnapper copy() { + return new AnuridSwarmsnapper(this); + } +} diff --git a/Mage.Sets/src/mage/sets/judgment/CanopyClaws.java b/Mage.Sets/src/mage/sets/judgment/CanopyClaws.java new file mode 100644 index 00000000000..a82f0dd29d6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/judgment/CanopyClaws.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.judgment; + +import java.util.UUID; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageAllEffect; +import mage.abilities.effects.common.continuous.LoseAbilityTargetEffect; +import mage.abilities.keyword.FlashbackAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TimingRule; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class CanopyClaws extends CardImpl { + + public CanopyClaws(UUID ownerId) { + super(ownerId, 108, "Canopy Claws", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{G}"); + this.expansionSetCode = "JUD"; + + // Target creature loses flying until end of turn. + this.getSpellAbility().addEffect(new LoseAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + // Flashback {G} + this.addAbility(new FlashbackAbility(new ManaCostsImpl("{G}"), TimingRule.INSTANT)); + } + + public CanopyClaws(final CanopyClaws card) { + super(card); + } + + @Override + public CanopyClaws copy() { + return new CanopyClaws(this); + } +} diff --git a/Mage.Sets/src/mage/sets/judgment/DefyGravity.java b/Mage.Sets/src/mage/sets/judgment/DefyGravity.java new file mode 100644 index 00000000000..78e71a19d09 --- /dev/null +++ b/Mage.Sets/src/mage/sets/judgment/DefyGravity.java @@ -0,0 +1,67 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.judgment; + +import java.util.UUID; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FlashbackAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TimingRule; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class DefyGravity extends CardImpl { + + public DefyGravity(UUID ownerId) { + super(ownerId, 38, "Defy Gravity", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{U}"); + this.expansionSetCode = "JUD"; + + // Target creature gains flying until end of turn. + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + // Flashback {U} + this.addAbility(new FlashbackAbility(new ManaCostsImpl("{U}"), TimingRule.INSTANT)); + } + + public DefyGravity(final DefyGravity card) { + super(card); + } + + @Override + public DefyGravity copy() { + return new DefyGravity(this); + } +} diff --git a/Mage.Sets/src/mage/sets/judgment/Envelop.java b/Mage.Sets/src/mage/sets/judgment/Envelop.java index 7a522b74895..99df4a891f4 100644 --- a/Mage.Sets/src/mage/sets/judgment/Envelop.java +++ b/Mage.Sets/src/mage/sets/judgment/Envelop.java @@ -1,69 +1,69 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ -package mage.sets.judgment; - -import java.util.UUID; -import mage.abilities.effects.common.CounterTargetEffect; -import mage.cards.CardImpl; -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.filter.FilterSpell; -import mage.filter.predicate.mageobject.CardTypePredicate; -import mage.target.TargetSpell; - -/** - * - * @author LevelX2 - */ -public class Envelop extends CardImpl { - - private static final FilterSpell filter = new FilterSpell("Sorcery"); - - static { - filter.add(new CardTypePredicate(CardType.SORCERY)); - } - - public Envelop(UUID ownerId) { - super(ownerId, 39, "Envelop", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{U}"); - this.expansionSetCode = "JUD"; - - - // Counter target sorcery spell. - this.getSpellAbility().addEffect(new CounterTargetEffect()); - this.getSpellAbility().addTarget(new TargetSpell(filter)); - } - - public Envelop(final Envelop card) { - super(card); - } - - @Override - public Envelop copy() { - return new Envelop(this); - } -} +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.judgment; + +import java.util.UUID; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.target.TargetSpell; + +/** + * + * @author LevelX2 + */ +public class Envelop extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("sorcery spell"); + + static { + filter.add(new CardTypePredicate(CardType.SORCERY)); + } + + public Envelop(UUID ownerId) { + super(ownerId, 39, "Envelop", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{U}"); + this.expansionSetCode = "JUD"; + + + // Counter target sorcery spell. + this.getSpellAbility().addEffect(new CounterTargetEffect()); + this.getSpellAbility().addTarget(new TargetSpell(filter)); + } + + public Envelop(final Envelop card) { + super(card); + } + + @Override + public Envelop copy() { + return new Envelop(this); + } +} diff --git a/Mage.Sets/src/mage/sets/judgment/ExoskeletalArmor.java b/Mage.Sets/src/mage/sets/judgment/ExoskeletalArmor.java new file mode 100644 index 00000000000..772c3b34805 --- /dev/null +++ b/Mage.Sets/src/mage/sets/judgment/ExoskeletalArmor.java @@ -0,0 +1,80 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.judgment; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreatureCard; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class ExoskeletalArmor extends CardImpl { + + public ExoskeletalArmor(UUID ownerId) { + super(ownerId, 114, "Exoskeletal Armor", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); + this.expansionSetCode = "JUD"; + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature gets +X/+X, where X is the number of creature cards in all graveyards. + CardsInAllGraveyardsCount count = new CardsInAllGraveyardsCount(new FilterCreatureCard()); + Effect effect = new BoostEnchantedEffect(count, count, Duration.WhileOnBattlefield); + effect.setText("Enchanted creature gets +X/+X, where X is the number of creature cards in all graveyards"); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public ExoskeletalArmor(final ExoskeletalArmor card) { + super(card); + } + + @Override + public ExoskeletalArmor copy() { + return new ExoskeletalArmor(this); + } +} diff --git a/Mage.Sets/src/mage/sets/judgment/Glory.java b/Mage.Sets/src/mage/sets/judgment/Glory.java new file mode 100644 index 00000000000..d510bf7de07 --- /dev/null +++ b/Mage.Sets/src/mage/sets/judgment/Glory.java @@ -0,0 +1,54 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.judgment; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class Glory extends mage.sets.prereleaseevents.Glory { + + public Glory(UUID ownerId) { + super(ownerId); + this.cardNumber = 11; + this.expansionSetCode = "JUD"; + this.rarity = Rarity.RARE; + } + + public Glory(final Glory card) { + super(card); + } + + @Override + public Glory copy() { + return new Glory(this); + } +} diff --git a/Mage.Sets/src/mage/sets/judgment/HarvesterDruid.java b/Mage.Sets/src/mage/sets/judgment/HarvesterDruid.java new file mode 100644 index 00000000000..e14b8b0a191 --- /dev/null +++ b/Mage.Sets/src/mage/sets/judgment/HarvesterDruid.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.judgment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.mana.AnyColorLandsProduceManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; + +/** + * + * @author LoneFox + */ +public class HarvesterDruid extends CardImpl { + + public HarvesterDruid(UUID ownerId) { + super(ownerId, 120, "Harvester Druid", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{G}"); + this.expansionSetCode = "JUD"; + this.subtype.add("Human"); + this.subtype.add("Druid"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {tap}: Add to your mana pool one mana of any color that a land you control could produce. + this.addAbility(new AnyColorLandsProduceManaAbility(TargetController.YOU)); + } + + public HarvesterDruid(final HarvesterDruid card) { + super(card); + } + + @Override + public HarvesterDruid copy() { + return new HarvesterDruid(this); + } +} diff --git a/Mage.Sets/src/mage/sets/judgment/HuntingGrounds.java b/Mage.Sets/src/mage/sets/judgment/HuntingGrounds.java new file mode 100644 index 00000000000..773badce237 --- /dev/null +++ b/Mage.Sets/src/mage/sets/judgment/HuntingGrounds.java @@ -0,0 +1,74 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.judgment; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.SpellCastOpponentTriggeredAbility; +import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.PutPermanentOnBattlefieldEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreatureCard; + +/** + * + * @author LoneFox + */ +public class HuntingGrounds extends CardImpl { + + public HuntingGrounds(UUID ownerId) { + super(ownerId, 138, "Hunting Grounds", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{G}{W}"); + this.expansionSetCode = "JUD"; + + // Threshold - As long as seven or more cards are in your graveyard, Hunting Grounds has "Whenever an opponent casts a spell, you may put a creature card from your hand onto the battlefield." + Ability gainedAbility = new SpellCastOpponentTriggeredAbility(new PutPermanentOnBattlefieldEffect( + new FilterCreatureCard("a creature card")), true); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new GainAbilitySourceEffect(gainedAbility, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), + "As long as seven or more cards are in your graveyard, {this} has \"Whenever an opponent casts a spell, you may put a creature card from your hand onto the battlefield.\"")); + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); + } + + public HuntingGrounds(final HuntingGrounds card) { + super(card); + } + + @Override + public HuntingGrounds copy() { + return new HuntingGrounds(this); + } +} diff --git a/Mage.Sets/src/mage/sets/judgment/MaskedGorgon.java b/Mage.Sets/src/mage/sets/judgment/MaskedGorgon.java new file mode 100644 index 00000000000..507de938f13 --- /dev/null +++ b/Mage.Sets/src/mage/sets/judgment/MaskedGorgon.java @@ -0,0 +1,94 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.judgment; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.ProtectionAbility; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author LoneFox + */ +public class MaskedGorgon extends CardImpl { + + private static final FilterCreaturePermanent filter1 = new FilterCreaturePermanent("green creatures and white creatures"); + private static final FilterCard filter2 = new FilterCard("Gorgons"); + private static final FilterCard filter3 = new FilterCard("green and from white"); + + static { + filter1.add(Predicates.or(new ColorPredicate(ObjectColor.GREEN), new ColorPredicate(ObjectColor.WHITE))); + filter2.add(new SubtypePredicate("Gorgon")); + filter3.add(Predicates.or(new ColorPredicate(ObjectColor.GREEN), new ColorPredicate(ObjectColor.WHITE))); + } + + public MaskedGorgon(UUID ownerId) { + super(ownerId, 69, "Masked Gorgon", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{4}{B}"); + this.expansionSetCode = "JUD"; + this.subtype.add("Gorgon"); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Green creatures and white creatures have protection from Gorgons. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect( + new ProtectionAbility(filter2), Duration.WhileOnBattlefield, filter1))); + // Threshold - Masked Gorgon has protection from green and from white as long as seven or more cards are in your graveyard. + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new GainAbilitySourceEffect(new ProtectionAbility(filter3), Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), + "{this} has protection from green and from white as long as seven or more cards are in your graveyard")); + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); + } + + public MaskedGorgon(final MaskedGorgon card) { + super(card); + } + + @Override + public MaskedGorgon copy() { + return new MaskedGorgon(this); + } +} diff --git a/Mage.Sets/src/mage/sets/judgment/SilverSeraph.java b/Mage.Sets/src/mage/sets/judgment/SilverSeraph.java new file mode 100644 index 00000000000..a8643e20119 --- /dev/null +++ b/Mage.Sets/src/mage/sets/judgment/SilverSeraph.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.judgment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class SilverSeraph extends CardImpl { + + public SilverSeraph(UUID ownerId) { + super(ownerId, 23, "Silver Seraph", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{5}{W}{W}{W}"); + this.expansionSetCode = "JUD"; + this.subtype.add("Angel"); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // Threshold - Other creatures you control get +2/+2 as long as seven or more cards are in your graveyard. + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostControlledEffect(2, 2, Duration.WhileOnBattlefield, true), new CardsInControllerGraveCondition(7), + "other creatures you control +2/+2 as long as seven or more cards are in your graveyard")); + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); + } + + public SilverSeraph(final SilverSeraph card) { + super(card); + } + + @Override + public SilverSeraph copy() { + return new SilverSeraph(this); + } +} diff --git a/Mage.Sets/src/mage/sets/judgment/SpellgorgerBarbarian.java b/Mage.Sets/src/mage/sets/judgment/SpellgorgerBarbarian.java new file mode 100644 index 00000000000..927f5e8ce73 --- /dev/null +++ b/Mage.Sets/src/mage/sets/judgment/SpellgorgerBarbarian.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.judgment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class SpellgorgerBarbarian extends CardImpl { + + public SpellgorgerBarbarian(UUID ownerId) { + super(ownerId, 100, "Spellgorger Barbarian", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{R}"); + this.expansionSetCode = "JUD"; + this.subtype.add("Human"); + this.subtype.add("Nightmare"); + this.subtype.add("Barbarian"); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // When Spellgorger Barbarian enters the battlefield, discard a card at random. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DiscardControllerEffect(1, true))); + // When Spellgorger Barbarian leaves the battlefield, draw a card. + this.addAbility(new LeavesBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1), false)); + } + + public SpellgorgerBarbarian(final SpellgorgerBarbarian card) { + super(card); + } + + @Override + public SpellgorgerBarbarian copy() { + return new SpellgorgerBarbarian(this); + } +} diff --git a/Mage.Sets/src/mage/sets/judgment/Swelter.java b/Mage.Sets/src/mage/sets/judgment/Swelter.java new file mode 100644 index 00000000000..d7ea8545eb9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/judgment/Swelter.java @@ -0,0 +1,60 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.judgment; + +import java.util.UUID; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class Swelter extends CardImpl { + + public Swelter(UUID ownerId) { + super(ownerId, 101, "Swelter", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{3}{R}"); + this.expansionSetCode = "JUD"; + + // Swelter deals 2 damage to each of two target creatures. + this.getSpellAbility().addEffect(new DamageTargetEffect(2, true, "each of two target creatures")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(2, 2)); + } + + public Swelter(final Swelter card) { + super(card); + } + + @Override + public Swelter copy() { + return new Swelter(this); + } +} diff --git a/Mage.Sets/src/mage/sets/judgment/TunnelerWurm.java b/Mage.Sets/src/mage/sets/judgment/TunnelerWurm.java new file mode 100644 index 00000000000..d9c828c64bf --- /dev/null +++ b/Mage.Sets/src/mage/sets/judgment/TunnelerWurm.java @@ -0,0 +1,65 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.judgment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class TunnelerWurm extends CardImpl { + + public TunnelerWurm(UUID ownerId) { + super(ownerId, 135, "Tunneler Wurm", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{6}{G}{G}"); + this.expansionSetCode = "JUD"; + this.subtype.add("Wurm"); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Discard a card: Regenerate Tunneler Wurm. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new DiscardCardCost())); + } + + public TunnelerWurm(final TunnelerWurm card) { + super(card); + } + + @Override + public TunnelerWurm copy() { + return new TunnelerWurm(this); + } +} diff --git a/Mage.Sets/src/mage/sets/judgment/VenomousVines.java b/Mage.Sets/src/mage/sets/judgment/VenomousVines.java new file mode 100644 index 00000000000..664bba4cd9a --- /dev/null +++ b/Mage.Sets/src/mage/sets/judgment/VenomousVines.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.judgment; + +import java.util.UUID; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.FilterPermanent; +import mage.filter.predicate.permanent.EnchantedPredicate; +import mage.target.TargetPermanent; + +/** + * + * @author LoneFox + */ +public class VenomousVines extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("enchanted permanent"); + + static { + filter.add(new EnchantedPredicate()); + } + + public VenomousVines(UUID ownerId) { + super(ownerId, 136, "Venomous Vines", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{2}{G}{G}"); + this.expansionSetCode = "JUD"; + + // Destroy target enchanted permanent. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + } + + public VenomousVines(final VenomousVines card) { + super(card); + } + + @Override + public VenomousVines copy() { + return new VenomousVines(this); + } +} diff --git a/Mage.Sets/src/mage/sets/judgment/VigilantSentry.java b/Mage.Sets/src/mage/sets/judgment/VigilantSentry.java new file mode 100644 index 00000000000..350d4b21848 --- /dev/null +++ b/Mage.Sets/src/mage/sets/judgment/VigilantSentry.java @@ -0,0 +1,83 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.judgment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.common.TargetAttackingOrBlockingCreature; + +/** + * + * @author LoneFox + */ +public class VigilantSentry extends CardImpl { + + public VigilantSentry(UUID ownerId) { + super(ownerId, 33, "Vigilant Sentry", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); + this.expansionSetCode = "JUD"; + this.subtype.add("Human"); + this.subtype.add("Nomad"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Threshold - As long as seven or more cards are in your graveyard, Vigilant Sentry gets +1/+1 and has "{tap}: Target attacking or blocking creature gets +3/+3 until end of turn." + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), + "As long as seven or more cards are in your graveyard, {this} gets +1/+1")); + Ability gainedAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(3, 3, Duration.EndOfTurn), new TapSourceCost()); + gainedAbility.addTarget(new TargetAttackingOrBlockingCreature()); + ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(gainedAbility), + new CardsInControllerGraveCondition(7), "and has \"{T}: Target attacking or blocking creature gets +3/+3 until end of turn.\"")); + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); + } + + public VigilantSentry(final VigilantSentry card) { + super(card); + } + + @Override + public VigilantSentry copy() { + return new VigilantSentry(this); + } +} diff --git a/Mage.Sets/src/mage/sets/judgment/WormfangDrake.java b/Mage.Sets/src/mage/sets/judgment/WormfangDrake.java index 15d030afde7..bc7b385611c 100644 --- a/Mage.Sets/src/mage/sets/judgment/WormfangDrake.java +++ b/Mage.Sets/src/mage/sets/judgment/WormfangDrake.java @@ -33,6 +33,7 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.effects.common.ReturnFromExileForSourceEffect; import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; @@ -103,7 +104,7 @@ class WormfangDrakeExileCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); MageObject sourceObject = ability.getSourceObject(game); if (controller != null && sourceObject != null) { diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/KheruLichLord.java b/Mage.Sets/src/mage/sets/khansoftarkir/KheruLichLord.java index 048f1d84fc0..43958e4aa70 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/KheruLichLord.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/KheruLichLord.java @@ -134,10 +134,7 @@ class KheruLichLordEffect extends OneShotEffect { ExileTargetEffect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(fixedTarget); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); KheruLichLordReplacementEffect replacementEffect = new KheruLichLordReplacementEffect(); replacementEffect.setTargetPointer(fixedTarget); diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/MarduWarshrieker.java b/Mage.Sets/src/mage/sets/khansoftarkir/MarduWarshrieker.java index 754c0bfdc42..86f6e5e6555 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/MarduWarshrieker.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/MarduWarshrieker.java @@ -55,7 +55,7 @@ public class MarduWarshrieker extends CardImpl { this.toughness = new MageInt(3); // Raid - When Mardu Warshrieker enters the battlefield, if you attacked with a creature this turn, add {R}{W}{B} to your mana pool. - this.addAbility(new ConditionalTriggeredAbility(new EntersBattlefieldTriggeredAbility(new AddManaToManaPoolSourceControllerEffect(new Mana(1, 0, 0, 1, 1, 0, 0))), RaidCondition.getInstance(), + this.addAbility(new ConditionalTriggeredAbility(new EntersBattlefieldTriggeredAbility(new AddManaToManaPoolSourceControllerEffect(new Mana(1, 0, 0, 1, 1, 0, 0, 0))), RaidCondition.getInstance(), "Raid - When {this} enters the battlefield, if you attacked with a creature this turn, add {R}{W}{B} to your mana pool."), new PlayerAttackedWatcher()); } diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/RattleclawMystic.java b/Mage.Sets/src/mage/sets/khansoftarkir/RattleclawMystic.java index 96e97ce61f4..b518f0676d8 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/RattleclawMystic.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/RattleclawMystic.java @@ -65,7 +65,7 @@ public class RattleclawMystic extends CardImpl { this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}"))); // When Rattleclaw Mystic is turned face up, add {G}{U}{R} to your mana pool. - this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new AddManaToManaPoolSourceControllerEffect(new Mana(1,1,1,0,0,0,0)))); + this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new AddManaToManaPoolSourceControllerEffect(new Mana(1,1,1,0,0,0,0, 0)))); } diff --git a/Mage.Sets/src/mage/sets/legends/ChainLightning.java b/Mage.Sets/src/mage/sets/legends/ChainLightning.java index 21f95b87186..f1e1227f655 100644 --- a/Mage.Sets/src/mage/sets/legends/ChainLightning.java +++ b/Mage.Sets/src/mage/sets/legends/ChainLightning.java @@ -105,7 +105,7 @@ class ChainLightningEffect extends OneShotEffect { if (affectedPlayer != null) { if (affectedPlayer.chooseUse(Outcome.Copy, "Pay {R}{R} to copy the spell?", source, game)) { Cost cost = new ManaCostsImpl("{R}{R}"); - if (cost.pay(source, game, source.getSourceId(), affectedPlayer.getId(), false)) { + if (cost.pay(source, game, source.getSourceId(), affectedPlayer.getId(), false, null)) { Spell spell = game.getStack().getSpell(source.getSourceId()); if (spell != null) { Spell copy = spell.copySpell(); diff --git a/Mage.Sets/src/mage/sets/legends/CosmicHorror.java b/Mage.Sets/src/mage/sets/legends/CosmicHorror.java index 0f0e6273f24..9e65ce2b958 100644 --- a/Mage.Sets/src/mage/sets/legends/CosmicHorror.java +++ b/Mage.Sets/src/mage/sets/legends/CosmicHorror.java @@ -100,7 +100,7 @@ class CosmicHorrorEffect extends OneShotEffect { } if (controller.chooseUse(Outcome.Benefit, sb.toString(), source, game)) { cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/legends/EternalWarrior.java b/Mage.Sets/src/mage/sets/legends/EternalWarrior.java new file mode 100644 index 00000000000..c9925185a07 --- /dev/null +++ b/Mage.Sets/src/mage/sets/legends/EternalWarrior.java @@ -0,0 +1,54 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.legends; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author icetc + */ +public class EternalWarrior extends mage.sets.fifthedition.EternalWarrior { + + public EternalWarrior(UUID ownerId) { + super(ownerId); + this.cardNumber = 142; + this.expansionSetCode = "LEG"; + this.rarity = Rarity.UNCOMMON; + } + + public EternalWarrior(final EternalWarrior card) { + super(card); + } + + @Override + public EternalWarrior copy() { + return new EternalWarrior(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/legends/HazezonTamar.java b/Mage.Sets/src/mage/sets/legends/HazezonTamar.java index 19ca690ac55..9a3aa3e5ff4 100644 --- a/Mage.Sets/src/mage/sets/legends/HazezonTamar.java +++ b/Mage.Sets/src/mage/sets/legends/HazezonTamar.java @@ -112,10 +112,7 @@ class HazezonTamarEntersEffect extends OneShotEffect { Effect effect = new CreateTokenEffect(new HazezonTamarSandWarrior(), new PermanentsOnBattlefieldCount(new FilterControlledLandPermanent())); effect.setText("put X 1/1 Sand Warrior creature tokens that are red, green, and white onto the battlefield, where X is the number of lands you control at that time"); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility(effect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/legends/Reset.java b/Mage.Sets/src/mage/sets/legends/Reset.java index 18820f1320f..271dea36f35 100644 --- a/Mage.Sets/src/mage/sets/legends/Reset.java +++ b/Mage.Sets/src/mage/sets/legends/Reset.java @@ -28,20 +28,14 @@ package mage.sets.legends; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; -import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.CompoundCondition; +import mage.abilities.condition.common.AfterUpkeepStepCondtion; +import mage.abilities.condition.common.OnOpponentsTurnCondition; import mage.abilities.effects.common.UntapAllLandsControllerEffect; import mage.cards.CardImpl; import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.PhaseStep; import mage.constants.Rarity; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; /** * @@ -53,11 +47,11 @@ public class Reset extends CardImpl { super(ownerId, 73, "Reset", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{U}{U}"); this.expansionSetCode = "LEG"; - // Cast Reset only during an opponent's turn after his or her upkeep step. - Ability ability = new SimpleStaticAbility(Zone.ALL, new ResetReplacementEffect()); - ability.setRuleAtTheTop(true); - this.addAbility(ability); + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, null, + new CompoundCondition(OnOpponentsTurnCondition.getInstance(), AfterUpkeepStepCondtion.getInstance()), + "Cast {this} only during an opponent's turn after his or her upkeep step")); + // Untap all lands you control. this.getSpellAbility().addEffect(new UntapAllLandsControllerEffect()); } @@ -71,37 +65,3 @@ public class Reset extends CardImpl { return new Reset(this); } } - -class ResetReplacementEffect extends ContinuousRuleModifyingEffectImpl { - ResetReplacementEffect() { - super(Duration.EndOfGame, Outcome.Detriment); - staticText = "Cast {this} only during an opponent's turn after his or her upkeep step"; - } - - ResetReplacementEffect(final ResetReplacementEffect effect) { - super(effect); - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType().equals(GameEvent.EventType.CAST_SPELL) && event.getSourceId().equals(source.getSourceId())) { - if (game.getTurn().getStepType().equals(PhaseStep.UNTAP) - || game.getTurn().getStepType().equals(PhaseStep.UPKEEP) - || !game.getOpponents(source.getControllerId()).contains(game.getActivePlayerId())) { - return true; - } - - } - return false; - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public ResetReplacementEffect copy() { - return new ResetReplacementEffect(this); - } -} diff --git a/Mage.Sets/src/mage/sets/legends/Sentinel.java b/Mage.Sets/src/mage/sets/legends/Sentinel.java index d4a4fd64e75..2d534a7e53e 100644 --- a/Mage.Sets/src/mage/sets/legends/Sentinel.java +++ b/Mage.Sets/src/mage/sets/legends/Sentinel.java @@ -33,7 +33,6 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.SetToughnessSourceEffect; import mage.cards.CardImpl; @@ -66,13 +65,12 @@ public class Sentinel extends CardImpl { FilterCreaturePermanent filter = new FilterCreaturePermanent("creature blocking or blocked by Sentinel"); filter.add(Predicates.or(new BlockedByIdPredicate(this.getId()), - new BlockingAttackerIdPredicate(this.getId()))); + new BlockingAttackerIdPredicate(this.getId()))); // 0: Change Sentinel's base toughness to 1 plus the power of target creature blocking or blocked by Sentinel. (This effect lasts indefinitely.) Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SentinelEffect(), new GenericManaCost(0)); - ability.addTarget(null); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); - + } public Sentinel(final Sentinel card) { @@ -86,21 +84,21 @@ public class Sentinel extends CardImpl { } class SentinelEffect extends OneShotEffect { - + public SentinelEffect() { super(Outcome.Detriment); this.staticText = "Change {this}'s base toughness to 1 plus the power of target creature blocking or blocked by {this}. (This effect lasts indefinitely.)"; } - + public SentinelEffect(final SentinelEffect effect) { super(effect); } - + @Override public SentinelEffect copy() { return new SentinelEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); diff --git a/Mage.Sets/src/mage/sets/legends/TheTabernacleAtPendrellVale.java b/Mage.Sets/src/mage/sets/legends/TheTabernacleAtPendrellVale.java index c938ac247c4..65012e33c2d 100644 --- a/Mage.Sets/src/mage/sets/legends/TheTabernacleAtPendrellVale.java +++ b/Mage.Sets/src/mage/sets/legends/TheTabernacleAtPendrellVale.java @@ -91,7 +91,7 @@ class DestroySourceUnlessPaysEffect extends OneShotEffect { if (player != null && permanent != null) { if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "?", source, game)) { cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/legions/ElvishSoultiller.java b/Mage.Sets/src/mage/sets/legions/ElvishSoultiller.java new file mode 100644 index 00000000000..014632be1d1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/legions/ElvishSoultiller.java @@ -0,0 +1,121 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.legions; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.cards.repository.CardRepository; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author LevelX2 + */ +public class ElvishSoultiller extends CardImpl { + + public ElvishSoultiller(UUID ownerId) { + super(ownerId, 124, "Elvish Soultiller", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); + this.expansionSetCode = "LGN"; + this.subtype.add("Elf"); + this.subtype.add("Mutant"); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // When Elvish Soultiller dies, choose a creature type. Shuffle all creature cards of that type from your graveyard into your library. + addAbility(new DiesTriggeredAbility(new ElvishSoultillerEffect())); + + } + + public ElvishSoultiller(final ElvishSoultiller card) { + super(card); + } + + @Override + public ElvishSoultiller copy() { + return new ElvishSoultiller(this); + } +} + +class ElvishSoultillerEffect extends OneShotEffect { + + public ElvishSoultillerEffect() { + super(Outcome.Benefit); + this.staticText = "choose a creature type. Shuffle all creature cards of that type from your graveyard into your library"; + } + + public ElvishSoultillerEffect(final ElvishSoultillerEffect effect) { + super(effect); + } + + @Override + public ElvishSoultillerEffect copy() { + return new ElvishSoultillerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject mageObject = game.getObject(source.getSourceId()); + if (controller != null && mageObject != null) { + Choice typeChoice = new ChoiceImpl(true); + typeChoice.setMessage("Choose creature type"); + typeChoice.setChoices(CardRepository.instance.getCreatureTypes()); + while (!controller.choose(outcome, typeChoice, game)) { + if (!controller.canRespond()) { + return false; + } + } + if (!game.isSimulation()) { + game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + typeChoice.getChoice()); + } + Cards cardsToLibrary = new CardsImpl(); + FilterCreatureCard filter = new FilterCreatureCard(); + filter.add(new SubtypePredicate(typeChoice.getChoice())); + cardsToLibrary.addAll(controller.getGraveyard().getCards(filter, source.getSourceId(), source.getControllerId(), game)); + controller.putCardsOnTopOfLibrary(cardsToLibrary, game, source, false); + controller.shuffleLibrary(game); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/legions/WirewoodChanneler.java b/Mage.Sets/src/mage/sets/legions/WirewoodChanneler.java index f878e0563fb..40329bf44df 100644 --- a/Mage.Sets/src/mage/sets/legions/WirewoodChanneler.java +++ b/Mage.Sets/src/mage/sets/legions/WirewoodChanneler.java @@ -61,7 +61,7 @@ public class WirewoodChanneler extends CardImpl { this.toughness = new MageInt(2); // {T}: Add X mana of any one color to your mana pool, where X is the number of Elves on the battlefield. - DynamicManaAbility ability = new DynamicManaAbility(new Mana(0,0,0,0,0,0,1), new PermanentsOnBattlefieldCount(filter), new TapSourceCost(), + DynamicManaAbility ability = new DynamicManaAbility(new Mana(0,0,0,0,0,0,1, 0), new PermanentsOnBattlefieldCount(filter), new TapSourceCost(), "Add X mana of any one color to your mana pool, where X is the number of Elves on the battlefield", true); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/limitedalpha/BasaltMonolith.java b/Mage.Sets/src/mage/sets/limitedalpha/BasaltMonolith.java index 2d0f72a8e50..8bd25a64bb1 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/BasaltMonolith.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/BasaltMonolith.java @@ -54,7 +54,7 @@ public class BasaltMonolith extends CardImpl { // Basalt Monolith doesn't untap during your untap step. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DontUntapInControllersUntapStepSourceEffect())); // {tap}: Add {C}{C}{C} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0,0,0,0,0,3,0),new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 0, 0, 0, 0, 3), new TapSourceCost())); // {3}: Untap Basalt Monolith. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new UntapSourceEffect(), new GenericManaCost(3))); } diff --git a/Mage.Sets/src/mage/sets/limitedalpha/Berserk.java b/Mage.Sets/src/mage/sets/limitedalpha/Berserk.java index d1da5c2f49c..4e65465e508 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/Berserk.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/Berserk.java @@ -65,11 +65,10 @@ public class Berserk extends CardImpl { super(ownerId, 94, "Berserk", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{G}"); this.expansionSetCode = "LEA"; - // Cast Berserk only before the combat damage step. (Zone = all because it can be at least graveyard or hand) this.addAbility(new SimpleStaticAbility(Zone.ALL, new BerserkReplacementEffect()), new CombatDamageStepStartedWatcher()); - // Target creature gains trample and gets +X/+0 until end of turn, where X is its power. + // Target creature gains trample and gets +X/+0 until end of turn, where X is its power. // At the beginning of the next end step, destroy that creature if it attacked this turn. Effect effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); effect.setText("Target creature gains trample"); @@ -94,6 +93,7 @@ public class Berserk extends CardImpl { } class BerserkReplacementEffect extends ContinuousRuleModifyingEffectImpl { + BerserkReplacementEffect() { super(Duration.EndOfGame, Outcome.Detriment); staticText = "Cast {this} only before the combat damage step"; @@ -171,10 +171,7 @@ class BerserkDestroyEffect extends OneShotEffect { Effect effect = new BerserkDelayedDestroyEffect(); effect.setTargetPointer(new FixedTarget(this.getTargetPointer().getFirst(game, source))); AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } return false; @@ -205,7 +202,7 @@ class BerserkDelayedDestroyEffect extends OneShotEffect { if (permanent != null) { Watcher watcher = game.getState().getWatchers().get("AttackedThisTurn"); if (watcher != null && watcher instanceof AttackedThisTurnWatcher) { - if (((AttackedThisTurnWatcher)watcher).getAttackedThisTurnCreatures().contains(permanent.getId())) { + if (((AttackedThisTurnWatcher) watcher).getAttackedThisTurnCreatures().contains(permanent.getId())) { return permanent.destroy(source.getSourceId(), game, false); } } diff --git a/Mage.Sets/src/mage/sets/limitedalpha/DemonicHordes.java b/Mage.Sets/src/mage/sets/limitedalpha/DemonicHordes.java index b0b6516f12c..7e00ef02cea 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/DemonicHordes.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/DemonicHordes.java @@ -111,7 +111,7 @@ class DemonicHordesEffect extends OneShotEffect { } if (controller.chooseUse(Outcome.Benefit, sb.toString(), source, game)) { cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/limitedalpha/LibraryOfLeng.java b/Mage.Sets/src/mage/sets/limitedalpha/LibraryOfLeng.java new file mode 100644 index 00000000000..c929823f598 --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedalpha/LibraryOfLeng.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.limitedalpha; + +import java.util.UUID; + +/** + * + * @author LevelX2 + */ +public class LibraryOfLeng extends mage.sets.limitedbeta.LibraryOfLeng { + + public LibraryOfLeng(UUID ownerId) { + super(ownerId); + this.cardNumber = 257; + this.expansionSetCode = "LEA"; + } + + public LibraryOfLeng(final LibraryOfLeng card) { + super(card); + } + + @Override + public LibraryOfLeng copy() { + return new LibraryOfLeng(this); + } +} diff --git a/Mage.Sets/src/mage/sets/limitedbeta/LibraryOfLeng.java b/Mage.Sets/src/mage/sets/limitedbeta/LibraryOfLeng.java new file mode 100644 index 00000000000..fc1b1df94a3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedbeta/LibraryOfLeng.java @@ -0,0 +1,149 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.limitedbeta; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +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.players.Player; + +/** + * + * @author LevelX2 + */ +public class LibraryOfLeng extends CardImpl { + + public LibraryOfLeng(UUID ownerId) { + super(ownerId, 259, "Library of Leng", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT}, "{1}"); + this.expansionSetCode = "LEB"; + + // You have no maximum hand size. + Effect effect = new MaximumHandSizeControllerEffect(Integer.MAX_VALUE, Duration.WhileOnBattlefield, MaximumHandSizeControllerEffect.HandSizeModification.SET); + addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + + // If an effect causes you to discard a card, discard it, but you may put it on top of your library instead of into your graveyard. + addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new LibraryOfLengEffect())); + + } + + public LibraryOfLeng(final LibraryOfLeng card) { + super(card); + } + + @Override + public LibraryOfLeng copy() { + return new LibraryOfLeng(this); + } +} + +class LibraryOfLengEffect extends ReplacementEffectImpl { + + private UUID cardId; + private int zoneChangeCounter; + + public LibraryOfLengEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "If an effect causes you to discard a card, discard it, but you may put it on top of your library instead of into your graveyard"; + } + + public LibraryOfLengEffect(final LibraryOfLengEffect effect) { + super(effect); + this.cardId = effect.cardId; + this.zoneChangeCounter = effect.zoneChangeCounter; + } + + @Override + public LibraryOfLengEffect copy() { + return new LibraryOfLengEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType().equals(EventType.DISCARD_CARD) + || event.getType().equals(EventType.ZONE_CHANGE); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getType().equals(EventType.DISCARD_CARD)) { + return event.getPlayerId().equals(source.getControllerId()); + } + if (event.getType().equals(EventType.ZONE_CHANGE)) { + if (event.getTargetId().equals(cardId) && game.getState().getZoneChangeCounter(event.getTargetId()) == zoneChangeCounter) { + if (((ZoneChangeEvent) event).getFromZone().equals(Zone.HAND) && ((ZoneChangeEvent) event).getToZone().equals(Zone.GRAVEYARD)) { + return true; + } + } + } + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + if (event.getType().equals(EventType.DISCARD_CARD)) { + // only save card info + Card card = game.getCard(event.getTargetId()); + if (card != null) { + cardId = card.getId(); + zoneChangeCounter = game.getState().getZoneChangeCounter(cardId); + } + return false; + } + if (event.getType().equals(EventType.ZONE_CHANGE)) { + Player controller = game.getPlayer(source.getControllerId()); + Card card = game.getCard(event.getTargetId()); + if (controller != null && card != null) { + cardId = null; + zoneChangeCounter = 0; + if (controller.chooseUse(outcome, "Put " + card.getIdName() + " on top of your library instead?", source, game)) { + Cards cardsToLibrary = new CardsImpl(card); + controller.putCardsOnTopOfLibrary(cardsToLibrary, game, source, false); + return true; + } + } + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/sets/lorwyn/BrokenAmbitions.java b/Mage.Sets/src/mage/sets/lorwyn/BrokenAmbitions.java index b4168bb6136..cfa6b0f536f 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/BrokenAmbitions.java +++ b/Mage.Sets/src/mage/sets/lorwyn/BrokenAmbitions.java @@ -120,7 +120,7 @@ class BrokenAmbitionsEffect extends OneShotEffect { message = costToPay.getText() + " to prevent counter effect?"; } costToPay.clearPaid(); - if (!(controller.chooseUse(Outcome.Benefit, message, source, game) && costToPay.pay(source, game, spell.getSourceId(), spell.getControllerId(), false))) { + if (!(controller.chooseUse(Outcome.Benefit, message, source, game) && costToPay.pay(source, game, spell.getSourceId(), spell.getControllerId(), false, null))) { game.getStack().counter(spell.getId(), source.getSourceId(), game); } if (ClashEffect.getInstance().apply(game, source)) { diff --git a/Mage.Sets/src/mage/sets/lorwyn/CeaselessSearblades.java b/Mage.Sets/src/mage/sets/lorwyn/CeaselessSearblades.java new file mode 100644 index 00000000000..55439d5359a --- /dev/null +++ b/Mage.Sets/src/mage/sets/lorwyn/CeaselessSearblades.java @@ -0,0 +1,117 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.lorwyn; + +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.MageInt; +import mage.cards.CardImpl; + +import java.util.UUID; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.Card; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; + +/** + * + * @author Will + */ +public class CeaselessSearblades extends CardImpl { + + public CeaselessSearblades(UUID ownerId) { + super(ownerId, 158, "Ceaseless Searblades", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{R}"); + this.expansionSetCode = "LRW"; + this.subtype.add("Elemental"); + this.subtype.add("Warrior"); + + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Whenever you activate an ability of an Elemental, Ceaseless Searblades gets +1/+0 until end of turn. + this.addAbility(new CeaselessSearbladesTriggeredAbility()); + + } + + public CeaselessSearblades(final CeaselessSearblades card) { + super(card); + } + + @Override + public CeaselessSearblades copy() { + return new CeaselessSearblades(this); + } +} + +class CeaselessSearbladesTriggeredAbility extends TriggeredAbilityImpl { + + private static final FilterCard filter = new FilterCard("an Elemental"); + + static { + filter.add(new SubtypePredicate("Elemental")); + } + + CeaselessSearbladesTriggeredAbility() { + super(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn), false); + } + + CeaselessSearbladesTriggeredAbility(final CeaselessSearbladesTriggeredAbility ability) { + super(ability); + } + + @Override + public CeaselessSearbladesTriggeredAbility copy() { + return new CeaselessSearbladesTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Card source = game.getPermanentOrLKIBattlefield(event.getSourceId()); + if (event.getPlayerId().equals(getControllerId()) + && source != null + && filter.match(source, game)) { + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever you activate an ability of an Elemental, " + super.getRule(); + } +} diff --git a/Mage.Sets/src/mage/sets/lorwyn/RingsOfBrighthearth.java b/Mage.Sets/src/mage/sets/lorwyn/RingsOfBrighthearth.java index 8793c91e928..720ad9ed003 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/RingsOfBrighthearth.java +++ b/Mage.Sets/src/mage/sets/lorwyn/RingsOfBrighthearth.java @@ -131,7 +131,7 @@ class RingsOfBrighthearthEffect extends OneShotEffect { ManaCostsImpl cost = new ManaCostsImpl("{2}"); if (player != null) { if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "? If you do, copy that ability. You may choose new targets for the copy.", source, game)) { - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { Ability ability = (Ability) getValue("stackAbility"); Player controller = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); diff --git a/Mage.Sets/src/mage/sets/lorwyn/SilvergillAdept.java b/Mage.Sets/src/mage/sets/lorwyn/SilvergillAdept.java index 9ec52f20fd7..4740bbd5e27 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/SilvergillAdept.java +++ b/Mage.Sets/src/mage/sets/lorwyn/SilvergillAdept.java @@ -31,6 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -96,7 +97,7 @@ class SilvergillAdeptCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player player = game.getPlayer(controllerId); if (player == null) { diff --git a/Mage.Sets/src/mage/sets/lorwyn/SoulbrightFlamekin.java b/Mage.Sets/src/mage/sets/lorwyn/SoulbrightFlamekin.java index 7fc49236753..10df70970ab 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/SoulbrightFlamekin.java +++ b/Mage.Sets/src/mage/sets/lorwyn/SoulbrightFlamekin.java @@ -122,7 +122,7 @@ class SoulbrightFlamekinEffect extends OneShotEffect { } info.activations++; if (info.activations == 3) { - controller.getManaPool().addMana(new Mana(8,0,0,0,0,0,0), game, source); + controller.getManaPool().addMana(new Mana(8,0,0,0,0,0,0, 0), game, source); } return true; } diff --git a/Mage.Sets/src/mage/sets/magic2010/DragonWhelp.java b/Mage.Sets/src/mage/sets/magic2010/DragonWhelp.java index 9b6ce7495f7..1ce3dcb76c0 100644 --- a/Mage.Sets/src/mage/sets/magic2010/DragonWhelp.java +++ b/Mage.Sets/src/mage/sets/magic2010/DragonWhelp.java @@ -28,11 +28,6 @@ package mage.sets.magic2010; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; @@ -43,6 +38,11 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; @@ -100,10 +100,7 @@ class DragonWhelpEffect extends OneShotEffect { if (amount == null) { amount = 0; DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new DragonWhelpDelayedEffect()); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } amount++; game.getState().setValue(source.getSourceId().toString() + "DragonWhelp", amount); diff --git a/Mage.Sets/src/mage/sets/magic2010/Polymorph.java b/Mage.Sets/src/mage/sets/magic2010/Polymorph.java index e3347137348..59ff3e19fb4 100644 --- a/Mage.Sets/src/mage/sets/magic2010/Polymorph.java +++ b/Mage.Sets/src/mage/sets/magic2010/Polymorph.java @@ -56,7 +56,6 @@ public class Polymorph extends CardImpl { super(ownerId, 67, "Polymorph", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{3}{U}"); this.expansionSetCode = "M10"; - // Destroy target creature. It can't be regenerated. this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); @@ -93,11 +92,7 @@ class PolymorphEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent == null) { - permanent = (Permanent) game.getLastKnownInformation(source.getFirstTarget(), Zone.BATTLEFIELD); - } - + Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); if (permanent != null) { Player player = game.getPlayer(permanent.getControllerId()); if (player != null) { diff --git a/Mage.Sets/src/mage/sets/magic2011/AncientHellkite.java b/Mage.Sets/src/mage/sets/magic2011/AncientHellkite.java index 0d85a1a63c5..4d42818e8e9 100644 --- a/Mage.Sets/src/mage/sets/magic2011/AncientHellkite.java +++ b/Mage.Sets/src/mage/sets/magic2011/AncientHellkite.java @@ -36,6 +36,7 @@ import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.ActivatedAbilityImpl; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.mana.ColoredManaCost; import mage.abilities.effects.common.DamageTargetEffect; @@ -137,7 +138,7 @@ class AncientHellkiteCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { this.paid = true; return paid; } diff --git a/Mage.Sets/src/mage/sets/magic2012/AdaptiveAutomaton.java b/Mage.Sets/src/mage/sets/magic2012/AdaptiveAutomaton.java index d6af2a5a2ab..9d646d73863 100644 --- a/Mage.Sets/src/mage/sets/magic2012/AdaptiveAutomaton.java +++ b/Mage.Sets/src/mage/sets/magic2012/AdaptiveAutomaton.java @@ -50,7 +50,6 @@ import mage.filter.predicate.permanent.AnotherPredicate; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; /** * @author nantuko @@ -87,8 +86,8 @@ public class AdaptiveAutomaton extends CardImpl { } } - class AdaptiveAutomatonAddSubtypeEffect extends ContinuousEffectImpl { + public AdaptiveAutomatonAddSubtypeEffect() { super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); staticText = "{this} is the chosen type in addition to its other types"; diff --git a/Mage.Sets/src/mage/sets/magic2013/AugurOfBolas.java b/Mage.Sets/src/mage/sets/magic2013/AugurOfBolas.java index 7f1084a1331..90d6c555f7f 100644 --- a/Mage.Sets/src/mage/sets/magic2013/AugurOfBolas.java +++ b/Mage.Sets/src/mage/sets/magic2013/AugurOfBolas.java @@ -113,7 +113,7 @@ class AugurOfBolasEffect extends OneShotEffect { int number = topCards.count(new FilterInstantOrSorceryCard(), source.getSourceId(), source.getControllerId(), game); if (number > 0) { if (controller.chooseUse(outcome, "Reveal an instant or sorcery card from the looked at cards and put it into your hand?", source, game)) { - Card card = null; + Card card; if (number == 1) { card = topCards.getCards(new FilterInstantOrSorceryCard(), source.getSourceId(), source.getControllerId(), game).iterator().next(); } else { @@ -122,7 +122,7 @@ class AugurOfBolasEffect extends OneShotEffect { card = topCards.get(target.getFirstTarget(), game); } if (card != null) { - controller.moveCards(card, null, Zone.HAND, source, game); + controller.moveCards(card, Zone.HAND, source, game); controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game); topCards.remove(card); } diff --git a/Mage.Sets/src/mage/sets/magic2014/AcademyRaider.java b/Mage.Sets/src/mage/sets/magic2014/AcademyRaider.java index 19bfedc8976..e005feb0f2d 100644 --- a/Mage.Sets/src/mage/sets/magic2014/AcademyRaider.java +++ b/Mage.Sets/src/mage/sets/magic2014/AcademyRaider.java @@ -1,103 +1,72 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ -package mage.sets.magic2014; - -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.IntimidateAbility; -import mage.cards.CardImpl; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.game.Game; -import mage.players.Player; - -/** - * - * @author jeffwadsworth - */ -public class AcademyRaider extends CardImpl { - - public AcademyRaider(UUID ownerId) { - super(ownerId, 124, "Academy Raider", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{R}"); - this.expansionSetCode = "M14"; - this.subtype.add("Human"); - this.subtype.add("Warrior"); - - this.power = new MageInt(1); - this.toughness = new MageInt(1); - - // Intimidate - this.addAbility(IntimidateAbility.getInstance()); - - // Whenever Academy Raider deals combat damage to a player, you may discard a card. If you do, draw a card. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new DiscardAndDrawEffect(), true)); - - } - - public AcademyRaider(final AcademyRaider card) { - super(card); - } - - @Override - public AcademyRaider copy() { - return new AcademyRaider(this); - } -} - -class DiscardAndDrawEffect extends OneShotEffect { - - public DiscardAndDrawEffect() { - super(Outcome.DrawCard); - staticText = "you may discard a card. If you do, draw a card"; - } - - public DiscardAndDrawEffect(final DiscardAndDrawEffect effect) { - super(effect); - } - - @Override - public DiscardAndDrawEffect copy() { - return new DiscardAndDrawEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player you = game.getPlayer(source.getControllerId()); - if (you != null) { - you.discard(1, source, game); - if (you.drawCards(1, game) > 0) { - return true; - } - } - return false; - } -} +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.magic2014; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.IntimidateAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author jeffwadsworth + */ +public class AcademyRaider extends CardImpl { + + public AcademyRaider(UUID ownerId) { + super(ownerId, 124, "Academy Raider", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{R}"); + this.expansionSetCode = "M14"; + this.subtype.add("Human"); + this.subtype.add("Warrior"); + + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Intimidate + this.addAbility(IntimidateAbility.getInstance()); + + // Whenever Academy Raider deals combat damage to a player, you may discard a card. If you do, draw a card. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new DiscardCardCost()), false)); + + } + + public AcademyRaider(final AcademyRaider card) { + super(card); + } + + @Override + public AcademyRaider copy() { + return new AcademyRaider(this); + } +} diff --git a/Mage.Sets/src/mage/sets/magic2014/LiturgyOfBlood.java b/Mage.Sets/src/mage/sets/magic2014/LiturgyOfBlood.java index 1686965860f..af17063e50c 100644 --- a/Mage.Sets/src/mage/sets/magic2014/LiturgyOfBlood.java +++ b/Mage.Sets/src/mage/sets/magic2014/LiturgyOfBlood.java @@ -50,7 +50,7 @@ public class LiturgyOfBlood extends CardImpl { // Destroy target creature. Add {B}{B}{B} to your mana pool. this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(new BasicManaEffect(new Mana(0, 0, 0, 0, 3, 0, 0))); + this.getSpellAbility().addEffect(new BasicManaEffect(new Mana(0, 0, 0, 0, 3, 0, 0, 0))); } public LiturgyOfBlood(final LiturgyOfBlood card) { diff --git a/Mage.Sets/src/mage/sets/magic2015/IndulgentTormentor.java b/Mage.Sets/src/mage/sets/magic2015/IndulgentTormentor.java index 5918480369a..63ae6f133b0 100644 --- a/Mage.Sets/src/mage/sets/magic2015/IndulgentTormentor.java +++ b/Mage.Sets/src/mage/sets/magic2015/IndulgentTormentor.java @@ -102,14 +102,14 @@ class IndulgentTormentorEffect extends OneShotEffect { Cost cost = new SacrificeTargetCost(new TargetControlledCreaturePermanent()); if (cost.canPay(source, source.getSourceId(), opponent.getId(), game) && opponent.chooseUse(outcome, "Sacrifice a creature to prevent the card draw?", source, game)) { - if (cost.pay(source, game, source.getSourceId(), opponent.getId(), false)) { + if (cost.pay(source, game, source.getSourceId(), opponent.getId(), false, null)) { return true; } } cost = new PayLifeCost(3); if (cost.canPay(source, source.getSourceId(), opponent.getId(), game) && opponent.chooseUse(outcome, "Pay 3 life to prevent the card draw?", source, game)) { - if (cost.pay(source, game, source.getSourceId(), opponent.getId(), false)) { + if (cost.pay(source, game, source.getSourceId(), opponent.getId(), false, null)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/magic2015/NecromancersStockpile.java b/Mage.Sets/src/mage/sets/magic2015/NecromancersStockpile.java index 51af6f7dedf..575766661b8 100644 --- a/Mage.Sets/src/mage/sets/magic2015/NecromancersStockpile.java +++ b/Mage.Sets/src/mage/sets/magic2015/NecromancersStockpile.java @@ -30,6 +30,7 @@ package mage.sets.magic2015; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; @@ -92,7 +93,7 @@ class NecromancersStockpileDiscardTargetCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { if (targets.choose(Outcome.Discard, controllerId, sourceId, game)) { Player player = game.getPlayer(controllerId); for (UUID targetId : targets.get(0).getTargets()) { diff --git a/Mage.Sets/src/mage/sets/magic2015/Phytotitan.java b/Mage.Sets/src/mage/sets/magic2015/Phytotitan.java index d339ddbfc2e..bbb6fefcca1 100644 --- a/Mage.Sets/src/mage/sets/magic2015/Phytotitan.java +++ b/Mage.Sets/src/mage/sets/magic2015/Phytotitan.java @@ -27,6 +27,7 @@ */ package mage.sets.magic2015; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; @@ -41,8 +42,6 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.game.Game; -import java.util.UUID; - /** * * @author LevelX2 @@ -76,7 +75,7 @@ class PhytotitanEffect extends OneShotEffect { private static final String effectText = "return it to the battlefield tapped under its owner's control at the beginning of his or her next upkeep"; - PhytotitanEffect ( ) { + PhytotitanEffect() { super(Outcome.Benefit); staticText = effectText; } @@ -91,10 +90,7 @@ class PhytotitanEffect extends OneShotEffect { Effect effect = new ReturnSourceFromGraveyardToBattlefieldEffect(true, true); effect.setText(staticText); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility(effect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } diff --git a/Mage.Sets/src/mage/sets/magic2015/SliverHive.java b/Mage.Sets/src/mage/sets/magic2015/SliverHive.java index 5ec2056da03..1e3e3f90288 100644 --- a/Mage.Sets/src/mage/sets/magic2015/SliverHive.java +++ b/Mage.Sets/src/mage/sets/magic2015/SliverHive.java @@ -29,11 +29,11 @@ package mage.sets.magic2015; import java.util.UUID; import mage.ConditionalMana; -import mage.MageInt; import mage.MageObject; import mage.Mana; import mage.abilities.Ability; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.Cost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.decorator.ConditionalActivatedAbility; @@ -124,7 +124,7 @@ class SliverHiveConditionalMana extends ConditionalMana { class SliverHiveManaCondition extends CreatureCastManaCondition { @Override - public boolean apply(Game game, Ability source, UUID manaProducer) { + public boolean apply(Game game, Ability source, UUID manaProducer, Cost costToPay) { if (super.apply(game, source)) { MageObject object = game.getObject(source.getSourceId()); if (object.hasSubtype("Sliver")) { diff --git a/Mage.Sets/src/mage/sets/magic2015/TheChainVeil.java b/Mage.Sets/src/mage/sets/magic2015/TheChainVeil.java index a000d5dbf9e..b69e8999176 100644 --- a/Mage.Sets/src/mage/sets/magic2015/TheChainVeil.java +++ b/Mage.Sets/src/mage/sets/magic2015/TheChainVeil.java @@ -34,10 +34,11 @@ import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; 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.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; @@ -66,12 +67,13 @@ public class TheChainVeil extends CardImpl { this.supertype.add("Legendary"); // At the beginning of your end step, if you didn't activate a loyalty ability of a planeswalker this turn, you lose 2 life. - this.addAbility(new BeginningOfEndStepTriggeredAbility(new TheChainVeilTriggeredEffect(), TargetController.YOU, false), new ActivatedLoyaltyAbilityWatcher()); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + Zone.BATTLEFIELD, new LoseLifeSourceControllerEffect(2), TargetController.YOU, TheChainVeilCondition.getInstance(), false), new ActivatedLoyaltyAbilityWatcher()); // {4}, {T}: For each planeswalker you control, you may activate one of its loyalty abilities once this turn as though none of its loyalty abilities had been activated this turn. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new TheChainVeilIncreaseLoyaltyUseEffect(), - new ManaCostsImpl("{4}")); + new TheChainVeilIncreaseLoyaltyUseEffect(), + new ManaCostsImpl("{4}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); @@ -87,61 +89,29 @@ public class TheChainVeil extends CardImpl { } } -class TheChainVeilTriggeredEffect extends OneShotEffect { - - public TheChainVeilTriggeredEffect() { - super(Outcome.LoseLife); - this.staticText = "if you didn't activate a loyalty ability of a planeswalker this turn, you lose 2 life"; - } - - public TheChainVeilTriggeredEffect(final TheChainVeilTriggeredEffect effect) { - super(effect); - } - - @Override - public TheChainVeilTriggeredEffect copy() { - return new TheChainVeilTriggeredEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - ActivatedLoyaltyAbilityWatcher watcher = (ActivatedLoyaltyAbilityWatcher) game.getState().getWatchers().get("ActivatedLoyaltyAbilityWatcher"); - if (watcher != null) { - if (!watcher.activatedLayaltyAbility(source.getControllerId())) { - controller.loseLife(2, game); - } - } - } - return false; - } -} - - class ActivatedLoyaltyAbilityWatcher extends Watcher { private final Set playerIds = new HashSet<>(); public ActivatedLoyaltyAbilityWatcher() { - super("ActivatedLoyaltyAbilityWatcher", WatcherScope.GAME); + super("ActivatedLoyaltyAbilityWatcher", WatcherScope.GAME); } public ActivatedLoyaltyAbilityWatcher(final ActivatedLoyaltyAbilityWatcher watcher) { - super(watcher); - playerIds.addAll(watcher.playerIds); + super(watcher); + playerIds.addAll(watcher.playerIds); } @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.ACTIVATED_ABILITY ) { - StackObject stackObject = game.getStack().getStackObject(event.getTargetId()); - if (stackObject != null && - stackObject.getStackAbility() != null && - stackObject.getStackAbility() instanceof LoyaltyAbility) { - playerIds.add(stackObject.getControllerId()); - } - } + if (event.getType() == GameEvent.EventType.ACTIVATED_ABILITY) { + StackObject stackObject = game.getStack().getStackObject(event.getTargetId()); + if (stackObject != null + && stackObject.getStackAbility() != null + && stackObject.getStackAbility() instanceof LoyaltyAbility) { + playerIds.add(stackObject.getControllerId()); + } + } } @Override @@ -151,7 +121,7 @@ class ActivatedLoyaltyAbilityWatcher extends Watcher { @Override public ActivatedLoyaltyAbilityWatcher copy() { - return new ActivatedLoyaltyAbilityWatcher(this); + return new ActivatedLoyaltyAbilityWatcher(this); } public boolean activatedLayaltyAbility(UUID playerId) { @@ -194,3 +164,30 @@ class TheChainVeilIncreaseLoyaltyUseEffect extends ContinuousEffectImpl { return layer == Layer.RulesEffects; } } + +class TheChainVeilCondition implements Condition { + + private static final TheChainVeilCondition fInstance = new TheChainVeilCondition(); + + public static Condition getInstance() { + return fInstance; + } + + @Override + public boolean apply(Game game, Ability source) { + ActivatedLoyaltyAbilityWatcher watcher = (ActivatedLoyaltyAbilityWatcher) game.getState().getWatchers().get("ActivatedLoyaltyAbilityWatcher"); + if (watcher != null) { + if (!watcher.activatedLayaltyAbility(source.getControllerId())) { + return true; + } + } + + return false; + } + + @Override + public String toString() { + return "if you didn't activate a loyalty ability of a planeswalker this turn"; + } + +} diff --git a/Mage.Sets/src/mage/sets/magic2015/WasteNot.java b/Mage.Sets/src/mage/sets/magic2015/WasteNot.java index ed5690362ef..8a65d0e558e 100644 --- a/Mage.Sets/src/mage/sets/magic2015/WasteNot.java +++ b/Mage.Sets/src/mage/sets/magic2015/WasteNot.java @@ -113,7 +113,7 @@ class WasteNotCreatureTriggeredAbility extends TriggeredAbilityImpl { class WasteNotLandTriggeredAbility extends TriggeredAbilityImpl { WasteNotLandTriggeredAbility() { - super(Zone.BATTLEFIELD, new BasicManaEffect(new Mana(0, 0, 0, 0, 2, 0, 0)), false); + super(Zone.BATTLEFIELD, new BasicManaEffect(new Mana(0, 0, 0, 0, 2, 0, 0, 0)), false); } WasteNotLandTriggeredAbility(final WasteNotLandTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/sets/magicorigins/AlhammarretsArchive.java b/Mage.Sets/src/mage/sets/magicorigins/AlhammarretsArchive.java index 4543f0c49c1..063e47a2285 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/AlhammarretsArchive.java +++ b/Mage.Sets/src/mage/sets/magicorigins/AlhammarretsArchive.java @@ -87,11 +87,6 @@ class AlhammarretsArchiveEffect extends ReplacementEffectImpl { return new AlhammarretsArchiveEffect(this); } - @Override - public boolean apply(Game game, Ability source) { - return true; - } - @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { event.setAmount(event.getAmount() * 2); @@ -132,9 +127,9 @@ class AlhammarretsArchiveReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - player.drawCards(2, game, event.getAppliedEffects()); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + controller.drawCards(2, game, event.getAppliedEffects()); } return true; } @@ -146,15 +141,17 @@ class AlhammarretsArchiveReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (game.getActivePlayerId().equals(event.getPlayerId()) && game.getPhase().getStep().getType().equals(PhaseStep.DRAW)) { - CardsDrawnDuringDrawStepWatcher watcher = (CardsDrawnDuringDrawStepWatcher) game.getState().getWatchers().get("CardsDrawnDuringDrawStep"); - if (watcher != null && watcher.getAmountCardsDrawn(event.getPlayerId()) > 0) { + if (event.getPlayerId().equals(source.getControllerId())) { + if (game.getActivePlayerId().equals(event.getPlayerId()) + && game.getPhase().getStep().getType().equals(PhaseStep.DRAW)) { + CardsDrawnDuringDrawStepWatcher watcher = (CardsDrawnDuringDrawStepWatcher) game.getState().getWatchers().get("CardsDrawnDuringDrawStep"); + if (watcher != null && watcher.getAmountCardsDrawn(event.getPlayerId()) > 0) { + return true; + } + } else { return true; } - } else { - return true; } - return false; } } diff --git a/Mage.Sets/src/mage/sets/magicorigins/FlameshadowConjuring.java b/Mage.Sets/src/mage/sets/magicorigins/FlameshadowConjuring.java index d8fa46e9902..ac71c34eeb6 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/FlameshadowConjuring.java +++ b/Mage.Sets/src/mage/sets/magicorigins/FlameshadowConjuring.java @@ -109,10 +109,7 @@ class FlameshadowConjuringEffect extends OneShotEffect { ExileTargetEffect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } return true; } diff --git a/Mage.Sets/src/mage/sets/magicorigins/NissaSageAnimist.java b/Mage.Sets/src/mage/sets/magicorigins/NissaSageAnimist.java index c1e5a65d797..b98aa077804 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/NissaSageAnimist.java +++ b/Mage.Sets/src/mage/sets/magicorigins/NissaSageAnimist.java @@ -122,7 +122,7 @@ class NissaSageAnimistPlusOneEffect extends OneShotEffect { if (card.getCardType().contains(CardType.LAND)) { targetZone = Zone.BATTLEFIELD; } - return controller.moveCards(card, null, targetZone, source, game); + return controller.moveCards(card, targetZone, source, game); } return true; } diff --git a/Mage.Sets/src/mage/sets/magicorigins/TouchOfMoonglove.java b/Mage.Sets/src/mage/sets/magicorigins/TouchOfMoonglove.java index 9edcf4a82fd..116d5126128 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/TouchOfMoonglove.java +++ b/Mage.Sets/src/mage/sets/magicorigins/TouchOfMoonglove.java @@ -104,10 +104,7 @@ class TouchOfMoongloveAddTriggerEffect extends OneShotEffect { Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); if (permanent != null) { DelayedTriggeredAbility delayedAbility = new TouchOfMoongloveDelayedTriggeredAbility(new MageObjectReference(permanent, game)); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } return true; } diff --git a/Mage.Sets/src/mage/sets/mastersedition/UrzasBauble.java b/Mage.Sets/src/mage/sets/mastersedition/UrzasBauble.java new file mode 100644 index 00000000000..38fdf48b949 --- /dev/null +++ b/Mage.Sets/src/mage/sets/mastersedition/UrzasBauble.java @@ -0,0 +1,115 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mastersedition; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; + +/** + * + * @author Plopman + */ +public class UrzasBauble extends CardImpl { + + public UrzasBauble(UUID ownerId) { + super(ownerId, 170, "Urza's Bauble", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT}, "{0}"); + this.expansionSetCode = "MED"; + + // {tap}, Sacrifice Urza's Bauble: Look at a card at random in target player's hand. You draw a card at the beginning of the next turn's upkeep. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LookAtRandomCardEffect(), new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetPlayer()); + ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false)); + this.addAbility(ability); + } + + + public UrzasBauble(final UrzasBauble card) { + super(card); + } + + @Override + public UrzasBauble copy() { + return new UrzasBauble(this); + } +} + +class LookAtRandomCardEffect extends OneShotEffect { + + public LookAtRandomCardEffect() { + super(Outcome.Benefit); + this.staticText = "Look at a card at random in target player's hand"; + } + + public LookAtRandomCardEffect(final LookAtRandomCardEffect effect) { + super(effect); + } + + @Override + public LookAtRandomCardEffect copy() { + return new LookAtRandomCardEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player you = game.getPlayer(source.getControllerId()); + Player targetPlayer = game.getPlayer(source.getFirstTarget()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (you != null && targetPlayer != null) { + if(!targetPlayer.getHand().isEmpty()) + { + Cards randomCard = new CardsImpl(); + Card card = targetPlayer.getHand().getRandom(game); + randomCard.add(card); + you.lookAtCards(sourceObject != null ? sourceObject.getName() : null, randomCard, game); + } + return true; + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/sets/masterseditionii/ElementalAugury.java b/Mage.Sets/src/mage/sets/masterseditionii/ElementalAugury.java new file mode 100644 index 00000000000..7c1c523b1fe --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditionii/ElementalAugury.java @@ -0,0 +1,109 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.masterseditionii; + +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.cards.Card; +import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; + +/** + * + * @author Plopman + */ +public class ElementalAugury extends CardImpl { + + public ElementalAugury(UUID ownerId) { + super(ownerId, 193, "Elemental Augury", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{U}{B}{R}"); + this.expansionSetCode = "ME2"; + + // {3}: Look at the top three cards of target player's library, then put them back in any order. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ElementalAuguryEffect(), new ManaCostsImpl("3")); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + public ElementalAugury(final ElementalAugury card) { + super(card); + } + + @Override + public ElementalAugury copy() { + return new ElementalAugury(this); + } +} + +class ElementalAuguryEffect extends OneShotEffect { + + public ElementalAuguryEffect() { + super(Outcome.DrawCard); + this.staticText = "look at the top three cards of target player's library, then put them back in any order"; + } + + public ElementalAuguryEffect(final ElementalAuguryEffect effect) { + super(effect); + } + + @Override + public ElementalAuguryEffect copy() { + return new ElementalAuguryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player targetPlayer = game.getPlayer(source.getFirstTarget()); + if (targetPlayer == null + || controller == null) { + return false; + } + Cards cards = new CardsImpl(); + int count = Math.min(targetPlayer.getLibrary().size(), 3); + for (int i = 0; i < count; i++) { + Card card = targetPlayer.getLibrary().removeFromTop(game); + if (card != null) { + cards.add(card); + } + } + controller.lookAtCards("Elemental Augury", cards, game); + controller.putCardsOnTopOfLibrary(cards, game, source, true); + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditionii/ForgottenLore.java b/Mage.Sets/src/mage/sets/masterseditionii/ForgottenLore.java index 3fc2f88f87e..4dad8951946 100644 --- a/Mage.Sets/src/mage/sets/masterseditionii/ForgottenLore.java +++ b/Mage.Sets/src/mage/sets/masterseditionii/ForgottenLore.java @@ -117,7 +117,7 @@ class ForgottenLoreEffect extends OneShotEffect { if(!done) { if(cost.canPay(source, source.getSourceId(), you.getId(), game) && you.chooseUse(Outcome.Benefit, "Pay {G} to choose a different card ?", source, game)) { cost.clearPaid(); - if(!cost.pay(source, game, source.getSourceId(), you.getId(), false)) { + if(!cost.pay(source, game, source.getSourceId(), you.getId(), false, null)) { done = true; } } diff --git a/Mage.Sets/src/mage/sets/masterseditionii/Panic.java b/Mage.Sets/src/mage/sets/masterseditionii/Panic.java index 16b034a6316..ca97a04ba11 100644 --- a/Mage.Sets/src/mage/sets/masterseditionii/Panic.java +++ b/Mage.Sets/src/mage/sets/masterseditionii/Panic.java @@ -28,23 +28,17 @@ package mage.sets.masterseditionii; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; -import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.condition.common.BeforeBlockersAreDeclaredCondition; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.combat.CantBlockTargetEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.PhaseStep; import mage.constants.Rarity; import mage.constants.TurnPhase; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; import mage.target.common.TargetCreaturePermanent; /** @@ -58,14 +52,12 @@ public class Panic extends CardImpl { this.expansionSetCode = "ME2"; // Cast Panic only during combat before blockers are declared. - Ability ability = new SimpleStaticAbility(Zone.ALL, new PanicRuleModifyingEffect()); - ability.setRuleAtTheTop(true); - this.addAbility(ability); - + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(TurnPhase.COMBAT, BeforeBlockersAreDeclaredCondition.getInstance())); + // Target creature can't block this turn. this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addEffect(new CantBlockTargetEffect(Duration.EndOfTurn)); - + // Draw a card at the beginning of the next turn's upkeep. this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false)); } @@ -79,42 +71,3 @@ public class Panic extends CardImpl { return new Panic(this); } } - -class PanicRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl { - - PanicRuleModifyingEffect() { - super(Duration.EndOfGame, Outcome.Detriment); - staticText = "Cast {this} only during combat before blockers are declared"; - } - - PanicRuleModifyingEffect(final PanicRuleModifyingEffect effect) { - super(effect); - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType().equals(GameEvent.EventType.CAST_SPELL); - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getSourceId().equals(source.getSourceId())) { - return !TurnPhase.COMBAT.equals(game.getTurn().getPhaseType()) || - game.getStep().getType().equals(PhaseStep.DECLARE_BLOCKERS) || - game.getStep().getType().equals(PhaseStep.FIRST_COMBAT_DAMAGE) || - game.getStep().getType().equals(PhaseStep.COMBAT_DAMAGE) || - game.getStep().getType().equals(PhaseStep.END_COMBAT); - } - return false; - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public PanicRuleModifyingEffect copy() { - return new PanicRuleModifyingEffect(this); - } -} diff --git a/Mage.Sets/src/mage/sets/masterseditionii/Portent.java b/Mage.Sets/src/mage/sets/masterseditionii/Portent.java new file mode 100644 index 00000000000..3ec0b39cd8e --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditionii/Portent.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.masterseditionii; + +import java.util.UUID; + +/** + * + * @author Plopman + */ +public class Portent extends mage.sets.fifthedition.Portent { + + public Portent(UUID ownerId) { + super(ownerId); + this.cardNumber = 60; + this.expansionSetCode = "ME2"; + } + + public Portent(final Portent card) { + super(card); + } + + @Override + public Portent copy() { + return new Portent(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditionii/ThunderWall.java b/Mage.Sets/src/mage/sets/masterseditionii/ThunderWall.java new file mode 100644 index 00000000000..9ad9165a3fd --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditionii/ThunderWall.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.masterseditionii; + +import java.util.UUID; + +/** + * + * @author icetc + */ +public class ThunderWall extends mage.sets.iceage.ThunderWall { + + public ThunderWall(UUID ownerId) { + super(ownerId); + this.cardNumber = 71; + this.expansionSetCode = "ME2"; + } + + public ThunderWall(final ThunderWall card) { + super(card); + } + + @Override + public ThunderWall copy() { + return new ThunderWall(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditioniii/ManaVortex.java b/Mage.Sets/src/mage/sets/masterseditioniii/ManaVortex.java index 6cf19b12be0..a42dc2577ff 100644 --- a/Mage.Sets/src/mage/sets/masterseditioniii/ManaVortex.java +++ b/Mage.Sets/src/mage/sets/masterseditioniii/ManaVortex.java @@ -113,7 +113,7 @@ class CounterSourceEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if(controller.chooseUse(Outcome.Detriment, "Sacrifice a land to not counter " + spell.getName() + "?", source, game)){ SacrificeTargetCost cost = new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledLandPermanent())); - if(cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)){ + if(cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)){ game.informPlayers(controller.getLogName() + " sacrifices a land to not counter " + spell.getName() + "."); return true; } diff --git a/Mage.Sets/src/mage/sets/masterseditioniii/WanderingMage.java b/Mage.Sets/src/mage/sets/masterseditioniii/WanderingMage.java index a09c453c49b..cda82b37cb3 100644 --- a/Mage.Sets/src/mage/sets/masterseditioniii/WanderingMage.java +++ b/Mage.Sets/src/mage/sets/masterseditioniii/WanderingMage.java @@ -31,6 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.PayLifeCost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -124,7 +125,7 @@ class WanderingMageCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(ability.getTargets().get(1).getFirstTarget()); if (permanent != null) { permanent.addCounters(CounterType.M1M1.createInstance(), game); diff --git a/Mage.Sets/src/mage/sets/masterseditioniv/GorillaWarCry.java b/Mage.Sets/src/mage/sets/masterseditioniv/GorillaWarCry.java index 8fdd8972bf2..b8812157b30 100644 --- a/Mage.Sets/src/mage/sets/masterseditioniv/GorillaWarCry.java +++ b/Mage.Sets/src/mage/sets/masterseditioniv/GorillaWarCry.java @@ -28,10 +28,9 @@ package mage.sets.masterseditioniv; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; -import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.condition.common.BeforeBlockersAreDeclaredCondition; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -40,14 +39,9 @@ import mage.abilities.keyword.MenaceAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.PhaseStep; import mage.constants.Rarity; import mage.constants.TurnPhase; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; -import mage.game.Game; -import mage.game.events.GameEvent; /** * @@ -60,15 +54,13 @@ public class GorillaWarCry extends CardImpl { this.expansionSetCode = "ME4"; // Cast Gorilla War Cry only during combat before blockers are declared. - Ability ability = new SimpleStaticAbility(Zone.ALL, new GorillaWarCryRuleModifyingEffect()); - ability.setRuleAtTheTop(true); - this.addAbility(ability); - + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(TurnPhase.COMBAT, BeforeBlockersAreDeclaredCondition.getInstance())); + // All creatures gain menace until end of turn. (They can't be blocked except by two or more creatures.) Effect effect = new GainAbilityAllEffect(new MenaceAbility(), Duration.EndOfTurn, new FilterCreaturePermanent()); effect.setText("All creatures gain menace until end of turn. (They can't be blocked except by two or more creatures.)"); this.getSpellAbility().addEffect(effect); - + // Draw a card at the beginning of the next turn's upkeep. this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false)); } @@ -82,43 +74,3 @@ public class GorillaWarCry extends CardImpl { return new GorillaWarCry(this); } } - -class GorillaWarCryRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl { - - GorillaWarCryRuleModifyingEffect() { - super(Duration.EndOfGame, Outcome.Detriment); - staticText = "Cast {this} only during combat before blockers are declared"; - } - - GorillaWarCryRuleModifyingEffect(final GorillaWarCryRuleModifyingEffect effect) { - super(effect); - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType().equals(GameEvent.EventType.CAST_SPELL); - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getSourceId().equals(source.getSourceId())) { - return !TurnPhase.COMBAT.equals(game.getTurn().getPhaseType()) || - game.getStep().getType().equals(PhaseStep.DECLARE_BLOCKERS) || - game.getStep().getType().equals(PhaseStep.FIRST_COMBAT_DAMAGE) || - game.getStep().getType().equals(PhaseStep.COMBAT_DAMAGE) || - game.getStep().getType().equals(PhaseStep.END_COMBAT); - } - return false; - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public GorillaWarCryRuleModifyingEffect copy() { - return new GorillaWarCryRuleModifyingEffect(this); - } -} - diff --git a/Mage.Sets/src/mage/sets/masterseditioniv/HasranOgress.java b/Mage.Sets/src/mage/sets/masterseditioniv/HasranOgress.java index ecaabd74092..b321e1e625a 100644 --- a/Mage.Sets/src/mage/sets/masterseditioniv/HasranOgress.java +++ b/Mage.Sets/src/mage/sets/masterseditioniv/HasranOgress.java @@ -92,7 +92,7 @@ class HasranOgressEffect extends OneShotEffect { Cost cost = new ManaCostsImpl("{2}"); String message = "Would you like to pay {2} to prevent taking 3 damage from Hasran Ogress?"; if (!(controller.chooseUse(Outcome.Benefit, message, source, game) - && cost.pay(source, game, source.getSourceId(), controller.getId(), false))) { + && cost.pay(source, game, source.getSourceId(), controller.getId(), false, null))) { controller.damage(3, source.getSourceId(), game, false, true); } return true; diff --git a/Mage.Sets/src/mage/sets/masterseditioniv/LibraryOfLeng.java b/Mage.Sets/src/mage/sets/masterseditioniv/LibraryOfLeng.java new file mode 100644 index 00000000000..32b45b5106c --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditioniv/LibraryOfLeng.java @@ -0,0 +1,54 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.masterseditioniv; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LevelX2 + */ +public class LibraryOfLeng extends mage.sets.limitedbeta.LibraryOfLeng { + + public LibraryOfLeng(UUID ownerId) { + super(ownerId); + this.cardNumber = 211; + this.expansionSetCode = "ME4"; + this.rarity = Rarity.COMMON; + } + + public LibraryOfLeng(final LibraryOfLeng card) { + super(card); + } + + @Override + public LibraryOfLeng copy() { + return new LibraryOfLeng(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditioniv/SoldeviMachinist.java b/Mage.Sets/src/mage/sets/masterseditioniv/SoldeviMachinist.java index ba2b128d299..afd305d5907 100644 --- a/Mage.Sets/src/mage/sets/masterseditioniv/SoldeviMachinist.java +++ b/Mage.Sets/src/mage/sets/masterseditioniv/SoldeviMachinist.java @@ -34,6 +34,7 @@ import mage.MageObject; import mage.Mana; import mage.abilities.Ability; import mage.abilities.condition.Condition; +import mage.abilities.costs.Cost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.mana.ConditionalColorlessManaAbility; import mage.abilities.mana.builder.ConditionalManaBuilder; @@ -109,7 +110,7 @@ class ArtifactAbilityManaCondition extends ManaCondition implements Condition { } @Override - public boolean apply(Game game, Ability source, UUID originalId) { + public boolean apply(Game game, Ability source, UUID originalId, Cost costsToPay) { return apply(game, source); } } diff --git a/Mage.Sets/src/mage/sets/mercadianmasques/BogWitch.java b/Mage.Sets/src/mage/sets/mercadianmasques/BogWitch.java index 82c83f63f0e..b1a69e0ac94 100644 --- a/Mage.Sets/src/mage/sets/mercadianmasques/BogWitch.java +++ b/Mage.Sets/src/mage/sets/mercadianmasques/BogWitch.java @@ -56,7 +56,7 @@ public class BogWitch extends CardImpl { this.toughness = new MageInt(1); // {B}, {tap}, Discard a card: Add {B}{B}{B} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new BasicManaEffect(new Mana(0, 0, 0, 0, 3, 0, 0)), new ManaCostsImpl("{B}")); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new BasicManaEffect(new Mana(0, 0, 0, 0, 3, 0, 0, 0)), new ManaCostsImpl("{B}")); ability.addCost(new TapSourceCost()); ability.addCost(new DiscardCardCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/mercadianmasques/HornOfPlenty.java b/Mage.Sets/src/mage/sets/mercadianmasques/HornOfPlenty.java index 7348c1d5b82..a9c6619197c 100644 --- a/Mage.Sets/src/mage/sets/mercadianmasques/HornOfPlenty.java +++ b/Mage.Sets/src/mage/sets/mercadianmasques/HornOfPlenty.java @@ -94,7 +94,7 @@ class HornOfPlentyEffect extends OneShotEffect { if (caster != null) { if (caster.chooseUse(Outcome.DrawCard, "Pay {1} to draw a card at the beginning of the next end step?", source, game)) { Cost cost = new ManaCostsImpl("{1}"); - if (cost.pay(source, game, source.getSourceId(), caster.getId(), false)) { + if (cost.pay(source, game, source.getSourceId(), caster.getId(), false, null)) { Effect effect = new DrawCardTargetEffect(1); effect.setTargetPointer(new FixedTarget(caster.getId())); return new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect, TargetController.ANY)).apply(game, source); diff --git a/Mage.Sets/src/mage/sets/mercadianmasques/KyrenToy.java b/Mage.Sets/src/mage/sets/mercadianmasques/KyrenToy.java index 52e9b04d023..e47e646b6a8 100644 --- a/Mage.Sets/src/mage/sets/mercadianmasques/KyrenToy.java +++ b/Mage.Sets/src/mage/sets/mercadianmasques/KyrenToy.java @@ -60,7 +60,7 @@ public class KyrenToy extends CardImpl { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.CHARGE.createInstance(1)), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); this.addAbility(ability); - + // {T}, Remove X charge counters from Kyren Toy: Add X mana of {C} to your mana pool, and then add {C} to your mana pool. ability = new KyrenToyManaAbility(); ability.addCost(new RemoveVariableCountersSourceCost(CounterType.CHARGE.createInstance(1))); @@ -75,8 +75,9 @@ public class KyrenToy extends CardImpl { public KyrenToy copy() { return new KyrenToy(this); } - + private class KyrenToyManaAbility extends BasicManaAbility { + KyrenToyManaAbility() { super(new KyrenToyManaEffect()); } @@ -89,7 +90,7 @@ public class KyrenToy extends CardImpl { public KyrenToyManaAbility copy() { return new KyrenToyManaAbility(this); } -} + } private class KyrenToyManaEffect extends ManaEffect { @@ -110,10 +111,10 @@ public class KyrenToy extends CardImpl { int numberOfMana = 0; for (Cost cost : source.getCosts()) { if (cost instanceof RemoveVariableCountersSourceCost) { - numberOfMana = ((RemoveVariableCountersSourceCost)cost).getAmount(); + numberOfMana = ((RemoveVariableCountersSourceCost) cost).getAmount(); } } - Mana mana = new Mana(0, 0, 0, 0, 0, numberOfMana + 1, 0); + Mana mana = new Mana(0, 0, 0, 0, 0, 0, 0, numberOfMana + 1); checkToFirePossibleEvents(mana, game, source); player.getManaPool().addMana(mana, game, source); return true; @@ -130,5 +131,5 @@ public class KyrenToy extends CardImpl { public KyrenToyManaEffect copy() { return new KyrenToyManaEffect(this); } - } + } } diff --git a/Mage.Sets/src/mage/sets/mercadianmasques/LandGrant.java b/Mage.Sets/src/mage/sets/mercadianmasques/LandGrant.java index 5f369b7827b..58983142992 100644 --- a/Mage.Sets/src/mage/sets/mercadianmasques/LandGrant.java +++ b/Mage.Sets/src/mage/sets/mercadianmasques/LandGrant.java @@ -31,6 +31,7 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.costs.AlternativeCostSourceAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.cards.CardImpl; @@ -105,7 +106,7 @@ class LandGrantReavealCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player player = game.getPlayer(controllerId); if (player != null) { player.revealCards("Land Grant", player.getHand(), game); diff --git a/Mage.Sets/src/mage/sets/mercadianmasques/MidnightRitual.java b/Mage.Sets/src/mage/sets/mercadianmasques/MidnightRitual.java new file mode 100644 index 00000000000..799caabd38c --- /dev/null +++ b/Mage.Sets/src/mage/sets/mercadianmasques/MidnightRitual.java @@ -0,0 +1,112 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mercadianmasques; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreatureCard; +import mage.game.Game; +import mage.game.permanent.token.ZombieToken; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author Skyler Sell + */ +public class MidnightRitual extends CardImpl { + + private final FilterCreatureCard filter = new FilterCreatureCard("creature card from your graveyard"); + + public MidnightRitual(UUID ownerId) { + super(ownerId, 146, "Midnight Ritual", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{X}{2}{B}"); + this.expansionSetCode = "MMQ"; + + // Exile X target creature cards from your graveyard. + // For each creature card exiled this way, put a 2/2 black Zombie creature token onto the battlefield. + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); + this.getSpellAbility().addEffect(new MidnightRitualEffect()); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + if (ability instanceof SpellAbility) { + ability.getTargets().clear(); + ability.addTarget(new TargetCardInYourGraveyard(ability.getManaCostsToPay().getX(), filter)); + } + } + + public MidnightRitual(final MidnightRitual card) { + super(card); + } + + @Override + public MidnightRitual copy() { + return new MidnightRitual(this); + } +} + +class MidnightRitualEffect extends OneShotEffect { + + public MidnightRitualEffect() { + super(Outcome.Neutral); + this.staticText = "Exile X target creature cards from your graveyard. For each creature card exiled this way, put a 2/2 black Zombie creature token onto the battlefield"; + } + + public MidnightRitualEffect(final MidnightRitualEffect effect) { + super(effect); + } + + @Override + public MidnightRitualEffect copy() { + return new MidnightRitualEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Cards cardsToExile = new CardsImpl(getTargetPointer().getTargets(game, source)); + controller.moveCards(cardsToExile, Zone.EXILED, source, game); + if (!cardsToExile.isEmpty()) { + new ZombieToken().putOntoBattlefield(cardsToExile.size(), game, source.getSourceId(), controller.getId()); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/mirage/Afterlife.java b/Mage.Sets/src/mage/sets/mirage/Afterlife.java index 8c636422ca0..83fb1d5924f 100644 --- a/Mage.Sets/src/mage/sets/mirage/Afterlife.java +++ b/Mage.Sets/src/mage/sets/mirage/Afterlife.java @@ -28,15 +28,13 @@ package mage.sets.mirage; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; -import mage.constants.Zone; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.SpiritWhiteToken; @@ -52,7 +50,6 @@ public class Afterlife extends CardImpl { super(ownerId, 205, "Afterlife", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{2}{W}"); this.expansionSetCode = "MIR"; - // Destroy target creature. It can't be regenerated. Its controller puts a // 1/1 white Spirit creature token with flying onto the battlefield. this.getSpellAbility().addTarget(new TargetCreaturePermanent()); @@ -96,4 +93,4 @@ class AfterlifeEffect extends OneShotEffect { return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/mirage/Aleatory.java b/Mage.Sets/src/mage/sets/mirage/Aleatory.java index 02aef32375c..b4ed436e495 100644 --- a/Mage.Sets/src/mage/sets/mirage/Aleatory.java +++ b/Mage.Sets/src/mage/sets/mirage/Aleatory.java @@ -29,9 +29,9 @@ package mage.sets.mirage; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; -import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.condition.common.AfterBlockersAreDeclaredCondition; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -40,12 +40,9 @@ import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; -import mage.constants.PhaseStep; import mage.constants.Rarity; import mage.constants.TurnPhase; -import mage.constants.Zone; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; @@ -61,14 +58,12 @@ public class Aleatory extends CardImpl { this.expansionSetCode = "MIR"; // Cast Aleatory only during combat after blockers are declared. - Ability ability = new SimpleStaticAbility(Zone.ALL, new AleatoryRuleModifyingEffect()); - ability.setRuleAtTheTop(true); - this.addAbility(ability); - + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(TurnPhase.COMBAT, AfterBlockersAreDeclaredCondition.getInstance())); + // Flip a coin. If you win the flip, target creature gets +1/+1 until end of turn. this.getSpellAbility().addEffect(new AleatoryEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - + // Draw a card at the beginning of the next turn's upkeep. this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false)); } @@ -83,43 +78,6 @@ public class Aleatory extends CardImpl { } } -class AleatoryRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl { - - AleatoryRuleModifyingEffect() { - super(Duration.EndOfGame, Outcome.Detriment); - staticText = "Cast {this} only during combat after blockers are declared"; - } - - AleatoryRuleModifyingEffect(final AleatoryRuleModifyingEffect effect) { - super(effect); - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType().equals(GameEvent.EventType.CAST_SPELL); - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getSourceId().equals(source.getSourceId())) { - return !game.getPhase().getType().equals(TurnPhase.COMBAT) || - game.getStep().getType().equals(PhaseStep.BEGIN_COMBAT) || - game.getStep().getType().equals(PhaseStep.DECLARE_ATTACKERS); - } - return false; - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public AleatoryRuleModifyingEffect copy() { - return new AleatoryRuleModifyingEffect(this); - } -} - class AleatoryEffect extends OneShotEffect { public AleatoryEffect() { @@ -139,8 +97,8 @@ class AleatoryEffect extends OneShotEffect { if (controller.flipCoin(game)) { game.addEffect(new BoostTargetEffect(1, 1, Duration.EndOfTurn), source); return true; - } } + } return false; } diff --git a/Mage.Sets/src/mage/sets/mirage/Flash.java b/Mage.Sets/src/mage/sets/mirage/Flash.java index 02a8f7a0749..c1ed840589c 100644 --- a/Mage.Sets/src/mage/sets/mirage/Flash.java +++ b/Mage.Sets/src/mage/sets/mirage/Flash.java @@ -105,7 +105,7 @@ class FlashEffect extends OneShotEffect { StringBuilder sb = new StringBuilder("Pay ").append(reducedCost.getText()).append("?"); if (player.chooseUse(Outcome.Benefit, sb.toString(), source, game)) { reducedCost.clearPaid(); - if (reducedCost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (reducedCost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/mirage/LionsEyeDiamond.java b/Mage.Sets/src/mage/sets/mirage/LionsEyeDiamond.java index 4f42ee0fdc5..9f985fc11a0 100644 --- a/Mage.Sets/src/mage/sets/mirage/LionsEyeDiamond.java +++ b/Mage.Sets/src/mage/sets/mirage/LionsEyeDiamond.java @@ -72,7 +72,7 @@ class LionsEyeDiamondAbility extends ManaAbility { public LionsEyeDiamondAbility() { super(Zone.BATTLEFIELD, new AddManaOfAnyColorEffect(3), new SacrificeSourceCost()); this.addCost(new DiscardHandCost()); - this.netMana.add(new Mana(0,0,0,0,0,0,3)); + this.netMana.add(new Mana(0,0,0,0,0,0,3, 0)); } public LionsEyeDiamondAbility(Zone zone, Mana mana, Cost cost) { diff --git a/Mage.Sets/src/mage/sets/mirage/PhyrexianDreadnought.java b/Mage.Sets/src/mage/sets/mirage/PhyrexianDreadnought.java index 62b549deee7..3ad96e7b13e 100644 --- a/Mage.Sets/src/mage/sets/mirage/PhyrexianDreadnought.java +++ b/Mage.Sets/src/mage/sets/mirage/PhyrexianDreadnought.java @@ -31,6 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; import mage.abilities.keyword.TrampleAbility; @@ -94,7 +95,7 @@ class PhyrexianDreadnoughtSacrificeCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { int sumPower = 0; if (targets.choose(Outcome.Sacrifice, controllerId, sourceId, game)) { for (UUID targetId: targets.get(0).getTargets()) { diff --git a/Mage.Sets/src/mage/sets/mirage/ShallowGrave.java b/Mage.Sets/src/mage/sets/mirage/ShallowGrave.java index 9ee5675fccf..73db7ee1705 100644 --- a/Mage.Sets/src/mage/sets/mirage/ShallowGrave.java +++ b/Mage.Sets/src/mage/sets/mirage/ShallowGrave.java @@ -112,10 +112,7 @@ class ShallowGraveEffect extends OneShotEffect { ExileTargetEffect exileEffect = new ExileTargetEffect(null, "", Zone.BATTLEFIELD); exileEffect.setTargetPointer(fixedTarget); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } } } diff --git a/Mage.Sets/src/mage/sets/mirage/TeferisIsle.java b/Mage.Sets/src/mage/sets/mirage/TeferisIsle.java index f964bf5d912..773727a636a 100644 --- a/Mage.Sets/src/mage/sets/mirage/TeferisIsle.java +++ b/Mage.Sets/src/mage/sets/mirage/TeferisIsle.java @@ -54,7 +54,7 @@ public class TeferisIsle extends CardImpl { // Teferi's Isle enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); // {tap}: Add {U}{U} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 2, 0, 0, 0, 0), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 2, 0, 0, 0, 0, 0), new TapSourceCost())); } diff --git a/Mage.Sets/src/mage/sets/mirage/VaporousDjinn.java b/Mage.Sets/src/mage/sets/mirage/VaporousDjinn.java index 5d264035798..6cf3d2a505e 100644 --- a/Mage.Sets/src/mage/sets/mirage/VaporousDjinn.java +++ b/Mage.Sets/src/mage/sets/mirage/VaporousDjinn.java @@ -98,7 +98,7 @@ class VaporousDjinnEffect extends OneShotEffect { Cost cost = new ManaCostsImpl("{U}{U}"); String message = "Would you like to pay {U}{U} to prevent {this} from phasing out?"; if (!(controller.chooseUse(Outcome.Benefit, message, source, game) - && cost.pay(source, game, source.getSourceId(), controller.getId(), false))) { + && cost.pay(source, game, source.getSourceId(), controller.getId(), false, null))) { permanent.phaseOut(game); } return true; diff --git a/Mage.Sets/src/mage/sets/mirage/ZirilanOfTheClaw.java b/Mage.Sets/src/mage/sets/mirage/ZirilanOfTheClaw.java index 69c00094294..cdfaf0c945c 100644 --- a/Mage.Sets/src/mage/sets/mirage/ZirilanOfTheClaw.java +++ b/Mage.Sets/src/mage/sets/mirage/ZirilanOfTheClaw.java @@ -60,7 +60,7 @@ import mage.target.targetpointer.FixedTarget; * @author fireshoes */ public class ZirilanOfTheClaw extends CardImpl { - + public ZirilanOfTheClaw(UUID ownerId) { super(ownerId, 204, "Zirilan of the Claw", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); this.expansionSetCode = "MIR"; @@ -70,7 +70,7 @@ public class ZirilanOfTheClaw extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(4); - // {1}{R}{R}, {tap}: Search your library for a Dragon permanent card and put that card onto the battlefield. Then shuffle your library. + // {1}{R}{R}, {tap}: Search your library for a Dragon permanent card and put that card onto the battlefield. Then shuffle your library. // That Dragon gains haste until end of turn. Exile it at the beginning of the next end step. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ZirilanOfTheClawEffect(), new ManaCostsImpl("{1}{R}{R}")); ability.addCost(new TapSourceCost()); @@ -125,10 +125,7 @@ class ZirilanOfTheClawEffect extends OneShotEffect { ExileTargetEffect exileEffect = new ExileTargetEffect(null, null, Zone.BATTLEFIELD); exileEffect.setTargetPointer(new FixedTarget(permanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } } return true; diff --git a/Mage.Sets/src/mage/sets/mirrodin/Cathodion.java b/Mage.Sets/src/mage/sets/mirrodin/Cathodion.java index 6ca82d31e62..3ed4e730700 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/Cathodion.java +++ b/Mage.Sets/src/mage/sets/mirrodin/Cathodion.java @@ -28,13 +28,13 @@ package mage.sets.mirrodin; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.Mana; import mage.abilities.common.DiesTriggeredAbility; import mage.abilities.effects.common.BasicManaEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; /** * @@ -48,7 +48,7 @@ public class Cathodion extends CardImpl { this.subtype.add("Construct"); this.power = new MageInt(3); this.toughness = new MageInt(3); - this.addAbility(new DiesTriggeredAbility(new BasicManaEffect(new Mana(0, 0, 0, 0, 0, 3, 0)), false)); + this.addAbility(new DiesTriggeredAbility(new BasicManaEffect(new Mana(0, 0, 0, 0, 0, 0, 0, 3)), false)); } public Cathodion(final Cathodion card) { diff --git a/Mage.Sets/src/mage/sets/mirrodin/ClockworkCondor.java b/Mage.Sets/src/mage/sets/mirrodin/ClockworkCondor.java index d995f968486..a8ed102a9b8 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/ClockworkCondor.java +++ b/Mage.Sets/src/mage/sets/mirrodin/ClockworkCondor.java @@ -25,13 +25,9 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.mirrodin; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksOrBlocksTriggeredAbility; @@ -42,7 +38,9 @@ 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.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; @@ -53,7 +51,7 @@ import mage.game.permanent.Permanent; */ public class ClockworkCondor extends CardImpl { - public ClockworkCondor (UUID ownerId) { + public ClockworkCondor(UUID ownerId) { super(ownerId, 154, "Clockwork Condor", Rarity.COMMON, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); this.expansionSetCode = "MRD"; this.subtype.add("Bird"); @@ -64,7 +62,7 @@ public class ClockworkCondor extends CardImpl { this.addAbility(new AttacksOrBlocksTriggeredAbility(new ClockworkCondorEffect(), false)); } - public ClockworkCondor (final ClockworkCondor card) { + public ClockworkCondor(final ClockworkCondor card) { super(card); } @@ -75,6 +73,7 @@ public class ClockworkCondor extends CardImpl { } class ClockworkCondorEffect extends OneShotEffect { + ClockworkCondorEffect() { super(Outcome.UnboostCreature); staticText = "remove a +1/+1 counter from {this} at end of combat"; @@ -89,9 +88,7 @@ class ClockworkCondorEffect extends OneShotEffect { Permanent p = game.getPermanent(source.getSourceId()); if (p != null) { AtTheEndOfCombatDelayedTriggeredAbility ability = new AtTheEndOfCombatDelayedTriggeredAbility(new RemoveCounterSourceEffect(CounterType.P1P1.createInstance())); - ability.setSourceId(source.getSourceId()); - ability.setControllerId(source.getControllerId()); - game.addDelayedTriggeredAbility(ability); + game.addDelayedTriggeredAbility(ability, source); } return false; } diff --git a/Mage.Sets/src/mage/sets/mirrodin/ClockworkDragon.java b/Mage.Sets/src/mage/sets/mirrodin/ClockworkDragon.java index d478eb1a378..e7174b34e09 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/ClockworkDragon.java +++ b/Mage.Sets/src/mage/sets/mirrodin/ClockworkDragon.java @@ -25,14 +25,9 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.mirrodin; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksOrBlocksTriggeredAbility; @@ -45,7 +40,10 @@ 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.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; @@ -56,7 +54,7 @@ import mage.game.permanent.Permanent; */ public class ClockworkDragon extends CardImpl { - public ClockworkDragon (UUID ownerId) { + public ClockworkDragon(UUID ownerId) { super(ownerId, 155, "Clockwork Dragon", Rarity.RARE, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{7}"); this.expansionSetCode = "MRD"; this.subtype.add("Dragon"); @@ -68,7 +66,7 @@ public class ClockworkDragon extends CardImpl { this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new GenericManaCost(3))); } - public ClockworkDragon (final ClockworkDragon card) { + public ClockworkDragon(final ClockworkDragon card) { super(card); } @@ -79,6 +77,7 @@ public class ClockworkDragon extends CardImpl { } class ClockworkDragonEffect extends OneShotEffect { + ClockworkDragonEffect() { super(Outcome.UnboostCreature); staticText = "remove a +1/+1 counter from {this} at end of combat"; @@ -93,9 +92,7 @@ class ClockworkDragonEffect extends OneShotEffect { Permanent p = game.getPermanent(source.getSourceId()); if (p != null) { AtTheEndOfCombatDelayedTriggeredAbility ability = new AtTheEndOfCombatDelayedTriggeredAbility(new RemoveCounterSourceEffect(CounterType.P1P1.createInstance())); - ability.setSourceId(source.getSourceId()); - ability.setControllerId(source.getControllerId()); - game.addDelayedTriggeredAbility(ability); + game.addDelayedTriggeredAbility(ability, source); } return false; } diff --git a/Mage.Sets/src/mage/sets/mirrodin/ClockworkVorrac.java b/Mage.Sets/src/mage/sets/mirrodin/ClockworkVorrac.java index e783cbcbbb4..8bd4c71c1bb 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/ClockworkVorrac.java +++ b/Mage.Sets/src/mage/sets/mirrodin/ClockworkVorrac.java @@ -28,9 +28,6 @@ package mage.sets.mirrodin; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksOrBlocksTriggeredAbility; @@ -43,7 +40,9 @@ import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; @@ -79,6 +78,7 @@ public class ClockworkVorrac extends CardImpl { } class ClockworkVorracEffect extends OneShotEffect { + ClockworkVorracEffect() { super(Outcome.UnboostCreature); staticText = "remove a +1/+1 counter from {this} at end of combat"; @@ -93,9 +93,7 @@ class ClockworkVorracEffect extends OneShotEffect { Permanent p = game.getPermanent(source.getSourceId()); if (p != null) { AtTheEndOfCombatDelayedTriggeredAbility ability = new AtTheEndOfCombatDelayedTriggeredAbility(new RemoveCounterSourceEffect(CounterType.P1P1.createInstance())); - ability.setSourceId(source.getSourceId()); - ability.setControllerId(source.getControllerId()); - game.addDelayedTriggeredAbility(ability); + game.addDelayedTriggeredAbility(ability, source); } return false; } @@ -106,4 +104,3 @@ class ClockworkVorracEffect extends OneShotEffect { } } - diff --git a/Mage.Sets/src/mage/sets/mirrodin/CrystalShard.java b/Mage.Sets/src/mage/sets/mirrodin/CrystalShard.java index 5068a42903b..8d848adfe4c 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/CrystalShard.java +++ b/Mage.Sets/src/mage/sets/mirrodin/CrystalShard.java @@ -107,7 +107,7 @@ class CrystalShardEffect extends OneShotEffect { cost.clearPaid(); final StringBuilder sb = new StringBuilder("Pay {1}? (Otherwise ").append(targetCreature.getName()).append(" will be returned to its owner's hand)"); if (player.chooseUse(Outcome.Benefit, sb.toString(), source, game)) { - cost.pay(source, game, targetCreature.getControllerId(), targetCreature.getControllerId(), false); + cost.pay(source, game, targetCreature.getControllerId(), targetCreature.getControllerId(), false, null); } if (!cost.isPaid()) { controller.moveCards(targetCreature, Zone.BATTLEFIELD, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/sets/mirrodin/Deconstruct.java b/Mage.Sets/src/mage/sets/mirrodin/Deconstruct.java index 9ee62a3fbbd..5617cb1216f 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/Deconstruct.java +++ b/Mage.Sets/src/mage/sets/mirrodin/Deconstruct.java @@ -56,7 +56,7 @@ public class Deconstruct extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent(filter)); - this.getSpellAbility().addEffect(new BasicManaEffect(new Mana(0, 3, 0, 0, 0, 0, 0))); + this.getSpellAbility().addEffect(new BasicManaEffect(new Mana(0, 3, 0, 0, 0, 0, 0, 0))); } public Deconstruct(final Deconstruct card) { diff --git a/Mage.Sets/src/mage/sets/mirrodin/NeurokFamiliar.java b/Mage.Sets/src/mage/sets/mirrodin/NeurokFamiliar.java new file mode 100644 index 00000000000..ad5b4eeb64c --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirrodin/NeurokFamiliar.java @@ -0,0 +1,119 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mirrodin; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterArtifactCard; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author rollergo11 + */ +public class NeurokFamiliar extends CardImpl { + + public NeurokFamiliar(UUID ownerId) { + super(ownerId, 43, "Neurok Familiar", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{U}"); + this.expansionSetCode = "MRD"; + this.subtype.add("Bird"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // When Neurok Familiar enters the battlefield, reveal the top card of your library. If it's an artifact card, put it into your hand. Otherwise, put it into your graveyard. + this.addAbility(new EntersBattlefieldTriggeredAbility(new NeurokFamiliarEffect())); + } + + public NeurokFamiliar(final NeurokFamiliar card) { + super(card); + } + + @java.lang.Override + public NeurokFamiliar copy() { + return new NeurokFamiliar(this); + } +} + +class NeurokFamiliarEffect extends OneShotEffect { + + private static final FilterArtifactCard filterPutInHand = new FilterArtifactCard("artifact card to put in hand"); + + public NeurokFamiliarEffect() { + super(Outcome.DrawCard); + this.staticText = "Reveal the top card of your library. If it's an artifact card, put it into your hand. Otherwise, put it into your graveyard."; + } + + public NeurokFamiliarEffect(final NeurokFamiliarEffect effect) { + super(effect); + } + + @java.lang.Override + public NeurokFamiliarEffect copy() { + return new NeurokFamiliarEffect(this); + } + + @java.lang.Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller == null || sourceObject == null) { + return false; + } + + if (controller.getLibrary().size() > 0) { + Card card = controller.getLibrary().getFromTop(game); + if (card != null) { + Cards cards = new CardsImpl(card); + controller.revealCards(sourceObject.getIdName(), cards, game); + if (card.getCardType().contains(CardType.ARTIFACT)) { + controller.moveCards(card, Zone.HAND, source, game); + } else { + controller.moveCards(card, Zone.GRAVEYARD, source, game); + } + } + } + return true; + } + +} diff --git a/Mage.Sets/src/mage/sets/mirrodin/RustElemental.java b/Mage.Sets/src/mage/sets/mirrodin/RustElemental.java new file mode 100644 index 00000000000..51734a30993 --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirrodin/RustElemental.java @@ -0,0 +1,124 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mirrodin; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.OnEventTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author rollergo11 + */ +public class RustElemental extends CardImpl { + + public RustElemental(UUID ownerId) { + super(ownerId, 234, "Rust Elemental", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); + this.expansionSetCode = "MRD"; + this.subtype.add("Elemental"); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // At the beginning of your upkeep, sacrifice an artifact other than Rust Elemental. If you can't, tap Rust Elemental and you lose 4 life. + this.addAbility(new OnEventTriggeredAbility(GameEvent.EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", new RustElementalEffect(), false)); + } + + public RustElemental(final RustElemental card) { + super(card); + } + + @java.lang.Override + public RustElemental copy() { + return new RustElemental(this); + } +} + +class RustElementalEffect extends OneShotEffect { + + private static final FilterControlledArtifactPermanent filter = new FilterControlledArtifactPermanent("artifact"); + + static { + filter.add(new AnotherPredicate()); + } + + public RustElementalEffect() { + super(Outcome.Damage); + this.staticText = "Sacrifice an artifact other than {this}. If you can't, tap {this} and you lose 4 life."; + } + + public RustElementalEffect(final RustElementalEffect effect) { + super(effect); + } + + @java.lang.Override + public RustElementalEffect copy() { + return new RustElementalEffect(this); + } + + @java.lang.Override + public boolean apply(Game game, Ability source) { + Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (sourceObject != null) { + // create cost for sacrificing an artifact + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); + // if they can pay the cost, then they must pay + if (target.canChoose(source.getSourceId(), controller.getId(), game)) { + controller.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + Permanent artifactSacrifice = game.getPermanent(target.getFirstTarget()); + if (artifactSacrifice != null) { + // sacrifice the chosen artifact + artifactSacrifice.sacrifice(source.getSourceId(), game); + } + } else { + sourceObject.tap(game); + controller.damage(4, source.getSourceId(), game, false, true); + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/mirrodin/SeethingSong.java b/Mage.Sets/src/mage/sets/mirrodin/SeethingSong.java index 63ddebe54fd..2e29d38b13f 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/SeethingSong.java +++ b/Mage.Sets/src/mage/sets/mirrodin/SeethingSong.java @@ -44,7 +44,7 @@ public class SeethingSong extends CardImpl { super(ownerId, 104, "Seething Song", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{2}{R}"); this.expansionSetCode = "MRD"; - this.getSpellAbility().addEffect(new BasicManaEffect(new Mana(5, 0, 0, 0, 0, 0, 0))); + this.getSpellAbility().addEffect(new BasicManaEffect(new Mana(5, 0, 0, 0, 0, 0, 0, 0))); } public SeethingSong(final SeethingSong card) { diff --git a/Mage.Sets/src/mage/sets/mirrodin/TajNarSwordsmith.java b/Mage.Sets/src/mage/sets/mirrodin/TajNarSwordsmith.java index 884f933f931..51a8115e68d 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/TajNarSwordsmith.java +++ b/Mage.Sets/src/mage/sets/mirrodin/TajNarSwordsmith.java @@ -97,7 +97,7 @@ class TajNarSwordsmithEffect extends OneShotEffect { if (player != null && player.chooseUse(Outcome.BoostCreature, "Do you want to to pay {X}?", source, game)) { int costX = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); Cost cost = new GenericManaCost(costX); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { FilterCard filter = new FilterCard("Equipment card with converted mana cost " + costX + " or less"); filter.add(new SubtypePredicate("Equipment")); filter.add(new ConvertedManaCostPredicate(ComparisonType.LessThan, costX + 1)); diff --git a/Mage.Sets/src/mage/sets/mirrodin/TurnToDust.java b/Mage.Sets/src/mage/sets/mirrodin/TurnToDust.java index e7d98325521..e5f7433b23c 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/TurnToDust.java +++ b/Mage.Sets/src/mage/sets/mirrodin/TurnToDust.java @@ -56,7 +56,7 @@ public class TurnToDust extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent(filter)); - this.getSpellAbility().addEffect(new BasicManaEffect(new Mana(0, 1, 0, 0, 0, 0, 0))); + this.getSpellAbility().addEffect(new BasicManaEffect(new Mana(0, 1, 0, 0, 0, 0, 0, 0))); } public TurnToDust(final TurnToDust card) { diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/GruesomeEncore.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/GruesomeEncore.java index 1ebbe5a9c6f..fb9d37d566d 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/GruesomeEncore.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/GruesomeEncore.java @@ -28,11 +28,6 @@ package mage.sets.mirrodinbesieged; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; @@ -44,6 +39,11 @@ import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.HasteAbility; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.game.events.GameEvent; @@ -63,7 +63,7 @@ public class GruesomeEncore extends CardImpl { super(ownerId, 44, "Gruesome Encore", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{2}{B}"); this.expansionSetCode = "MBS"; - // Put target creature card from an opponent's graveyard onto the battlefield under your control. It gains haste. + // Put target creature card from an opponent's graveyard onto the battlefield under your control. It gains haste. this.getSpellAbility().addEffect(new GruesomeEncoreEffect()); // Exile it at the beginning of the next end step. If that creature would leave the battlefield, exile it instead of putting it anywhere else. this.getSpellAbility().addEffect(new GruesomeEncoreReplacementEffect()); @@ -109,10 +109,7 @@ class GruesomeEncoreEffect extends OneShotEffect { ExileTargetEffect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(new FixedTarget(card.getId())); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java index 606fe4a93a0..57fc2668225 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java @@ -44,7 +44,7 @@ import mage.filter.common.FilterNonlandCard; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.permanent.PermanentToken; +import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.players.Player; import mage.target.common.TargetCardInExile; @@ -167,11 +167,10 @@ class KnowledgePoolEffect2 extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); - MageObject sourceObject = game.getObject(source.getSourceId()); + Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId()); Player controller = game.getPlayer(source.getControllerId()); if (controller != null && spell != null && sourceObject != null) { - int zoneChangeCounter = (sourceObject instanceof PermanentToken) ? source.getSourceObjectZoneChangeCounter() : source.getSourceObjectZoneChangeCounter() - 1; - UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter); + UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), sourceObject.getZoneChangeCounter(game)); if (controller.moveCardsToExile(spell, source, game, true, exileZoneId, sourceObject.getIdName())) { Player player = game.getPlayer(spell.getControllerId()); if (player != null && player.chooseUse(Outcome.PlayForFree, "Cast another nonland card exiled with " + sourceObject.getLogName() + " without paying that card's mana cost?", source, game)) { diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/PistusStrike.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/PistusStrike.java index b9b7e8424f4..136ac6a28da 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/PistusStrike.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/PistusStrike.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,19 +20,17 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.mirrodinbesieged; import java.util.UUID; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; @@ -62,7 +60,6 @@ public class PistusStrike extends CardImpl { super(ownerId, 86, "Pistus Strike", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{2}{G}"); this.expansionSetCode = "MBS"; - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addEffect(new PoisonControllerTargetCreatureEffect()); @@ -96,15 +93,13 @@ class PoisonControllerTargetCreatureEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent p = game.getBattlefield().getPermanent(source.getFirstTarget()); - if (p == null) { - p = (Permanent) game.getLastKnownInformation(source.getFirstTarget(), Zone.BATTLEFIELD); - } - if (p != null) { - Player player = game.getPlayer(p.getControllerId()); + Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); + if (permanent != null) { + Player player = game.getPlayer(permanent.getControllerId()); if (player != null) { player.addCounters(CounterType.POISON.createInstance(), game); } + return true; } return false; } diff --git a/Mage.Sets/src/mage/sets/modernmasters/DesperateRitual.java b/Mage.Sets/src/mage/sets/modernmasters/DesperateRitual.java index c3da260b041..034061e8a7c 100644 --- a/Mage.Sets/src/mage/sets/modernmasters/DesperateRitual.java +++ b/Mage.Sets/src/mage/sets/modernmasters/DesperateRitual.java @@ -48,7 +48,7 @@ public class DesperateRitual extends CardImpl { // Add {R}{R}{R} to your mana pool. - this.getSpellAbility().addEffect(new BasicManaEffect(new Mana(3, 0, 0, 0, 0, 0, 0))); + this.getSpellAbility().addEffect(new BasicManaEffect(new Mana(3, 0, 0, 0, 0, 0, 0, 0))); // Splice onto Arcane {1}{R} this.addAbility(new SpliceOntoArcaneAbility("{1}{R}")); } diff --git a/Mage.Sets/src/mage/sets/modernmasters/GrinningIgnus.java b/Mage.Sets/src/mage/sets/modernmasters/GrinningIgnus.java index f9c3f1ae041..f833771589f 100644 --- a/Mage.Sets/src/mage/sets/modernmasters/GrinningIgnus.java +++ b/Mage.Sets/src/mage/sets/modernmasters/GrinningIgnus.java @@ -54,7 +54,7 @@ public class GrinningIgnus extends CardImpl { this.toughness = new MageInt(2); // {R}, Return Grinning Ignus to its owner's hand: Add {C}{C}{R} to your mana pool. Activate this ability only any time you could cast a sorcery. - Ability ability = new ActivateAsSorceryManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 0, 0, 2, 0), new ManaCostsImpl("{R}")); + Ability ability = new ActivateAsSorceryManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 0, 0, 0, 0, 2), new ManaCostsImpl("{R}")); ability.addCost(new ReturnToHandFromBattlefieldSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/modernmasters/IncrementalGrowth.java b/Mage.Sets/src/mage/sets/modernmasters/IncrementalGrowth.java index 3eccc7bed57..0f9c606abad 100644 --- a/Mage.Sets/src/mage/sets/modernmasters/IncrementalGrowth.java +++ b/Mage.Sets/src/mage/sets/modernmasters/IncrementalGrowth.java @@ -35,6 +35,8 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.Target; @@ -53,8 +55,23 @@ public class IncrementalGrowth extends CardImpl { // 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()); - Target target = new TargetCreaturePermanent(3,3); - this.getSpellAbility().addTarget(target); + + 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 counter)"); + 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); } public IncrementalGrowth(final IncrementalGrowth card) { @@ -86,9 +103,9 @@ class IncrementalGrowthEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int i = 0; - for (UUID targetId : getTargetPointer().getTargets(game, source)) { + for (Target target : source.getTargets()) { i++; - Permanent creature = game.getPermanent(targetId); + Permanent creature = game.getPermanent(target.getFirstTarget()); if (creature != null) { creature.addCounters(CounterType.P1P1.createInstance(i), game); } diff --git a/Mage.Sets/src/mage/sets/modernmasters/RiftElemental.java b/Mage.Sets/src/mage/sets/modernmasters/RiftElemental.java index d903c91b4d8..a580a6e15de 100644 --- a/Mage.Sets/src/mage/sets/modernmasters/RiftElemental.java +++ b/Mage.Sets/src/mage/sets/modernmasters/RiftElemental.java @@ -35,6 +35,7 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.ActivatedAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.RemoveCounterCost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -141,7 +142,7 @@ class RemoveCounterFromCardCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { paid = false; Player controller = game.getPlayer(controllerId); if (target.choose(Outcome.UnboostCreature, controllerId, sourceId, game)) { diff --git a/Mage.Sets/src/mage/sets/morningtide/HeritageDruid.java b/Mage.Sets/src/mage/sets/morningtide/HeritageDruid.java index 91526f04495..4bd393d4667 100644 --- a/Mage.Sets/src/mage/sets/morningtide/HeritageDruid.java +++ b/Mage.Sets/src/mage/sets/morningtide/HeritageDruid.java @@ -64,7 +64,7 @@ public class HeritageDruid extends CardImpl { this.toughness = new MageInt(1); // Tap three untapped Elves you control: Add {G}{G}{G} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 3, 0, 0, 0, 0, 0), new TapTargetCost(new TargetControlledCreaturePermanent(3, 3, filter, true)))); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 3, 0, 0, 0, 0, 0, 0), new TapTargetCost(new TargetControlledCreaturePermanent(3, 3, filter, true)))); } public HeritageDruid(final HeritageDruid card) { diff --git a/Mage.Sets/src/mage/sets/morningtide/MorselTheft.java b/Mage.Sets/src/mage/sets/morningtide/MorselTheft.java new file mode 100644 index 00000000000..350e66b4cc9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/morningtide/MorselTheft.java @@ -0,0 +1,75 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.morningtide; + +import java.util.UUID; +import mage.abilities.condition.common.ProwlCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.keyword.ProwlAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.TargetPlayer; + +/** + * + * @author LevelX2 + */ +public class MorselTheft extends CardImpl { + + public MorselTheft(UUID ownerId) { + super(ownerId, 68, "Morsel Theft", Rarity.COMMON, new CardType[]{CardType.TRIBAL, CardType.SORCERY}, "{2}{B}{B}"); + this.expansionSetCode = "MOR"; + this.subtype.add("Rogue"); + + // Prowl {1}{B} + this.addAbility(new ProwlAbility(this, "{1}{B}")); + + // Target player loses 3 life and you gain 3 life. If Morsel Theft's prowl cost was paid, draw a card. + getSpellAbility().addEffect(new LoseLifeTargetEffect(3)); + Effect effect = new GainLifeEffect(3); + effect.setText("and you gain 3 life"); + getSpellAbility().addEffect(effect); + getSpellAbility().addTarget(new TargetPlayer()); + getSpellAbility().addEffect(new ConditionalOneShotEffect(new DrawCardSourceControllerEffect(1), ProwlCondition.getInstance())); + + } + + public MorselTheft(final MorselTheft card) { + super(card); + } + + @Override + public MorselTheft copy() { + return new MorselTheft(this); + } +} diff --git a/Mage.Sets/src/mage/sets/nemesis/RootwaterThief.java b/Mage.Sets/src/mage/sets/nemesis/RootwaterThief.java index d7450641687..3cc720fe8c8 100644 --- a/Mage.Sets/src/mage/sets/nemesis/RootwaterThief.java +++ b/Mage.Sets/src/mage/sets/nemesis/RootwaterThief.java @@ -99,7 +99,7 @@ class RootwaterThiefEffect extends OneShotEffect { } String message = "Pay {2} to exile a card from damaged player's library?"; Cost cost = new ManaCostsImpl("{2}"); - if(controller.chooseUse(Outcome.Benefit, message, source, game) && cost.pay(source, game, source.getSourceId(), controller.getId(), false)) + if(controller.chooseUse(Outcome.Benefit, message, source, game) && cost.pay(source, game, source.getSourceId(), controller.getId(), false, null)) { TargetCardInLibrary target = new TargetCardInLibrary(); if (controller.searchLibrary(target, game, damagedPlayer.getId())) { diff --git a/Mage.Sets/src/mage/sets/nemesis/StrongholdGambit.java b/Mage.Sets/src/mage/sets/nemesis/StrongholdGambit.java new file mode 100644 index 00000000000..32eefe884f0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/nemesis/StrongholdGambit.java @@ -0,0 +1,138 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.nemesis; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInHand; + +/** + * + * @author LevelX2 + */ +public class StrongholdGambit extends CardImpl { + + public StrongholdGambit(UUID ownerId) { + super(ownerId, 100, "Stronghold Gambit", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{1}{R}"); + this.expansionSetCode = "NMS"; + + // Each player chooses a card in his or her hand. Then each player reveals his or her chosen card. The owner of each creature card revealed this way with the lowest converted mana cost puts it onto the battlefield. + getSpellAbility().addEffect(new StrongholdGambitEffect()); + } + + public StrongholdGambit(final StrongholdGambit card) { + super(card); + } + + @Override + public StrongholdGambit copy() { + return new StrongholdGambit(this); + } +} + +class StrongholdGambitEffect extends OneShotEffect { + + public StrongholdGambitEffect() { + super(Outcome.PutCreatureInPlay); + this.staticText = "Each player chooses a card in his or her hand. Then each player reveals his or her chosen card. The owner of each creature card revealed this way with the lowest converted mana cost puts it onto the battlefield"; + } + + public StrongholdGambitEffect(final StrongholdGambitEffect effect) { + super(effect); + } + + @Override + public StrongholdGambitEffect copy() { + return new StrongholdGambitEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller != null && sourceObject != null) { + Map choosenCard = new LinkedHashMap<>(); + for (UUID playerId : game.getState().getPlayerList(controller.getId())) { + Player player = game.getPlayer(playerId); + if (player != null && player.getHand().size() > 0) { + TargetCardInHand target = new TargetCardInHand(); + if (player.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + choosenCard.put(playerId, target.getFirstTarget()); + } + } + } + int lowestCMC = Integer.MAX_VALUE; + for (UUID playerId : game.getState().getPlayerList(controller.getId())) { + Player player = game.getPlayer(playerId); + if (player != null && choosenCard.containsKey(playerId)) { + Card card = game.getCard(choosenCard.get(playerId)); + if (card != null) { + Cards cardsToReveal = new CardsImpl(card); + player.revealCards(sourceObject.getIdName() + " (" + player.getName() + ")", cardsToReveal, game); + if (card.getCardType().contains(CardType.CREATURE) + && lowestCMC > card.getManaCost().convertedManaCost()) { + lowestCMC = card.getManaCost().convertedManaCost(); + } + } + } + } + if (lowestCMC < Integer.MAX_VALUE) { + Cards creaturesToBattlefield = new CardsImpl(); + for (UUID playerId : game.getState().getPlayerList(controller.getId())) { + Player player = game.getPlayer(playerId); + if (player != null && choosenCard.containsKey(playerId)) { + Card card = game.getCard(choosenCard.get(playerId)); + if (card != null) { + if (card.getCardType().contains(CardType.CREATURE) + && lowestCMC == card.getManaCost().convertedManaCost()) { + creaturesToBattlefield.add(card); + } + } + } + } + controller.moveCards(creaturesToBattlefield.getCards(game), Zone.BATTLEFIELD, source, game, false, false, true, null); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/newphyrexia/Artillerize.java b/Mage.Sets/src/mage/sets/newphyrexia/Artillerize.java index 0271c845d2b..359e59c939c 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/Artillerize.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/Artillerize.java @@ -28,11 +28,11 @@ package mage.sets.newphyrexia; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -45,7 +45,7 @@ import mage.target.common.TargetCreatureOrPlayer; */ public class Artillerize extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("artifact or creature"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("an artifact or creature"); static { filter.add(Predicates.or( @@ -57,7 +57,6 @@ public class Artillerize extends CardImpl { super(ownerId, 79, "Artillerize", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{3}{R}"); this.expansionSetCode = "NPH"; - this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); this.getSpellAbility().addEffect(new DamageTargetEffect(5)); diff --git a/Mage.Sets/src/mage/sets/newphyrexia/BeastWithin.java b/Mage.Sets/src/mage/sets/newphyrexia/BeastWithin.java index bbdaed7f86a..2d77d6380ea 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/BeastWithin.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/BeastWithin.java @@ -28,15 +28,13 @@ package mage.sets.newphyrexia; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; -import mage.constants.Zone; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.BeastToken; @@ -52,7 +50,7 @@ public class BeastWithin extends CardImpl { super(ownerId, 103, "Beast Within", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{2}{G}"); this.expansionSetCode = "NPH"; - + // Destroy target permanent. Its controller puts a 3/3 green Beast creature token onto the battlefield. this.getSpellAbility().addTarget(new TargetPermanent()); this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addEffect(new BeastWithinEffect()); @@ -86,12 +84,11 @@ class BeastWithinEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.BATTLEFIELD); + Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); if (permanent != null) { - BeastToken token = new BeastToken(); - token.putOntoBattlefield(1, game, source.getSourceId(), permanent.getControllerId()); + new BeastToken().putOntoBattlefield(1, game, source.getSourceId(), permanent.getControllerId()); } return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/newphyrexia/ChancellorOfTheAnnex.java b/Mage.Sets/src/mage/sets/newphyrexia/ChancellorOfTheAnnex.java index cacff52229b..c30f13f58b7 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/ChancellorOfTheAnnex.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/ChancellorOfTheAnnex.java @@ -84,7 +84,7 @@ public class ChancellorOfTheAnnex extends CardImpl { class ChancellorOfTheAnnexEffect extends OneShotEffect { - public ChancellorOfTheAnnexEffect () { + public ChancellorOfTheAnnexEffect() { super(Outcome.Benefit); staticText = "when each opponent casts his or her first spell of the game, counter that spell unless that player pays {1}"; } @@ -97,9 +97,7 @@ class ChancellorOfTheAnnexEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { DelayedTriggeredAbility ability = new ChancellorOfTheAnnexDelayedTriggeredAbility(opponentId); - ability.setSourceId(source.getSourceId()); - ability.setControllerId(source.getControllerId()); - game.addDelayedTriggeredAbility(ability); + game.addDelayedTriggeredAbility(ability, source); } return true; } @@ -115,7 +113,7 @@ class ChancellorOfTheAnnexDelayedTriggeredAbility extends DelayedTriggeredAbilit private final UUID playerId; - ChancellorOfTheAnnexDelayedTriggeredAbility (UUID playerId) { + ChancellorOfTheAnnexDelayedTriggeredAbility(UUID playerId) { super(new CounterUnlessPaysEffect(new GenericManaCost(1))); this.playerId = playerId; } diff --git a/Mage.Sets/src/mage/sets/newphyrexia/GreenhiltTrainee.java b/Mage.Sets/src/mage/sets/newphyrexia/GreenhiltTrainee.java index b207f7bddb1..14202ac9810 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/GreenhiltTrainee.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/GreenhiltTrainee.java @@ -35,6 +35,7 @@ import mage.constants.Rarity; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.common.continuous.BoostTargetEffect; @@ -102,7 +103,7 @@ class GreenhiltTraineeCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { this.paid = true; return paid; } diff --git a/Mage.Sets/src/mage/sets/newphyrexia/LeechingBite.java b/Mage.Sets/src/mage/sets/newphyrexia/LeechingBite.java index 54869297d22..eb760b652e1 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/LeechingBite.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/LeechingBite.java @@ -28,15 +28,20 @@ package mage.sets.newphyrexia; import java.util.UUID; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffectImpl; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; import mage.constants.Rarity; +import mage.constants.SubLayer; import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; -import mage.target.targetpointer.SecondTargetPointer; /** * @@ -48,16 +53,20 @@ public class LeechingBite extends CardImpl { super(ownerId, 113, "Leeching Bite", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{G}"); this.expansionSetCode = "NPH"; + // Target creature gets +1/+1 until end of turn. Another target creature gets -1/-1 until end of turn. - 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(new FilterCreaturePermanent("creature (getting the +1/+1 counter)"))); - effect = new BoostTargetEffect(-1, -1, Duration.EndOfTurn); - effect.setText("Another target creature gets -1/-1 until end of turn"); - effect.setTargetPointer(new SecondTargetPointer()); - this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature (getting the -1/-1 counter)"))); + 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); } public LeechingBite(final LeechingBite card) { @@ -69,3 +78,35 @@ public 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"; + } + + public 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/sets/ninthedition/FellwarStone.java b/Mage.Sets/src/mage/sets/ninthedition/FellwarStone.java index b9c37a37bc9..c74123bb228 100644 --- a/Mage.Sets/src/mage/sets/ninthedition/FellwarStone.java +++ b/Mage.Sets/src/mage/sets/ninthedition/FellwarStone.java @@ -28,10 +28,11 @@ package mage.sets.ninthedition; import java.util.UUID; -import mage.abilities.mana.AnyColorOpponentLandsProduceManaAbility; +import mage.abilities.mana.AnyColorLandsProduceManaAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; +import mage.constants.TargetController; /** * @@ -44,7 +45,7 @@ public class FellwarStone extends CardImpl { this.expansionSetCode = "9ED"; // {T}: Add to your mana pool one mana of any color that a land an opponent controls could produce. - this.addAbility(new AnyColorOpponentLandsProduceManaAbility()); + this.addAbility(new AnyColorLandsProduceManaAbility(TargetController.OPPONENT)); } public FellwarStone(final FellwarStone card) { diff --git a/Mage.Sets/src/mage/sets/ninthedition/Plagiarize.java b/Mage.Sets/src/mage/sets/ninthedition/Plagiarize.java new file mode 100644 index 00000000000..0a7252c9b77 --- /dev/null +++ b/Mage.Sets/src/mage/sets/ninthedition/Plagiarize.java @@ -0,0 +1,111 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.ninthedition; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.target.TargetPlayer; + +/** + * + * @author Skyler Sell + */ +public class Plagiarize extends CardImpl { + + public Plagiarize(UUID ownerId) { + super(ownerId, 89, "Plagiarize", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{3}{U}"); + this.expansionSetCode = "9ED"; + + // Until end of turn, if target player would draw a card, instead that player skips that draw and you draw a card. + this.getSpellAbility().addTarget(new TargetPlayer()); + this.getSpellAbility().addEffect(new PlagiarizeEffect()); + } + + public Plagiarize(final Plagiarize card) { + super(card); + } + + @Override + public Plagiarize copy() { + return new Plagiarize(this); + } +} + +class PlagiarizeEffect extends ReplacementEffectImpl { + + + public PlagiarizeEffect() { + super(Duration.EndOfTurn, Outcome.Detriment); + staticText = "Until end of turn, if target player would draw a card, instead that player skips that draw and you draw a card"; + } + + public PlagiarizeEffect(final PlagiarizeEffect effect) { + super(effect); + } + + @Override + public PlagiarizeEffect copy() { + return new PlagiarizeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + player.drawCards(1, game, event.getAppliedEffects()); + } + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DRAW_CARD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getPlayerId().equals(source.getFirstTarget())) { + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/AbstruseInterference.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/AbstruseInterference.java new file mode 100644 index 00000000000..6fe5be15dd7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/AbstruseInterference.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CounterUnlessPaysEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.game.permanent.token.EldraziScionToken; +import mage.target.TargetSpell; + +/** + * + * @author fireshoes + */ +public class AbstruseInterference extends CardImpl { + + public AbstruseInterference(UUID ownerId) { + super(ownerId, 40, "Abstruse Interference", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{2}{U}"); + this.expansionSetCode = "OGW"; + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // Counter target spell unless its controller pays {1}. + this.getSpellAbility().addTarget(new TargetSpell()); + this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(new GenericManaCost(1))); + + // You put a 1/1 colorless Eldrazi Scion creature token onto the battlefield. It has "Sacrifice this creature: Add {C} to your mana pool." + Effect effect = new CreateTokenEffect(new EldraziScionToken()); + effect.setText("You put a 1/1 colorless Eldrazi Scion creature token onto the battlefield. It has \"Sacrifice this creature: Add {C} to your mana pool.\""); + this.getSpellAbility().addEffect(effect); + } + + public AbstruseInterference(final AbstruseInterference card) { + super(card); + } + + @Override + public AbstruseInterference copy() { + return new AbstruseInterference(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/AffaProtector.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/AffaProtector.java new file mode 100644 index 00000000000..079003ef4e4 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/AffaProtector.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class AffaProtector extends CardImpl { + + public AffaProtector(UUID ownerId) { + super(ownerId, 14, "Affa Protector", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{W}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Human"); + this.subtype.add("Soldier"); + this.subtype.add("Ally"); + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + } + + public AffaProtector(final AffaProtector card) { + super(card); + } + + @Override + public AffaProtector copy() { + return new AffaProtector(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/AkoumFlameseeker.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/AkoumFlameseeker.java new file mode 100644 index 00000000000..1614e2e63b1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/AkoumFlameseeker.java @@ -0,0 +1,120 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +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.common.TapTargetCost; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author fireshoes + */ +public class AkoumFlameseeker extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("an untapped Ally you control"); + + static { + filter.add(new SubtypePredicate("Ally")); + filter.add(Predicates.not(new TappedPredicate())); + } + + public AkoumFlameseeker(UUID ownerId) { + super(ownerId, 101, "Akoum Flameseeker", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{R}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Human"); + this.subtype.add("Shaman"); + this.subtype.add("Ally"); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Cohort — {T}, Tap an untapped Ally you control: Discard a card. If you do, draw a card. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new AkoumFlameseekerEffect(), new TapSourceCost()); + ability.addCost(new TapTargetCost(new TargetControlledPermanent(filter))); + ability.setAbilityWord(AbilityWord.COHORT); + this.addAbility(ability); + } + + public AkoumFlameseeker(final AkoumFlameseeker card) { + super(card); + } + + @Override + public AkoumFlameseeker copy() { + return new AkoumFlameseeker(this); + } +} + +class AkoumFlameseekerEffect extends OneShotEffect { + + public AkoumFlameseekerEffect() { + super(Outcome.DrawCard); + this.staticText = "Discard a card. If you do, draw a card"; + } + + public AkoumFlameseekerEffect(final AkoumFlameseekerEffect effect) { + super(effect); + } + + @Override + public AkoumFlameseekerEffect copy() { + return new AkoumFlameseekerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Cards cards = controller.discard(1, false, source, game); + if (!cards.isEmpty()) { + controller.drawCards(1, game); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/AlliedReinforcements.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/AlliedReinforcements.java new file mode 100644 index 00000000000..4acffed88c6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/AlliedReinforcements.java @@ -0,0 +1,74 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.game.permanent.token.Token; + +/** + * + * @author fireshoes + */ +public class AlliedReinforcements extends CardImpl { + + public AlliedReinforcements(UUID ownerId) { + super(ownerId, 15, "Allied Reinforcements", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{3}{W}"); + this.expansionSetCode = "OGW"; + + // Put two 2/2 white Knight Ally creature tokens onto the battlefield. + this.getSpellAbility().addEffect(new CreateTokenEffect(new KnightAllyToken(), 2)); + } + + public AlliedReinforcements(final AlliedReinforcements card) { + super(card); + } + + @Override + public AlliedReinforcements copy() { + return new AlliedReinforcements(this); + } +} + +class KnightAllyToken extends Token { + + public KnightAllyToken() { + super("Knight Ally", "2/2 white Knight Ally creature token"); + this.setExpansionSetCodeForImage("BFZ"); + cardType.add(CardType.CREATURE); + color.setWhite(true); + subtype.add("Knight"); + subtype.add("Ally"); + power = new MageInt(2); + toughness = new MageInt(2); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/AncientCrab.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/AncientCrab.java new file mode 100644 index 00000000000..9cc546aba33 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/AncientCrab.java @@ -0,0 +1,58 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class AncientCrab extends CardImpl { + + public AncientCrab(UUID ownerId) { + super(ownerId, 50, "Ancient Crab", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Crab"); + this.power = new MageInt(1); + this.toughness = new MageInt(5); + } + + public AncientCrab(final AncientCrab card) { + super(card); + } + + @Override + public AncientCrab copy() { + return new AncientCrab(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/BalothNull.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/BalothNull.java new file mode 100644 index 00000000000..1f1bcb14d29 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/BalothNull.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterCreatureCard; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author fireshoes + */ +public class BalothNull extends CardImpl { + + public BalothNull(UUID ownerId) { + super(ownerId, 152, "Baloth Null", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{4}{B}{G}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Zombie"); + this.subtype.add("Beast"); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // When Baloth Null enters the battlefield, return up to two target creature cards from your graveyard to your hand. + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), false); + ability.addTarget(new TargetCardInYourGraveyard(0, 2, new FilterCreatureCard("creature cards from your graveyard"))); + this.addAbility(ability); + } + + public BalothNull(final BalothNull card) { + super(card); + } + + @Override + public BalothNull copy() { + return new BalothNull(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/BalothPup.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/BalothPup.java new file mode 100644 index 00000000000..431b5f080ce --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/BalothPup.java @@ -0,0 +1,72 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.counters.CounterType; + +/** + * + * @author LevelX2 + */ +public class BalothPup extends CardImpl { + + private final String rule = "{this} has trample as long as it has a +1/+1 counter on it"; + + public BalothPup(UUID ownerId) { + super(ownerId, 127, "Baloth Pup", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{G}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Beast"); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Baloth Pup has trample as long as it has a +1/+1 counter on it. + Effect effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(TrampleAbility.getInstance()), new SourceHasCounterCondition(CounterType.P1P1), rule); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public BalothPup(final BalothPup card) { + super(card); + } + + @Override + public BalothPup copy() { + return new BalothPup(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/BearerOfSilence.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/BearerOfSilence.java new file mode 100644 index 00000000000..a37603ddbbc --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/BearerOfSilence.java @@ -0,0 +1,82 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.CantBlockAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CastSourceTriggeredAbility; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.SacrificeEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterCreaturePermanent; +import mage.target.common.TargetOpponent; + +/** + * + * @author fireshoes + */ +public class BearerOfSilence extends CardImpl { + + public BearerOfSilence(UUID ownerId) { + super(ownerId, 67, "Bearer of Silence", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{B}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // When you cast Bearer of Silence, you may pay {1}{C}. If you do, target opponent sacrifices a creature. + Ability ability = new CastSourceTriggeredAbility(new DoIfCostPaid(new SacrificeEffect(new FilterCreaturePermanent(), 1, "Target opponent"), new ManaCostsImpl("{1}{C}"))); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Bearer of Silence can't block. + this.addAbility(new CantBlockAbility()); + } + + public BearerOfSilence(final BearerOfSilence card) { + super(card); + } + + @Override + public BearerOfSilence copy() { + return new BearerOfSilence(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/BirthingHulk.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/BirthingHulk.java new file mode 100644 index 00000000000..f8b7e9b461c --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/BirthingHulk.java @@ -0,0 +1,80 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.permanent.token.EldraziScionToken; + +/** + * + * @author LevelX2 + */ +public class BirthingHulk extends CardImpl { + + public BirthingHulk(UUID ownerId) { + super(ownerId, 121, "Birthing Hulk", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{6}{G}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.subtype.add("Drone"); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // When Birthing Hulk enters the battlefield, put two 1/1 colorless Eldrazi Scion creature tokens onto the battlefield. They have "Sacrifice this creature: Add {C} to your mana pool." + Effect effect = new CreateTokenEffect(new EldraziScionToken(), 2); + effect.setText("put two 1/1 colorless Eldrazi Scion creature tokens onto the battlefield. They have \"Sacrifice this creature: Add {C} to your mana pool.\""); + this.addAbility(new EntersBattlefieldTriggeredAbility(effect, false)); + + // {1}{C}: Regenerate Birthing Hulk. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{1}{C}"))); + + } + + public BirthingHulk(final BirthingHulk card) { + super(card); + } + + @Override + public BirthingHulk copy() { + return new BirthingHulk(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/BlindingDrone.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/BlindingDrone.java new file mode 100644 index 00000000000..6680f173072 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/BlindingDrone.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +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.common.TapTargetEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class BlindingDrone extends CardImpl { + + public BlindingDrone(UUID ownerId) { + super(ownerId, 41, "Blinding Drone", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{U}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.subtype.add("Drone"); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // {C}, {T}: Tap target creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), new ManaCostsImpl("{C}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public BlindingDrone(final BlindingDrone card) { + super(card); + } + + @Override + public BlindingDrone copy() { + return new BlindingDrone(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/BondsOfMortality.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/BondsOfMortality.java new file mode 100644 index 00000000000..0d0d32bf29d --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/BondsOfMortality.java @@ -0,0 +1,86 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.LoseAbilityAllEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; + +/** + * + * @author fireshoes + */ +public class BondsOfMortality extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponents control"); + + static { + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + } + + public BondsOfMortality(UUID ownerId) { + super(ownerId, 128, "Bonds of Mortality", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); + this.expansionSetCode = "OGW"; + + // When Bonds of Mortality enters the battlefield, draw a card. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1), false)); + + // {G}: Creatures your opponents control lose hexproof and indestructible until end of turn. + Effect effect = new LoseAbilityAllEffect(filter, HexproofAbility.getInstance(), Duration.EndOfTurn); + effect.setText("Creatures your opponents control lose hexproof"); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{G}")); + effect = new LoseAbilityAllEffect(filter, IndestructibleAbility.getInstance(), Duration.EndOfTurn); + effect.setText("and indestructible until end of turn"); + ability.addEffect(effect); + this.addAbility(ability); + } + + public BondsOfMortality(final BondsOfMortality card) { + super(card); + } + + @Override + public BondsOfMortality copy() { + return new BondsOfMortality(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/BoneSaw.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/BoneSaw.java new file mode 100644 index 00000000000..8300bc8c7c1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/BoneSaw.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; + +/** + * + * @author fireshoes + */ +public class BoneSaw extends mage.sets.conflux.BoneSaw { + + public BoneSaw(UUID ownerId) { + super(ownerId); + this.cardNumber = 161; + this.expansionSetCode = "OGW"; + } + + public BoneSaw(final BoneSaw card) { + super(card); + } + + @Override + public BoneSaw copy() { + return new BoneSaw(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/BoulderSalvo.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/BoulderSalvo.java new file mode 100644 index 00000000000..118392d3f83 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/BoulderSalvo.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.SurgeAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class BoulderSalvo extends CardImpl { + + public BoulderSalvo(UUID ownerId) { + super(ownerId, 102, "Boulder Salvo", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{4}{R}"); + this.expansionSetCode = "OGW"; + + // Boulder Salvo deals 4 damage to target creature. + this.getSpellAbility().addEffect(new DamageTargetEffect(4)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Surge {1}{R} + addAbility(new SurgeAbility(this, "{1}{R}")); + } + + public BoulderSalvo(final BoulderSalvo card) { + super(card); + } + + @Override + public BoulderSalvo copy() { + return new BoulderSalvo(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/BruteStrength.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/BruteStrength.java new file mode 100644 index 00000000000..bf6040559c9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/BruteStrength.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.Effect; +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.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class BruteStrength extends CardImpl { + + public BruteStrength(UUID ownerId) { + super(ownerId, 103, "Brute Strength", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{R}"); + this.expansionSetCode = "OGW"; + + // Target creature gets +3/+1 and gain trample until end of turn. + Effect effect = new BoostTargetEffect(3, 1, Duration.EndOfTurn); + effect.setText("Target creature gets +3/+1"); + 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().addTarget(new TargetCreaturePermanent()); + } + + public BruteStrength(final BruteStrength card) { + super(card); + } + + @Override + public BruteStrength copy() { + return new BruteStrength(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/CanopyGorger.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/CanopyGorger.java new file mode 100644 index 00000000000..daa82a67e71 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/CanopyGorger.java @@ -0,0 +1,58 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class CanopyGorger extends CardImpl { + + public CanopyGorger(UUID ownerId) { + super(ownerId, 129, "Canopy Gorger", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Wurm"); + this.power = new MageInt(6); + this.toughness = new MageInt(5); + } + + public CanopyGorger(final CanopyGorger card) { + super(card); + } + + @Override + public CanopyGorger copy() { + return new CanopyGorger(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/CaptainsClaws.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/CaptainsClaws.java new file mode 100644 index 00000000000..1f72a6e5946 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/CaptainsClaws.java @@ -0,0 +1,86 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.AttacksAttachedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.permanent.token.Token; + +/** + * + * @author LevelX2 + */ +public class CaptainsClaws extends CardImpl { + + public CaptainsClaws(UUID ownerId) { + super(ownerId, 162, "Captain's Claws", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{2}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Equipment"); + + // Equipped creature gets +1/+0. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(1, 0))); + // Whenever equipped creature attacks, put a 1/1 white Kor Ally creature token onto the battlefield tapped and attacking. + this.addAbility(new AttacksAttachedTriggeredAbility(new CreateTokenEffect(new KorAllyToken(), 1, true, true))); + // Equip {1} + this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(1))); + } + + public CaptainsClaws(final CaptainsClaws card) { + super(card); + } + + @Override + public CaptainsClaws copy() { + return new CaptainsClaws(this); + } +} + +class KorAllyToken extends Token { + + public KorAllyToken() { + super("Kor Ally", "1/1 white Kor Ally creature token"); + this.setExpansionSetCodeForImage("BFZ"); + cardType.add(CardType.CREATURE); + subtype.add("Kor"); + subtype.add("Ally"); + color.setWhite(true); + power = new MageInt(1); + toughness = new MageInt(1); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/ChandraFlamecaller.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/ChandraFlamecaller.java index 3e48358942b..2742f5deac9 100644 --- a/Mage.Sets/src/mage/sets/oathofthegatewatch/ChandraFlamecaller.java +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/ChandraFlamecaller.java @@ -135,6 +135,8 @@ class ChandraElementalElementalToken extends Token { public ChandraElementalElementalToken() { super("Elemental", "3/1 red Elemental creature tokens with haste"); + setTokenType(1); + setOriginalExpansionSetCode("OGW"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add("Elemental"); diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/ChitinousCloak.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/ChitinousCloak.java new file mode 100644 index 00000000000..52c059fec7f --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/ChitinousCloak.java @@ -0,0 +1,75 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +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; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LevelX2 + */ +public class ChitinousCloak extends CardImpl { + + public ChitinousCloak(UUID ownerId) { + super(ownerId, 163, "Chitinous Cloak", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT}, "{3}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Equipment"); + + // Equipped creature gets +2/+2 and has menace. + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(2, 2)); + Effect effect = new GainAbilityAttachedEffect(new MenaceAbility(), AttachmentType.EQUIPMENT); + effect.setText("and has menace"); + ability.addEffect(effect); + this.addAbility(ability); + // Equip {3} + this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(3))); + } + + public ChitinousCloak(final ChitinousCloak card) { + super(card); + } + + @Override + public ChitinousCloak copy() { + return new ChitinousCloak(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/AshenMoor.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/CinderBarrens.java similarity index 86% rename from Mage.Sets/src/mage/sets/oathofthegatewatch/AshenMoor.java rename to Mage.Sets/src/mage/sets/oathofthegatewatch/CinderBarrens.java index 4b4a1c39c5a..712d669a493 100644 --- a/Mage.Sets/src/mage/sets/oathofthegatewatch/AshenMoor.java +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/CinderBarrens.java @@ -39,13 +39,13 @@ import mage.constants.Rarity; * * @author fireshoes */ -public class AshenMoor extends CardImpl { +public class CinderBarrens extends CardImpl { - public AshenMoor(UUID ownerId) { - super(ownerId, 168, "Ashen Moor", Rarity.UNCOMMON, new CardType[]{CardType.LAND}, ""); + public CinderBarrens(UUID ownerId) { + super(ownerId, 168, "Cinder Barrens", Rarity.UNCOMMON, new CardType[]{CardType.LAND}, ""); this.expansionSetCode = "OGW"; - // Ashen Moor enters the battlefield tapped. + // Cinder Barrens enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); // {T}: Add {B} or {R} to your mana pool. @@ -53,12 +53,12 @@ public class AshenMoor extends CardImpl { this.addAbility(new RedManaAbility()); } - public AshenMoor(final AshenMoor card) { + public CinderBarrens(final CinderBarrens card) { super(card); } @Override - public AshenMoor copy() { - return new AshenMoor(this); + public CinderBarrens copy() { + return new CinderBarrens(this); } } diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/CinderHellion.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/CinderHellion.java new file mode 100644 index 00000000000..83070c65b6a --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/CinderHellion.java @@ -0,0 +1,71 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.common.TargetOpponent; + +/** + * + * @author fireshoes + */ +public class CinderHellion extends CardImpl { + + public CinderHellion(UUID ownerId) { + super(ownerId, 105, "Cinder Hellion", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{R}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Hellion"); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When Cinder Hellion enters the battlefield, it deals 2 damage to target opponent. + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2), false); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + public CinderHellion(final CinderHellion card) { + super(card); + } + + @Override + public CinderHellion copy() { + return new CinderHellion(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/CliffhavenVampire.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/CliffhavenVampire.java new file mode 100644 index 00000000000..0d736073577 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/CliffhavenVampire.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.GainLifeControllerTriggeredAbility; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class CliffhavenVampire extends CardImpl { + + public CliffhavenVampire(UUID ownerId) { + super(ownerId, 153, "Cliffhaven Vampire", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{W}{B}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Vampire"); + this.subtype.add("Warrior"); + this.subtype.add("Ally"); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever you gain life, each opponent loses 1 life. + this.addAbility(new GainLifeControllerTriggeredAbility(new LoseLifeOpponentsEffect(1), false)); + } + + public CliffhavenVampire(final CliffhavenVampire card) { + super(card); + } + + @Override + public CliffhavenVampire copy() { + return new CliffhavenVampire(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/ComparativeAnalysis.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/ComparativeAnalysis.java index 4fdb1cccab9..1f2106a70d9 100644 --- a/Mage.Sets/src/mage/sets/oathofthegatewatch/ComparativeAnalysis.java +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/ComparativeAnalysis.java @@ -48,10 +48,10 @@ public class ComparativeAnalysis extends CardImpl { // Target player draws two cards. this.getSpellAbility().addEffect(new DrawCardTargetEffect(2)); this.getSpellAbility().addTarget(new TargetPlayer()); - - // Has to be placed last here, because added spellAbility objects (e.g. effects) have to be copied from this + // Surge {2}{U} - addAbility(new SurgeAbility(this, "{2}{U}")); } + addAbility(new SurgeAbility(this, "{2}{U}")); + } public ComparativeAnalysis(final ComparativeAnalysis card) { super(card); diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/ConsumingSinkhole.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/ConsumingSinkhole.java new file mode 100644 index 00000000000..5641f939394 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/ConsumingSinkhole.java @@ -0,0 +1,84 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Mode; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.target.TargetPlayer; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class ConsumingSinkhole extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("land creature"); + + static { + filter.add(new CardTypePredicate(CardType.LAND)); + } + + public ConsumingSinkhole(UUID ownerId) { + super(ownerId, 94, "Consuming Sinkhole", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{3}{R}"); + this.expansionSetCode = "OGW"; + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // Choose one — Exile target land creature. + Effect effect = new ExileTargetEffect(); + effect.setText("Exile target land creature"); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + + // Consuming Sinkhole deals 4 damage to target player. + Mode mode = new Mode(); + mode.getEffects().add(new DamageTargetEffect(4)); + mode.getTargets().add(new TargetPlayer()); + this.getSpellAbility().addMode(mode); + } + + public ConsumingSinkhole(final ConsumingSinkhole card) { + super(card); + } + + @Override + public ConsumingSinkhole copy() { + return new ConsumingSinkhole(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/ContainmentMembrane.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/ContainmentMembrane.java new file mode 100644 index 00000000000..d11e1c1ff9d --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/ContainmentMembrane.java @@ -0,0 +1,78 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DontUntapInControllersUntapStepEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.SurgeAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class ContainmentMembrane extends CardImpl { + + public ContainmentMembrane(UUID ownerId) { + super(ownerId, 52, "Containment Membrane", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature doesn't untap during its controller's untap step. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DontUntapInControllersUntapStepEnchantedEffect())); + + // Surge {U} (You may cast a spell for its surge cost if you or a teammate have cast another spell in the same turn.) + addAbility(new SurgeAbility(this, "{U}")); + } + + public ContainmentMembrane(final ContainmentMembrane card) { + super(card); + } + + @Override + public ContainmentMembrane copy() { + return new ContainmentMembrane(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/CorpseChurn.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/CorpseChurn.java new file mode 100644 index 00000000000..ffa9be6217b --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/CorpseChurn.java @@ -0,0 +1,104 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreatureCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author LevelX2 + */ +public class CorpseChurn extends CardImpl { + + public CorpseChurn(UUID ownerId) { + super(ownerId, 83, "Corpse Churn", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{B}"); + this.expansionSetCode = "OGW"; + + // Put the top three cards of your library into your graveyard, then you may return a creature card from your graveyard to your hand. + getSpellAbility().addEffect(new PutTopCardOfLibraryIntoGraveControllerEffect(3)); + getSpellAbility().addEffect(new CorpseChurnEffect()); + } + + public CorpseChurn(final CorpseChurn card) { + super(card); + } + + @Override + public CorpseChurn copy() { + return new CorpseChurn(this); + } +} + +class CorpseChurnEffect extends OneShotEffect { + + public CorpseChurnEffect() { + super(Outcome.ReturnToHand); + this.staticText = ", then you may return a creature card from your graveyard to your hand"; + } + + public CorpseChurnEffect(final CorpseChurnEffect effect) { + super(effect); + } + + @Override + public CorpseChurnEffect copy() { + return new CorpseChurnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard")); + target.setNotTarget(true); + if (target.canChoose(source.getSourceId(), source.getControllerId(), game) + && controller.chooseUse(outcome, "Return a creature card from your graveyard to hand?", source, game) + && controller.choose(Outcome.ReturnToHand, target, source.getSourceId(), game)) { + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + controller.moveCards(card, Zone.HAND, source, game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/BlightedCrossroads.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/CorruptedCrossroads.java similarity index 86% rename from Mage.Sets/src/mage/sets/oathofthegatewatch/BlightedCrossroads.java rename to Mage.Sets/src/mage/sets/oathofthegatewatch/CorruptedCrossroads.java index 7dde87a5ddc..0125cf2cf1c 100644 --- a/Mage.Sets/src/mage/sets/oathofthegatewatch/BlightedCrossroads.java +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/CorruptedCrossroads.java @@ -47,28 +47,28 @@ import mage.game.Game; * * @author fireshoes */ -public class BlightedCrossroads extends CardImpl { +public class CorruptedCrossroads extends CardImpl { - public BlightedCrossroads(UUID ownerId) { - super(ownerId, 169, "Blighted Crossroads", Rarity.RARE, new CardType[]{CardType.LAND}, ""); + public CorruptedCrossroads(UUID ownerId) { + super(ownerId, 169, "Corrupted Crossroads", Rarity.RARE, new CardType[]{CardType.LAND}, ""); this.expansionSetCode = "OGW"; // {T}: Add {C} to your mana pool. this.addAbility(new ColorlessManaAbility()); - // {T}, Pay 1 life: Add one mana of any color to your mana pool. Spend this mana only to cast spells with devoid. + // {T}, Pay 1 life: Add one mana of any color to your mana pool. Spend this mana only to cast a spell with devoid. Ability ability = new ConditionalAnyColorManaAbility(1, new BlightedCrossroadsManaBuilder()); ability.addCost(new PayLifeCost(1)); this.addAbility(ability); } - public BlightedCrossroads(final BlightedCrossroads card) { + public CorruptedCrossroads(final CorruptedCrossroads card) { super(card); } @Override - public BlightedCrossroads copy() { - return new BlightedCrossroads(this); + public CorruptedCrossroads copy() { + return new CorruptedCrossroads(this); } } @@ -80,7 +80,7 @@ class BlightedCrossroadsManaBuilder extends ConditionalManaBuilder { @Override public String getRule() { - return "Spend this mana only to cast spells with devoid"; + return "Spend this mana only to cast a spell with devoid"; } } @@ -88,7 +88,7 @@ class BlightedCrossroadsConditionalMana extends ConditionalMana { public BlightedCrossroadsConditionalMana(Mana mana) { super(mana); - staticText = "Spend this mana only to cast spells with devoid"; + staticText = "Spend this mana only to cast a spell with devoid"; addCondition(new BlightedCrossroadsManaCondition()); } } diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/CrushOfTentacles.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/CrushOfTentacles.java index 4db3a1354da..9b07d459c89 100644 --- a/Mage.Sets/src/mage/sets/oathofthegatewatch/CrushOfTentacles.java +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/CrushOfTentacles.java @@ -1,86 +1,85 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ -package mage.sets.oathofthegatewatch; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.condition.common.SurgedCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.ReturnToHandFromBattlefieldAllEffect; -import mage.abilities.keyword.SurgeAbility; -import mage.cards.CardImpl; -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.filter.common.FilterNonlandPermanent; -import mage.game.permanent.token.Token; - -/** - * - * @author LevelX2 - */ -public class CrushOfTentacles extends CardImpl { - - public CrushOfTentacles(UUID ownerId) { - super(ownerId, 53, "Crush of Tentacles", Rarity.MYTHIC, new CardType[]{CardType.SORCERY}, "{4}{U}{U}"); - this.expansionSetCode = "OGW"; - - // Return all nonland permanents to their owners' hands. If Crush of Tentacles surge cost was paid, put an 8/8 blue Octopus creature token onto the battlefield. - getSpellAbility().addEffect(new ReturnToHandFromBattlefieldAllEffect(new FilterNonlandPermanent("nonland permanents"))); - Effect effect = new ConditionalOneShotEffect(new CreateTokenEffect(new CrushOfTentaclesToken()), SurgedCondition.getInstance()); - effect.setText("If {this} surge cost was paid, put an 8/8 blue Octopus creature token onto the battlefield"); - getSpellAbility().addEffect(effect); - - // Has to be placed last here, because added spellAbility objects (e.g. effects) have to be copied from this - // Surge {3}{U}{U} (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn) - addAbility(new SurgeAbility(this, "{3}{U}{U}")); - - } - - public CrushOfTentacles(final CrushOfTentacles card) { - super(card); - } - - @Override - public CrushOfTentacles copy() { - return new CrushOfTentacles(this); - } -} - -class CrushOfTentaclesToken extends Token { - - public CrushOfTentaclesToken() { - super("Octopus", "8/8 blue Octopus creature"); - this.cardType.add(CardType.CREATURE); - this.color.setBlue(true); - this.subtype.add("Octopus"); - this.power = new MageInt(8); - this.toughness = new MageInt(8); - } -} +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.condition.common.SurgedCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ReturnToHandFromBattlefieldAllEffect; +import mage.abilities.keyword.SurgeAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterNonlandPermanent; +import mage.game.permanent.token.Token; + +/** + * + * @author LevelX2 + */ +public class CrushOfTentacles extends CardImpl { + + public CrushOfTentacles(UUID ownerId) { + super(ownerId, 53, "Crush of Tentacles", Rarity.MYTHIC, new CardType[]{CardType.SORCERY}, "{4}{U}{U}"); + this.expansionSetCode = "OGW"; + + // Return all nonland permanents to their owners' hands. If Crush of Tentacles surge cost was paid, put an 8/8 blue Octopus creature token onto the battlefield. + getSpellAbility().addEffect(new ReturnToHandFromBattlefieldAllEffect(new FilterNonlandPermanent("nonland permanents"))); + Effect effect = new ConditionalOneShotEffect(new CreateTokenEffect(new CrushOfTentaclesToken()), SurgedCondition.getInstance()); + effect.setText("If {this} surge cost was paid, put an 8/8 blue Octopus creature token onto the battlefield"); + getSpellAbility().addEffect(effect); + + // Surge {3}{U}{U} (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn) + addAbility(new SurgeAbility(this, "{3}{U}{U}")); + } + + public CrushOfTentacles(final CrushOfTentacles card) { + super(card); + } + + @Override + public CrushOfTentacles copy() { + return new CrushOfTentacles(this); + } +} + +class CrushOfTentaclesToken extends Token { + + public CrushOfTentaclesToken() { + super("Octopus", "8/8 blue Octopus creature"); + this.setExpansionSetCodeForImage("BFZ"); + this.cardType.add(CardType.CREATURE); + this.color.setBlue(true); + this.subtype.add("Octopus"); + this.power = new MageInt(8); + this.toughness = new MageInt(8); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/CultivatorDrone.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/CultivatorDrone.java new file mode 100644 index 00000000000..9b3bd755c93 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/CultivatorDrone.java @@ -0,0 +1,125 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.ConditionalMana; +import mage.MageInt; +import mage.MageObject; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.ActivatedAbility; +import mage.abilities.SpellAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.keyword.DevoidAbility; +import mage.abilities.mana.ConditionalColorlessManaAbility; +import mage.abilities.mana.builder.ConditionalManaBuilder; +import mage.abilities.mana.conditional.ManaCondition; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author LevelX2 + */ +public class CultivatorDrone extends CardImpl { + + public CultivatorDrone(UUID ownerId) { + super(ownerId, 42, "Cultivator Drone", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{U}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.subtype.add("Drone"); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + // {T}: Add {C} to your mana pool. Spend this mana only to cast a colorless spell, activate an ability of a colorless permanent, or pay a cost that contains {C}. + this.addAbility(new ConditionalColorlessManaAbility(new TapSourceCost(), 1, new CultivatorDroneManaBuilder())); + } + + public CultivatorDrone(final CultivatorDrone card) { + super(card); + } + + @Override + public CultivatorDrone copy() { + return new CultivatorDrone(this); + } +} + +class CultivatorDroneManaBuilder extends ConditionalManaBuilder { + + @Override + public ConditionalMana build(Object... options) { + return new CultivatorDroneConditionalMana(this.mana); + } + + @Override + public String getRule() { + return "Spend this mana only to cast a colorless spell, activate an ability of a colorless permanent, or pay a cost that contains {C}"; + } +} + +class CultivatorDroneConditionalMana extends ConditionalMana { + + public CultivatorDroneConditionalMana(Mana mana) { + super(mana); + staticText = "Spend this mana only to cast a colorless spell, activate an ability of a colorless permanent, or pay a cost that contains {C}"; + addCondition(new CultivatorDroneManaCondition()); + } +} + +class CultivatorDroneManaCondition extends ManaCondition implements Condition { + + @Override + public boolean apply(Game game, Ability source, UUID originalId, Cost costToPay) { + if (source instanceof SpellAbility) { + MageObject object = game.getObject(source.getSourceId()); + if (object != null && object.getColor(game).isColorless()) { + return true; + } + } + if (source instanceof ActivatedAbility) { + Permanent object = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (object != null && object.getColor(game).isColorless()) { + return true; + } + } + if (costToPay instanceof ManaCost) { + return ((ManaCost) costToPay).getText().contains("{C}"); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/CycloneSire.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/CycloneSire.java new file mode 100644 index 00000000000..6cdb946b322 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/CycloneSire.java @@ -0,0 +1,78 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.counters.CounterType; +import mage.filter.common.FilterControlledLandPermanent; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author LevelX2 + */ +public class CycloneSire extends CardImpl { + + public CycloneSire(UUID ownerId) { + super(ownerId, 54, "Cyclone Sire", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{4}{U}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Elemental"); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // When Cyclone Sire dies, you may put three +1/+1 counters on target land you control. If you do, that land becomes a 0/0 Elemental creature with haste that's still a land. + Ability ability = new DiesTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance(3)), true); + Effect effect = new BecomesCreatureTargetEffect(new WallOfResurgenceToken(), false, true, Duration.Custom); + effect.setText("If you do, that land becomes a 0/0 Elemental creature with haste that's still a land"); + ability.addEffect(effect); + ability.addTarget(new TargetControlledPermanent(new FilterControlledLandPermanent())); + this.addAbility(ability); + } + + public CycloneSire(final CycloneSire card) { + super(card); + } + + @Override + public CycloneSire copy() { + return new CycloneSire(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/DazzlingReflection.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/DazzlingReflection.java new file mode 100644 index 00000000000..9da87a137d9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/DazzlingReflection.java @@ -0,0 +1,136 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.PreventionEffectImpl; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +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.targetpointer.FixedTarget; + +/** + * + * @author LevelX2 + */ +public class DazzlingReflection extends CardImpl { + + public DazzlingReflection(UUID ownerId) { + super(ownerId, 17, "Dazzling Reflection", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{W}"); + this.expansionSetCode = "OGW"; + + // You gain life equal to target creature's power. The next time that creature would deal damage this turn, prevent that damage. + getSpellAbility().addEffect(new DazzlingReflectionEffect()); + getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public DazzlingReflection(final DazzlingReflection card) { + super(card); + } + + @Override + public DazzlingReflection copy() { + return new DazzlingReflection(this); + } +} + +class DazzlingReflectionEffect extends OneShotEffect { + + public DazzlingReflectionEffect() { + super(Outcome.Benefit); + this.staticText = "You gain life equal to target creature's power. The next time that creature would deal damage this turn, prevent that damage"; + } + + public DazzlingReflectionEffect(final DazzlingReflectionEffect effect) { + super(effect); + } + + @Override + public DazzlingReflectionEffect copy() { + return new DazzlingReflectionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Permanent targetCreature = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); + controller.gainLife(targetCreature.getPower().getValue(), game); + ContinuousEffect effect = new DazzlingReflectionPreventEffect(); + effect.setTargetPointer(new FixedTarget(targetCreature, game)); + game.addEffect(effect, source); + return true; + } + return false; + } +} + +class DazzlingReflectionPreventEffect extends PreventionEffectImpl { + + public DazzlingReflectionPreventEffect() { + super(Duration.EndOfTurn, Integer.MAX_VALUE, false, false); + staticText = "The next time that creature would deal damage this turn, prevent that damage"; + } + + public DazzlingReflectionPreventEffect(final DazzlingReflectionPreventEffect effect) { + super(effect); + } + + @Override + public DazzlingReflectionPreventEffect copy() { + return new DazzlingReflectionPreventEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + super.replaceEvent(event, source, game); + discard(); + return false; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (super.applies(event, source, game)) { + if (event.getSourceId().equals(getTargetPointer().getFirst(game, source))) { + return true; + } + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/DeceiverOfForm.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/DeceiverOfForm.java new file mode 100644 index 00000000000..6b1019e768e --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/DeceiverOfForm.java @@ -0,0 +1,192 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author LevelX2 + */ +public class DeceiverOfForm extends CardImpl { + + public DeceiverOfForm(UUID ownerId) { + super(ownerId, 1, "Deceiver of Form", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{6}{C}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.power = new MageInt(8); + this.toughness = new MageInt(8); + + // At the beginning of combat on your turn, 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.addAbility(new BeginningOfCombatTriggeredAbility(new DeceiverOfFormEffect(), TargetController.YOU, false)); + } + + public DeceiverOfForm(final DeceiverOfForm card) { + super(card); + } + + @Override + public DeceiverOfForm copy() { + return new DeceiverOfForm(this); + } +} + +class DeceiverOfFormEffect extends OneShotEffect { + + public 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"; + } + + public DeceiverOfFormEffect(final DeceiverOfFormEffect effect) { + super(effect); + } + + @Override + public DeceiverOfFormEffect copy() { + return new DeceiverOfFormEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller != null && sourceObject != null) { + Card card = controller.getLibrary().getFromTop(game); + if (card != null) { + Cards cards = new CardsImpl(card); + controller.revealCards(sourceObject.getIdName(), cards, game); + if (card.getCardType().contains(CardType.CREATURE)) { + if (controller.chooseUse(outcome, "Let creatures you control other than " + + sourceObject.getLogName() + " becomes copies of " + card.getLogName() + " until end of turn?", source, game)) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), controller.getId(), game)) { + if (!permanent.getId().equals(sourceObject.getId())) { + ContinuousEffect effect = new DeceiverOfFormCopyEffect(card); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + } + } + } + } + if (controller.chooseUse(outcome, "Move " + card.getLogName() + " to the bottom of your library?", source, game)) { + controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.LIBRARY, false, true); + } + } + return true; + } + return false; + } +} + +class DeceiverOfFormCopyEffect extends ContinuousEffectImpl { + + private final Card card; + + public DeceiverOfFormCopyEffect(Card card) { + super(Duration.EndOfTurn, Layer.CopyEffects_1, SubLayer.NA, Outcome.BecomeCreature); + this.card = card; + staticText = "becomes copies of that card until end of turn"; + } + + public DeceiverOfFormCopyEffect(final DeceiverOfFormCopyEffect effect) { + super(effect); + this.card = effect.card; + } + + @Override + public DeceiverOfFormCopyEffect copy() { + return new DeceiverOfFormCopyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (card == null || permanent == null) { + discard(); + return false; + } + permanent.setName(card.getName()); + permanent.getPower().setValue(card.getPower().getValue()); + permanent.getToughness().setValue(card.getToughness().getValue()); + permanent.getColor(game).setColor(card.getColor(game)); + permanent.getManaCost().clear(); + permanent.getManaCost().add(card.getManaCost()); + permanent.getCardType().clear(); + for (CardType type : card.getCardType()) { + if (!permanent.getCardType().contains(type)) { + permanent.getCardType().add(type); + } + } + permanent.getSubtype().clear(); + for (String type : card.getSubtype()) { + if (!permanent.getSubtype().contains(type)) { + permanent.getSubtype().add(type); + } + } + permanent.getSupertype().clear(); + for (String type : card.getSupertype()) { + if (!permanent.getSupertype().contains(type)) { + permanent.getSupertype().add(type); + } + } + permanent.removeAllAbilities(source.getSourceId(), game); + + for (Ability ability : card.getAbilities()) { + if (!permanent.getAbilities().contains(ability)) { + permanent.addAbility(ability, source.getSourceId(), game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/DevourInFlames.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/DevourInFlames.java new file mode 100644 index 00000000000..b067e1d79a0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/DevourInFlames.java @@ -0,0 +1,66 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.costs.common.ReturnToHandChosenControlledPermanentCost; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterControlledLandPermanent; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreatureOrPlaneswalker; + +/** + * + * @author fireshoes + */ +public class DevourInFlames extends CardImpl { + + public DevourInFlames(UUID ownerId) { + super(ownerId, 106, "Devour in Flames", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{2}{R}"); + this.expansionSetCode = "OGW"; + + // As an additional cost to cast Devour in Flames, return a land you control to its owner's hand. + this.getSpellAbility().addCost(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(new FilterControlledLandPermanent("land")))); + + // Devour in Flames deals 5 damage to target creature or planeswalker. + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + this.getSpellAbility().addEffect(new DamageTargetEffect(5)); + } + + public DevourInFlames(final DevourInFlames card) { + super(card); + } + + @Override + public DevourInFlames copy() { + return new DevourInFlames(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/DimensionalInfiltrator.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/DimensionalInfiltrator.java new file mode 100644 index 00000000000..f43d4d8d562 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/DimensionalInfiltrator.java @@ -0,0 +1,127 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetOpponent; + +/** + * + * @author fireshoes + */ +public class DimensionalInfiltrator extends CardImpl { + + public DimensionalInfiltrator(UUID ownerId) { + super(ownerId, 44, "Dimensional Infiltrator", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{U}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {1}{C}: Exile the top card of target opponent's library. If it's a land card, you may return Dimensional Infiltrator to its owner's hand. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DimensionalInfiltratorEffect(), new ManaCostsImpl("{1}{C}")); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + public DimensionalInfiltrator(final DimensionalInfiltrator card) { + super(card); + } + + @Override + public DimensionalInfiltrator copy() { + return new DimensionalInfiltrator(this); + } +} + +class DimensionalInfiltratorEffect extends OneShotEffect { + + public DimensionalInfiltratorEffect() { + super(Outcome.PutCreatureInPlay); + this.staticText = "Exile the top card of target opponent's library. If it's a land card, you may return Dimensional Infiltrator to its owner's hand"; + } + + public DimensionalInfiltratorEffect(final DimensionalInfiltratorEffect effect) { + super(effect); + } + + @Override + public DimensionalInfiltratorEffect copy() { + return new DimensionalInfiltratorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(source.getFirstTarget()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (opponent == null || controller == null || sourceObject == null) { + return false; + } + + if (opponent.getLibrary().size() > 0) { + Card card = opponent.getLibrary().getFromTop(game); + if (card != null) { + card.moveToExile(null, "Dimensional Infiltrator", source.getSourceId(), game); + if (card.getCardType().contains(CardType.LAND)) { + if (controller.chooseUse(Outcome.Neutral, "Return " + sourceObject.getIdName() + " to its owner's hand?", source, game)) { + new ReturnToHandSourceEffect(true).apply(game, source); + } + } + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/DranasChosen.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/DranasChosen.java new file mode 100644 index 00000000000..151e31cf7e8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/DranasChosen.java @@ -0,0 +1,86 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +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.common.TapTargetCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.permanent.token.ZombieToken; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author fireshoes + */ +public class DranasChosen extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("an untapped Ally you control"); + + static { + filter.add(new SubtypePredicate("Ally")); + filter.add(Predicates.not(new TappedPredicate())); + } + + public DranasChosen(UUID ownerId) { + super(ownerId, 84, "Drana's Chosen", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Vampire"); + this.subtype.add("Shaman"); + this.subtype.add("Ally"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Cohort — {T}, Tap an untapped Ally you control: Put a 2/2 black Zombie creature token onto the battlefield tapped. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new ZombieToken(), 1, true, false), new TapSourceCost()); + ability.addCost(new TapTargetCost(new TargetControlledPermanent(filter))); + ability.setAbilityWord(AbilityWord.COHORT); + this.addAbility(ability); + } + + public DranasChosen(final DranasChosen card) { + super(card); + } + + @Override + public DranasChosen copy() { + return new DranasChosen(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/EldraziAggressor.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/EldraziAggressor.java new file mode 100644 index 00000000000..d7ec8064847 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/EldraziAggressor.java @@ -0,0 +1,85 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.ColorlessPredicate; +import mage.filter.predicate.permanent.AnotherPredicate; + +/** + * + * @author fireshoes + */ +public class EldraziAggressor extends CardImpl { + + private final String rule = "{this} has haste as long as you control another colorless creature"; + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another colorless creature"); + + static { + filter.add(new AnotherPredicate()); + filter.add(new ColorlessPredicate()); + } + + public EldraziAggressor(UUID ownerId) { + super(ownerId, 95, "Eldrazi Aggressor", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{R}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.subtype.add("Drone"); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // Eldrazi Aggressor has haste as long as you control another colorless creature. + Effect effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(HasteAbility.getInstance()), new PermanentsOnTheBattlefieldCondition(filter), rule); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public EldraziAggressor(final EldraziAggressor card) { + super(card); + } + + @Override + public EldraziAggressor copy() { + return new EldraziAggressor(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/EldraziDisplacer.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/EldraziDisplacer.java new file mode 100644 index 00000000000..4b5a12c0350 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/EldraziDisplacer.java @@ -0,0 +1,88 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +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.effects.Effect; +import mage.abilities.effects.common.ExileTargetForSourceEffect; +import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class EldraziDisplacer extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); + + static { + filter.add(new AnotherPredicate()); + } + + public EldraziDisplacer(UUID ownerId) { + super(ownerId, 13, "Eldrazi Displacer", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{W}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // {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"); + ability.addEffect(effect); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public EldraziDisplacer(final EldraziDisplacer card) { + super(card); + } + + @Override + public EldraziDisplacer copy() { + return new EldraziDisplacer(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/ForcedWillEldrazi.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/EldraziObligator.java similarity index 86% rename from Mage.Sets/src/mage/sets/oathofthegatewatch/ForcedWillEldrazi.java rename to Mage.Sets/src/mage/sets/oathofthegatewatch/EldraziObligator.java index bd9d3d5c5dd..cba250db109 100644 --- a/Mage.Sets/src/mage/sets/oathofthegatewatch/ForcedWillEldrazi.java +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/EldraziObligator.java @@ -51,10 +51,10 @@ import mage.target.common.TargetCreaturePermanent; * * @author fireshoes */ -public class ForcedWillEldrazi extends CardImpl { +public class EldraziObligator extends CardImpl { - public ForcedWillEldrazi(UUID ownerId) { - super(ownerId, 96, "Forced-Will Eldrazi", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{R}"); + public EldraziObligator(UUID ownerId) { + super(ownerId, 96, "Eldrazi Obligator", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{R}"); this.expansionSetCode = "OGW"; this.subtype.add("Eldrazi"); this.subtype.add("Drone"); @@ -63,11 +63,11 @@ public class ForcedWillEldrazi extends CardImpl { // Devoid this.addAbility(new DevoidAbility(this.color)); - + // Haste this.addAbility(HasteAbility.getInstance()); - - // When you cast Forced-Will Eldrazi, 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. + + // 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(new DoIfCostPaid(new GainControlTargetEffect(Duration.EndOfTurn), new ManaCostsImpl("{1}{C}"))); Effect effect = new UntapTargetEffect(); effect.setText("Untap that creature"); @@ -80,12 +80,12 @@ public class ForcedWillEldrazi extends CardImpl { this.addAbility(ability); } - public ForcedWillEldrazi(final ForcedWillEldrazi card) { + public EldraziObligator(final EldraziObligator card) { super(card); } @Override - public ForcedWillEldrazi copy() { - return new ForcedWillEldrazi(this); + public EldraziObligator copy() { + return new EldraziObligator(this); } } diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/ElementalUprising.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/ElementalUprising.java new file mode 100644 index 00000000000..e88a00360e6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/ElementalUprising.java @@ -0,0 +1,92 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.combat.MustBeBlockedByAtLeastOneTargetEffect; +import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.permanent.token.Token; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author LevelX2 + */ +public class ElementalUprising extends CardImpl { + + private static final FilterLandPermanent filter = new FilterLandPermanent("land you control"); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + public ElementalUprising(UUID ownerId) { + super(ownerId, 130, "Elemental Uprising", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{G}"); + this.expansionSetCode = "OGW"; + + // Target land you control becomes a 4/4 Elemental creature with haste until end of turn. It's still a land. It must be blocked this turn if able. + getSpellAbility().addEffect(new BecomesCreatureTargetEffect(new ElementalUprisingToken(), false, true, Duration.EndOfTurn)); + getSpellAbility().addTarget(new TargetLandPermanent(filter)); + Effect effect = new MustBeBlockedByAtLeastOneTargetEffect(Duration.EndOfTurn); + effect.setText("It must be blocked this turn if able"); + getSpellAbility().addEffect(effect); + } + + public ElementalUprising(final ElementalUprising card) { + super(card); + } + + @Override + public ElementalUprising copy() { + return new ElementalUprising(this); + } +} + +class ElementalUprisingToken extends Token { + + public ElementalUprisingToken() { + super("", "4/4 Elemental creature with haste"); + this.cardType.add(CardType.CREATURE); + + this.subtype.add("Elemental"); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + this.addAbility(HasteAbility.getInstance()); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/EmbodimentOfInsight.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/EmbodimentOfInsight.java new file mode 100644 index 00000000000..f4f477a1924 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/EmbodimentOfInsight.java @@ -0,0 +1,109 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.LandfallAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.permanent.token.Token; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author fireshoes + */ +public class EmbodimentOfInsight extends CardImpl { + + private static final FilterPermanent filterLandCreatures = new FilterPermanent("Land creatures"); + private static final FilterLandPermanent filterLand = new FilterLandPermanent("land you control"); + + static { + filterLandCreatures.add(new CardTypePredicate(CardType.LAND)); + filterLandCreatures.add(new CardTypePredicate(CardType.CREATURE)); + filterLand.add(new ControllerPredicate(TargetController.YOU)); + + } + + public EmbodimentOfInsight(UUID ownerId) { + super(ownerId, 131, "Embodiment of Insight", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{4}{G}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Elemental"); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Land creatures you control have vigilance. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, filterLandCreatures))); + + // Landfall - Whenever a land enters the battlefield under you control, you may have target land you control + // become a 3/3 Elemental creature with haste until end of turn. It's still a land. + Ability ability = new LandfallAbility(new BecomesCreatureTargetEffect(new EmbodimentOfInsightToken(), false, true, Duration.EndOfTurn), true); + ability.addTarget(new TargetLandPermanent(filterLand)); + this.addAbility(ability); + } + + public EmbodimentOfInsight(final EmbodimentOfInsight card) { + super(card); + } + + @Override + public EmbodimentOfInsight copy() { + return new EmbodimentOfInsight(this); + } +} + +class EmbodimentOfInsightToken extends Token { + + public EmbodimentOfInsightToken() { + super("", "3/3 Elemental creature with haste"); + this.cardType.add(CardType.CREATURE); + + this.subtype.add("Elemental"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + this.addAbility(HasteAbility.getInstance()); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/EssenceDepleter.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/EssenceDepleter.java new file mode 100644 index 00000000000..906ff1fc0ef --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/EssenceDepleter.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +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.effects.Effect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.common.TargetOpponent; + +/** + * + * @author LevelX2 + */ +public class EssenceDepleter extends CardImpl { + + public EssenceDepleter(UUID ownerId) { + super(ownerId, 69, "Essence Depleter", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // {1}{C}: Target opponent loses 1 life and you gain 1 life. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseLifeTargetEffect(1), new ManaCostsImpl("{1}{C}")); + Effect effect = new GainLifeEffect(1); + effect.setText("and you gain 1 life"); + ability.addEffect(effect); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + + } + + public EssenceDepleter(final EssenceDepleter card) { + super(card); + } + + @Override + public EssenceDepleter copy() { + return new EssenceDepleter(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/Expedite.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/Expedite.java new file mode 100644 index 00000000000..d84d70abc3f --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/Expedite.java @@ -0,0 +1,66 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class Expedite extends CardImpl { + + public Expedite(UUID ownerId) { + super(ownerId, 108, "Expedite", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{R}"); + this.expansionSetCode = "OGW"; + + // Target creature gains haste until end of turn. + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + } + + public Expedite(final Expedite card) { + super(card); + } + + @Override + public Expedite copy() { + return new Expedite(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/ExpeditionRaptor.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/ExpeditionRaptor.java new file mode 100644 index 00000000000..6da274e140a --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/ExpeditionRaptor.java @@ -0,0 +1,66 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.SupportAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class ExpeditionRaptor extends CardImpl { + + public ExpeditionRaptor(UUID ownerId) { + super(ownerId, 18, "Expedition Raptor", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Bird"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Expedition Raptor enters the battlefield, support 2. + this.addAbility(new SupportAbility(this, 2)); + } + + public ExpeditionRaptor(final ExpeditionRaptor card) { + super(card); + } + + @Override + public ExpeditionRaptor copy() { + return new ExpeditionRaptor(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/FallOfTheTitans.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/FallOfTheTitans.java new file mode 100644 index 00000000000..73a37808e60 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/FallOfTheTitans.java @@ -0,0 +1,65 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.SurgeAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author fireshoes + */ +public class FallOfTheTitans extends CardImpl { + + public FallOfTheTitans(UUID ownerId) { + super(ownerId, 109, "Fall of the Titans", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{X}{X}{R}"); + this.expansionSetCode = "OGW"; + + // Fall of the Titans deals X damage to each of up to two target creatures and/or players. + this.getSpellAbility().addTarget(new TargetCreatureOrPlayer(0, 2)); + this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); + + // Surge {X}{R} + addAbility(new SurgeAbility(this, "{X}{R}")); + } + + public FallOfTheTitans(final FallOfTheTitans card) { + super(card); + } + + @Override + public FallOfTheTitans copy() { + return new FallOfTheTitans(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/FlayingTendrils.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/FlayingTendrils.java new file mode 100644 index 00000000000..58bdcc25174 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/FlayingTendrils.java @@ -0,0 +1,113 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +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.players.Player; + +/** + * + * @author LevelX2 + */ +public class FlayingTendrils extends CardImpl { + + public FlayingTendrils(UUID ownerId) { + super(ownerId, 70, "Flaying Tendrils", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{1}{B}{B}"); + this.expansionSetCode = "OGW"; + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + // All creatures get -2/-2 until end of turn. If a creature would die this turn, exile it instead. + this.getSpellAbility().addEffect(new BoostAllEffect(-2, -2, Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new FlayingTendrilsReplacementEffect()); + } + + public FlayingTendrils(final FlayingTendrils card) { + super(card); + } + + @Override + public FlayingTendrils copy() { + return new FlayingTendrils(this); + } +} + +class FlayingTendrilsReplacementEffect extends ReplacementEffectImpl { + + public FlayingTendrilsReplacementEffect() { + super(Duration.EndOfTurn, Outcome.Exile); + staticText = "If a creature would die this turn, exile it instead"; + } + + public FlayingTendrilsReplacementEffect(final FlayingTendrilsReplacementEffect effect) { + super(effect); + } + + @Override + public FlayingTendrilsReplacementEffect copy() { + return new FlayingTendrilsReplacementEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent permanent = ((ZoneChangeEvent) event).getTarget(); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null && permanent != null) { + return controller.moveCards((Card) permanent, Zone.EXILED, source, game); + } + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.ZONE_CHANGE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + ZoneChangeEvent zce = (ZoneChangeEvent) event; + return zce.isDiesEvent() && zce.getTarget().getCardType().contains(CardType.CREATURE); + } + +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/GeneralTazri.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/GeneralTazri.java new file mode 100644 index 00000000000..688f6296b41 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/GeneralTazri.java @@ -0,0 +1,142 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreatureCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author LevelX2 + */ +public class GeneralTazri extends CardImpl { + + private static final FilterCreatureCard filter = new FilterCreatureCard("an Ally creature card"); + + static { + filter.add(new SubtypePredicate("Ally")); + } + + public GeneralTazri(UUID ownerId) { + super(ownerId, 19, "General Tazri", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{4}{W}"); + this.expansionSetCode = "OGW"; + this.supertype.add("Legendary"); + this.subtype.add("Human"); + this.subtype.add("Ally"); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // When General Tazri enters the battlefield, you may search your library for an Ally creature card, reveal it, put it into your hand, then shuffle your library. + this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInHandEffect( + new TargetCardInLibrary(filter), true, true), true)); + // {W}{U}{B}{R}{G}: Ally creatures you control get +X/+X until end of turn, where X is the number of colors among those creatures. + DynamicValue xValue = new GeneralTazriColorCount(); + this.addAbility(new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new BoostControlledEffect(xValue, xValue, Duration.EndOfTurn, new FilterCreaturePermanent("Ally", "Ally creatures"), false), + new ManaCostsImpl("{W}{U}{B}{R}{G}"))); + + } + + public GeneralTazri(final GeneralTazri card) { + super(card); + } + + @Override + public GeneralTazri copy() { + return new GeneralTazri(this); + } +} + +class GeneralTazriColorCount implements DynamicValue { + + private final static FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(new SubtypePredicate(("Ally"))); + } + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + int count = 0; + boolean black = false; + boolean red = false; + boolean white = false; + boolean green = false; + boolean blue = false; + for (Permanent creature : game.getBattlefield().getAllActivePermanents(filter, sourceAbility.getControllerId(), game)) { + ObjectColor color = creature.getColor(game); + black |= color.isBlack(); + red |= color.isRed(); + white |= color.isWhite(); + green |= color.isGreen(); + blue |= color.isBlue(); + } + count += black ? 1 : 0; + count += red ? 1 : 0; + count += white ? 1 : 0; + count += green ? 1 : 0; + count += blue ? 1 : 0; + return count; + } + + @Override + public GeneralTazriColorCount copy() { + return new GeneralTazriColorCount(); + } + + @Override + public String getMessage() { + return "the number of colors among those creatures"; + } + + @Override + public String toString() { + return "X"; + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/GiftOfTusks.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/GiftOfTusks.java new file mode 100644 index 00000000000..b85aa414117 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/GiftOfTusks.java @@ -0,0 +1,65 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.game.permanent.token.ElephantToken; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class GiftOfTusks extends CardImpl { + + public GiftOfTusks(UUID ownerId) { + super(ownerId, 55, "Gift of Tusks", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{U}"); + this.expansionSetCode = "OGW"; + + // Until end of turn, target creature loses all abilities and becomes a green Elephant with base power and toughness 3/3. + Effect effect = new BecomesCreatureTargetEffect(new ElephantToken(), true, false, Duration.EndOfTurn); + effect.setText("Until end of turn, target creature loses all abilities and becomes a green Elephant with base power and toughness 3/3"); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public GiftOfTusks(final GiftOfTusks card) { + super(card); + } + + @Override + public GiftOfTusks copy() { + return new GiftOfTusks(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/GoblinFreerunner.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/GoblinFreerunner.java new file mode 100644 index 00000000000..da19c3758dc --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/GoblinFreerunner.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.keyword.MenaceAbility; +import mage.abilities.keyword.SurgeAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class GoblinFreerunner extends CardImpl { + + public GoblinFreerunner(UUID ownerId) { + super(ownerId, 111, "Goblin Freerunner", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{R}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Goblin"); + this.subtype.add("Warrior"); + this.subtype.add("Ally"); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Surge {1}{R} (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn.) + addAbility(new SurgeAbility(this, "{1}{R}")); + + // Menace + this.addAbility(new MenaceAbility()); + } + + public GoblinFreerunner(final GoblinFreerunner card) { + super(card); + } + + @Override + public GoblinFreerunner copy() { + return new GoblinFreerunner(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/GraspOfDarkness.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/GraspOfDarkness.java new file mode 100644 index 00000000000..11191f35f90 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/GraspOfDarkness.java @@ -0,0 +1,54 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class GraspOfDarkness extends mage.sets.scarsofmirrodin.GraspOfDarkness { + + public GraspOfDarkness(UUID ownerId) { + super(ownerId); + this.cardNumber = 85; + this.expansionSetCode = "OGW"; + this.rarity = Rarity.UNCOMMON; + } + + public GraspOfDarkness(final GraspOfDarkness card) { + super(card); + } + + @Override + public GraspOfDarkness copy() { + return new GraspOfDarkness(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/GravityNegator.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/GravityNegator.java new file mode 100644 index 00000000000..54dc85d3e29 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/GravityNegator.java @@ -0,0 +1,88 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class GravityNegator extends CardImpl { + + private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); + + static { + filter.add(new AnotherPredicate()); + } + + public GravityNegator(UUID ownerId) { + super(ownerId, 45, "Gravity Negator", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{U}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.subtype.add("Drone"); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // 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(filter)); + this.addAbility(ability); + } + + public GravityNegator(final GravityNegator card) { + super(card); + } + + @Override + public GravityNegator copy() { + return new GravityNegator(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/GripOfTheRoil.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/GripOfTheRoil.java new file mode 100644 index 00000000000..5bcdc97f4fe --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/GripOfTheRoil.java @@ -0,0 +1,70 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.keyword.SurgeAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class GripOfTheRoil extends CardImpl { + + public GripOfTheRoil(UUID ownerId) { + super(ownerId, 56, "Grip of the Roil", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{2}{U}"); + this.expansionSetCode = "OGW"; + + // Tap target creature. It doesn't untap during its controller's next untap step. + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addEffect(new TapTargetEffect()); + this.getSpellAbility().addEffect(new DontUntapInControllersNextUntapStepTargetEffect()); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + + // Surge {1}{U} + addAbility(new SurgeAbility(this, "{1}{U}")); + } + + public GripOfTheRoil(final GripOfTheRoil card) { + super(card); + } + + @Override + public GripOfTheRoil copy() { + return new GripOfTheRoil(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/HarvesterTroll.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/HarvesterTroll.java new file mode 100644 index 00000000000..75f987c1fca --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/HarvesterTroll.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.counters.CounterType; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author LevelX2 + */ +public class HarvesterTroll extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("a creature or land"); + + static { + filter.add(Predicates.or(new CardTypePredicate(CardType.CREATURE), new CardTypePredicate(CardType.LAND))); + } + + public HarvesterTroll(UUID ownerId) { + super(ownerId, 133, "Harvester Troll", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{G}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Troll"); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // When Harvester Troll enters the battlefield, you may sacrifice a creature or land. If you do, put two +1/+1 counters on Harvester Troll. + EntersBattlefieldTriggeredAbility ability + = new EntersBattlefieldTriggeredAbility(new DoIfCostPaid(new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), + new SacrificeTargetCost(new TargetControlledPermanent(filter))), false); + this.addAbility(ability); + } + + public HarvesterTroll(final HarvesterTroll card) { + super(card); + } + + @Override + public HarvesterTroll copy() { + return new HarvesterTroll(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/HavocSower.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/HavocSower.java new file mode 100644 index 00000000000..1d21a768d59 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/HavocSower.java @@ -0,0 +1,70 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LevelX2 + */ +public class HavocSower extends CardImpl { + + public HavocSower(UUID ownerId) { + super(ownerId, 71, "Havoc Sower", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.subtype.add("Drone"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + // {1}{C}: Havoc Sower gets +2/+1 until end of turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(2, 1, Duration.EndOfTurn), new ManaCostsImpl("{1}{C}"))); + } + + public HavocSower(final HavocSower card) { + super(card); + } + + @Override + public HavocSower copy() { + return new HavocSower(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/HedronAlignment.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/HedronAlignment.java new file mode 100644 index 00000000000..94bdfcc1780 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/HedronAlignment.java @@ -0,0 +1,136 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.other.OwnerPredicate; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author LevelX2 + */ +public class HedronAlignment extends CardImpl { + + public HedronAlignment(UUID ownerId) { + super(ownerId, 57, "Hedron Alignment", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + this.expansionSetCode = "OGW"; + + // Hexproof + this.addAbility(HexproofAbility.getInstance()); + // At the beginning of your upkeep, you may reveal your hand. If you do, you win the game if you own a card named Hedron Alignment in exile, in your hand, in your graveyard, and on the battlefield. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new HedronAlignmentEffect(), TargetController.YOU, true)); + // {1}{U}: Scry 1. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ScryEffect(1), new ManaCostsImpl("{1}{U}"))); + } + + public HedronAlignment(final HedronAlignment card) { + super(card); + } + + @Override + public HedronAlignment copy() { + return new HedronAlignment(this); + } +} + +class HedronAlignmentEffect extends OneShotEffect { + + private final static FilterPermanent filterPermanent = new FilterPermanent(); + private final static FilterCard filterCard = new FilterCard(); + + static { + filterPermanent.add(new NamePredicate("Hedron Alignment")); + filterPermanent.add(new OwnerPredicate(TargetController.YOU)); + filterCard.add(new NamePredicate("Hedron Alignment")); + filterCard.add(new OwnerPredicate(TargetController.YOU)); + } + + public HedronAlignmentEffect() { + super(Outcome.Benefit); + this.staticText = "you may reveal your hand. If you do, you win the game if you own a card named Hedron Alignment in exile, in your hand, in your graveyard, and on the battlefield"; + } + + public HedronAlignmentEffect(final HedronAlignmentEffect effect) { + super(effect); + } + + @Override + public HedronAlignmentEffect copy() { + return new HedronAlignmentEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller != null && sourceObject != null) { + Cards cardsToReveal = new CardsImpl(); + controller.revealCards(sourceObject.getIdName(), cardsToReveal, game); + // Check battlefield + if (!game.getBattlefield().contains(filterPermanent, source.getControllerId(), game, 1)) { + return true; + } + if (controller.getHand().getCards(filterCard, source.getSourceId(), controller.getId(), game).isEmpty()) { + return true; + } + if (controller.getGraveyard().getCards(filterCard, source.getSourceId(), controller.getId(), game).isEmpty()) { + return true; + } + Cards cardsToCheck = new CardsImpl(); + cardsToCheck.addAll(game.getExile().getAllCards(game)); + if (cardsToCheck.count(filterCard, source.getSourceId(), controller.getId(), game) == 0) { + return true; + } + controller.won(game); + return true; + + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/HedronCrawler.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/HedronCrawler.java new file mode 100644 index 00000000000..363899e2b7d --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/HedronCrawler.java @@ -0,0 +1,62 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.mana.ColorlessManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class HedronCrawler extends CardImpl { + + public HedronCrawler(UUID ownerId) { + super(ownerId, 164, "Hedron Crawler", Rarity.COMMON, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Construct"); + this.power = new MageInt(0); + this.toughness = new MageInt(1); + + // {T}: Add {C} to your mana pool. + this.addAbility(new ColorlessManaAbility()); + } + + public HedronCrawler(final HedronCrawler card) { + super(card); + } + + @Override + public HedronCrawler copy() { + return new HedronCrawler(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/HissingQuagmire.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/HissingQuagmire.java new file mode 100644 index 00000000000..a3607df6147 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/HissingQuagmire.java @@ -0,0 +1,92 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.permanent.token.Token; + +/** + * + * @author fireshoes + */ +public class HissingQuagmire extends CardImpl { + + public HissingQuagmire(UUID ownerId) { + super(ownerId, 171, "Hissing Quagmire", Rarity.RARE, new CardType[]{CardType.LAND}, ""); + this.expansionSetCode = "OGW"; + + // Hissing Quagmire enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {B} or {G} to your mana pool. + this.addAbility(new BlackManaAbility()); + this.addAbility(new GreenManaAbility()); + + // {1}{B}{G}: Hissing Quagmire becomes a 2/2 black and green Elemental creature with deathtouch until end of turn. It's still a land. + Effect effect = new BecomesCreatureSourceEffect(new HissingQuagmireToken(), "land", Duration.EndOfTurn); + effect.setText("{this} becomes a 2/2 black and green Elemental creature with deathtouch until end of turn. It's still a land"); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{1}{B}{G}"))); + } + + public HissingQuagmire(final HissingQuagmire card) { + super(card); + } + + @Override + public HissingQuagmire copy() { + return new HissingQuagmire(this); + } +} + +class HissingQuagmireToken extends Token { + + public HissingQuagmireToken() { + super("", "2/2 black and green Elemental creature with deathtouch"); + cardType.add(CardType.CREATURE); + subtype.add("Elemental"); + color.setRed(true); + color.setWhite(true); + power = new MageInt(2); + toughness = new MageInt(2); + addAbility(DeathtouchAbility.getInstance()); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/ImmobilizerEldrazi.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/ImmobilizerEldrazi.java new file mode 100644 index 00000000000..b07a1b4475b --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/ImmobilizerEldrazi.java @@ -0,0 +1,98 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.combat.CantBlockAllEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicate; +import mage.game.Game; + +/** + * + * @author LevelX2 + */ +public class ImmobilizerEldrazi extends CardImpl { + + private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("Each creature with toughness greater than its power"); + + static { + filter.add(new ImmobilizerEldraziPredicate()); + } + + public ImmobilizerEldrazi(UUID ownerId) { + super(ownerId, 97, "Immobilizer Eldrazi", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{R}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.subtype.add("Drone"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // {2}{C}: Each creature with toughness greater than its power can't block this turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CantBlockAllEffect(filter, Duration.EndOfTurn), new ManaCostsImpl("{2}{C}")); + + this.addAbility(ability); + + } + + public ImmobilizerEldrazi(final ImmobilizerEldrazi card) { + super(card); + } + + @Override + public ImmobilizerEldrazi copy() { + return new ImmobilizerEldrazi(this); + } +} + +class ImmobilizerEldraziPredicate implements Predicate { + + @Override + public boolean apply(MageObject input, Game game) { + return input.getToughness().getValue() > input.getPower().getValue(); + } + + @Override + public String toString() { + return "toughness greater than its power"; + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/InverterOfTruth.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/InverterOfTruth.java new file mode 100644 index 00000000000..a182186ab92 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/InverterOfTruth.java @@ -0,0 +1,110 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author fireshoes + */ +public class InverterOfTruth extends CardImpl { + + public InverterOfTruth(UUID ownerId) { + super(ownerId, 72, "Inverter of Truth", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Inverter of Truth enters the battlefield, exile all cards from your library face down, then shuffle all cards from your graveyard into your library. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ExileLibraryEffect(), false)); + } + + public InverterOfTruth(final InverterOfTruth card) { + super(card); + } + + @Override + public InverterOfTruth copy() { + return new InverterOfTruth(this); + } +} + +class ExileLibraryEffect extends OneShotEffect { + + public ExileLibraryEffect() { + super(Outcome.Exile); + staticText = "exile all cards from your library face down, then shuffle all cards from your graveyard into your library"; + } + + @java.lang.Override + public ExileLibraryEffect copy() { + return new ExileLibraryEffect(); + } + + @java.lang.Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + int count = controller.getLibrary().size(); + if (count > 0) { + for (Card cardToExile: controller.getLibrary().getCards(game)) { + cardToExile.moveToExile(null, "", source.getSourceId(), game); + cardToExile.setFaceDown(true, game); + } + } + for (Card cardToLibrary: controller.getGraveyard().getCards(game)) { + controller.moveCardToLibraryWithInfo(cardToLibrary, source.getSourceId(), game, Zone.GRAVEYARD, true, true); + } + controller.shuffleLibrary(game); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/IonasBlessing.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/IonasBlessing.java new file mode 100644 index 00000000000..997d5d59f57 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/IonasBlessing.java @@ -0,0 +1,138 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import static mage.constants.Layer.RulesEffects; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class IonasBlessing extends CardImpl { + + public IonasBlessing(UUID ownerId) { + super(ownerId, 21, "Iona's Blessing", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature gets +2/+2, has vigilance, and can block an additional creature. + ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, 2, Duration.WhileOnBattlefield)); + Effect effect = new GainAbilityAttachedEffect(VigilanceAbility.getInstance(), AttachmentType.AURA); + effect.setText(", has vigilance"); + ability.addEffect(effect); + ability.addEffect(new IonasBlessingEffect()); + this.addAbility(ability); + } + + public IonasBlessing(final IonasBlessing card) { + super(card); + } + + @Override + public IonasBlessing copy() { + return new IonasBlessing(this); + } +} + +class IonasBlessingEffect extends ContinuousEffectImpl { + + public IonasBlessingEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = ", and can block an additional creature"; + } + + public IonasBlessingEffect(final IonasBlessingEffect effect) { + super(effect); + } + + @Override + public IonasBlessingEffect copy() { + return new IonasBlessingEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent perm = game.getPermanent(source.getSourceId()); + if (perm != null && perm.getAttachedTo() != null) { + Permanent enchanted = game.getPermanent(perm.getAttachedTo()); + if (enchanted != null) { + switch (layer) { + case RulesEffects: + // maxBlocks = 0 equals to "can block any number of creatures" + if (enchanted.getMaxBlocks() > 0) { + enchanted.setMaxBlocks(enchanted.getMaxBlocks() + 1); + } + break; + } + return true; + } + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.RulesEffects; + } + +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/IsolationZone.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/IsolationZone.java new file mode 100644 index 00000000000..22eeef30de6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/IsolationZone.java @@ -0,0 +1,112 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.OnLeaveReturnExiledToBattlefieldAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.util.CardUtil; + +/** + * + * @author fireshoes + */ +public class IsolationZone extends CardImpl { + + private final static FilterPermanent filter = new FilterPermanent("creature or enchantment an opponent controls"); + + static { + filter.add(Predicates.or(new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.ENCHANTMENT))); + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + } + + public IsolationZone(UUID ownerId) { + super(ownerId, 22, "Isolation Zone", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); + this.expansionSetCode = "OGW"; + + // When Isolation Zone enters the battlefield, exile target creature or enchantment an opponent controls until Isolation Zone leaves the battlefield. + Ability ability = new EntersBattlefieldTriggeredAbility(new IsolationZoneExileEffect()); + ability.addTarget(new TargetPermanent(filter)); + ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility())); + this.addAbility(ability); + } + + public IsolationZone(final IsolationZone card) { + super(card); + } + + @Override + public IsolationZone copy() { + return new IsolationZone(this); + } +} + +class IsolationZoneExileEffect extends OneShotEffect { + + public IsolationZoneExileEffect() { + super(Outcome.Benefit); + this.staticText = "exile target creature or enchantment an opponent controls until {this} leaves the battlefield"; + } + + public IsolationZoneExileEffect(final IsolationZoneExileEffect effect) { + super(effect); + } + + @Override + public IsolationZoneExileEffect copy() { + return new IsolationZoneExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + // If Stasis Snare leaves the battlefield before its triggered ability resolves, + // the target won't be exiled. + if (permanent != null) { + return new ExileTargetEffect(CardUtil.getCardExileZoneId(game, source), permanent.getIdName()).apply(game, source); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/JoragaAuxiliary.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/JoragaAuxiliary.java index 9b055b99644..8a124d1f93a 100644 --- a/Mage.Sets/src/mage/sets/oathofthegatewatch/JoragaAuxiliary.java +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/JoragaAuxiliary.java @@ -29,6 +29,7 @@ package mage.sets.oathofthegatewatch; 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.effects.keyword.SupportEffect; @@ -36,6 +37,8 @@ import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.target.common.TargetCreaturePermanent; /** * @@ -53,7 +56,9 @@ public class JoragaAuxiliary extends CardImpl { this.toughness = new MageInt(3); // {4}{G}{W}: Support 2. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new SupportEffect(this, 2), new ManaCostsImpl("{4}{G}{W}"))); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SupportEffect(this, 2, true), new ManaCostsImpl("{4}{G}{W}")); + ability.addTarget(new TargetCreaturePermanent(0, 2, new FilterCreaturePermanent("target creatures"), false)); + this.addAbility(ability); } public JoragaAuxiliary(final JoragaAuxiliary card) { diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/JoriEnRuinDiver.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/JoriEnRuinDiver.java index 5d36252e759..88396f9c5b1 100644 --- a/Mage.Sets/src/mage/sets/oathofthegatewatch/JoriEnRuinDiver.java +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/JoriEnRuinDiver.java @@ -34,13 +34,11 @@ import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; -import mage.constants.WatcherScope; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.stack.Spell; -import mage.watchers.Watcher; +import mage.watchers.common.CastSpellLastTurnWatcher; /** * @@ -58,7 +56,7 @@ public class JoriEnRuinDiver extends CardImpl { this.toughness = new MageInt(3); // Whenever you cast your second spell each turn, draw a card. - this.addAbility(new JoriEnTriggeredAbility(), new JoriEnWatcher()); + this.addAbility(new JoriEnTriggeredAbility(), new CastSpellLastTurnWatcher()); } public JoriEnRuinDiver(final JoriEnRuinDiver card) { @@ -94,8 +92,8 @@ class JoriEnTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { if (event.getPlayerId().equals(controllerId)) { - Watcher watcher = game.getState().getWatchers().get("SecondSpellCast", controllerId); - if (watcher != null && watcher.conditionMet()) { + CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get("CastSpellLastTurnWatcher"); + if (watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) == 2) { return true; } } @@ -107,42 +105,3 @@ class JoriEnTriggeredAbility extends TriggeredAbilityImpl { return "Whenever you cast your second spell each turn, draw a card."; } } - -class JoriEnWatcher extends Watcher { - - int spellCount = 0; - - public JoriEnWatcher() { - super("SecondSpellCast", WatcherScope.PLAYER); - } - - public JoriEnWatcher(final JoriEnWatcher watcher) { - super(watcher); - this.spellCount = watcher.spellCount; - } - - @Override - public JoriEnWatcher copy() { - return new JoriEnWatcher(this); - } - - @Override - public void watch(GameEvent event, Game game) { - condition = false; - if (event.getType() == GameEvent.EventType.SPELL_CAST && event.getPlayerId().equals(controllerId)) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null) { - spellCount++; - if (spellCount == 2) { - condition = true; - } - } - } - } - - @Override - public void reset() { - super.reset(); - spellCount = 0; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/JwarIsleAvenger.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/JwarIsleAvenger.java new file mode 100644 index 00000000000..c02da7189dc --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/JwarIsleAvenger.java @@ -0,0 +1,66 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.SurgeAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class JwarIsleAvenger extends CardImpl { + + public JwarIsleAvenger(UUID ownerId) { + super(ownerId, 58, "Jwar Isle Avenger", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{U}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Sphinx"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Surge {2}{U} (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn.) + addAbility(new SurgeAbility(this, "{2}{U}")); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + } + + public JwarIsleAvenger(final JwarIsleAvenger card) { + super(card); + } + + @Override + public JwarIsleAvenger copy() { + return new JwarIsleAvenger(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/KazuulsTollCollector.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/KazuulsTollCollector.java new file mode 100644 index 00000000000..de86c6f4f79 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/KazuulsTollCollector.java @@ -0,0 +1,108 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author fireshoes + */ +public class KazuulsTollCollector extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("Equipment you control"); + + static { + filter.add(new SubtypePredicate("Equipment")); + } + + public KazuulsTollCollector(UUID ownerId) { + super(ownerId, 112, "Kazuul's Toll Collector", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{R}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Ogre"); + this.subtype.add("Warrior"); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // {0}: Attach target Equipment you control to Kazuul's Toll Collector. Activate this ability only any time you could cast a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new KazuulsTollCollectorEffect(), new ManaCostsImpl("{0}")); + ability.addTarget(new TargetControlledPermanent(filter)); + this.addAbility(ability); + } + + public KazuulsTollCollector(final KazuulsTollCollector card) { + super(card); + } + + @Override + public KazuulsTollCollector copy() { + return new KazuulsTollCollector(this); + } +} + +class KazuulsTollCollectorEffect extends OneShotEffect { + + public KazuulsTollCollectorEffect() { + super(Outcome.BoostCreature); + staticText = "Attach target Equipment you control to {this}"; + } + + public KazuulsTollCollectorEffect(final KazuulsTollCollectorEffect effect) { + super(effect); + } + + @Override + public KazuulsTollCollectorEffect copy() { + return new KazuulsTollCollectorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent equipment = game.getPermanent(source.getFirstTarget()); + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent != null && equipment != null) { + return permanent.addAttachment(equipment.getId(), game); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/KorScythemaster.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/KorScythemaster.java new file mode 100644 index 00000000000..3a252178baa --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/KorScythemaster.java @@ -0,0 +1,74 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.SourceMatchesFilterCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterAttackingCreature; + +/** + * + * @author fireshoes + */ +public class KorScythemaster extends CardImpl { + + private static final String rule = "{this} has first strike as long as it's attacking"; + + public KorScythemaster(UUID ownerId) { + super(ownerId, 23, "Kor Scythemaster", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{W}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Kor"); + this.subtype.add("Soldier"); + this.subtype.add("Ally"); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Kor Scythemaster has first strike as long as its attacking. + ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance()), + new SourceMatchesFilterCondition(new FilterAttackingCreature()), rule); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public KorScythemaster(final KorScythemaster card) { + super(card); + } + + @Override + public KorScythemaster copy() { + return new KorScythemaster(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/KorSkyClimber.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/KorSkyClimber.java new file mode 100644 index 00000000000..257ab22d60e --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/KorSkyClimber.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author fireshoes + */ +public class KorSkyClimber extends CardImpl { + + public KorSkyClimber(UUID ownerId) { + super(ownerId, 24, "Kor Sky Climber", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{W}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Kor"); + this.subtype.add("Soldier"); + this.subtype.add("Ally"); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // {1}{W}: Kor Sky Climber gains flying until end of turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{1}{W}"))); + } + + public KorSkyClimber(final KorSkyClimber card) { + super(card); + } + + @Override + public KorSkyClimber copy() { + return new KorSkyClimber(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/KozilekTheGreatDistortion.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/KozilekTheGreatDistortion.java index 767e9f188df..b56e37457ed 100644 --- a/Mage.Sets/src/mage/sets/oathofthegatewatch/KozilekTheGreatDistortion.java +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/KozilekTheGreatDistortion.java @@ -34,6 +34,7 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.CardsInHandCondition; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -133,7 +134,7 @@ class KozilekDiscardCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Spell targetSpell = game.getStack().getSpell(ability.getFirstTarget()); if (targetSpell == null) { return false; diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/KozileksPathfinder.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/KozileksPathfinder.java new file mode 100644 index 00000000000..2257f8579cb --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/KozileksPathfinder.java @@ -0,0 +1,71 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +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.effects.common.combat.CantBeBlockedByTargetSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class KozileksPathfinder extends CardImpl { + + public KozileksPathfinder(UUID ownerId) { + super(ownerId, 5, "Kozilek's Pathfinder", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{6}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // {C}: Target creature can't block Kozilek's Pathfinder this turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CantBeBlockedByTargetSourceEffect(Duration.EndOfTurn), + new ManaCostsImpl("{C}")); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public KozileksPathfinder(final KozileksPathfinder card) { + super(card); + } + + @Override + public KozileksPathfinder copy() { + return new KozileksPathfinder(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/KozileksShrieker.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/KozileksShrieker.java new file mode 100644 index 00000000000..f4f50364555 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/KozileksShrieker.java @@ -0,0 +1,80 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +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.effects.Effect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LevelX2 + */ +public class KozileksShrieker extends CardImpl { + + public KozileksShrieker(UUID ownerId) { + super(ownerId, 73, "Kozilek's Shrieker", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.subtype.add("Drone"); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + // {C}: Kozilek's Shrieker gets +1/+0 and gains menace until end of turn. + Effect effect = new BoostSourceEffect(1, 0, Duration.EndOfTurn); + effect.setText("{this} gets +1/+0"); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{C}")); + effect = new GainAbilitySourceEffect(new MenaceAbility(), Duration.EndOfTurn); + effect.setText("and gains menace until end of turn"); + ability.addEffect(effect); + this.addAbility(ability); + } + + public KozileksShrieker(final KozileksShrieker card) { + super(card); + } + + @Override + public KozileksShrieker copy() { + return new KozileksShrieker(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/KozileksTranslator.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/KozileksTranslator.java new file mode 100644 index 00000000000..4e486209918 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/KozileksTranslator.java @@ -0,0 +1,71 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.Mana; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.effects.common.BasicManaEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.abilities.mana.ActivateOncePerTurnManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LevelX2 + */ +public class KozileksTranslator extends CardImpl { + + public KozileksTranslator(UUID ownerId) { + super(ownerId, 74, "Kozilek's Translator", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{B}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.subtype.add("Drone"); + this.power = new MageInt(3); + this.toughness = new MageInt(5); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // Pay 1 life: Add {C} to your mana pool. Activate this ability only once each turn. + this.addAbility(new ActivateOncePerTurnManaAbility(Zone.BATTLEFIELD, new BasicManaEffect(Mana.ColorlessMana(1)), new PayLifeCost(1))); + } + + public KozileksTranslator(final KozileksTranslator card) { + super(card); + } + + @Override + public KozileksTranslator copy() { + return new KozileksTranslator(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/LeadByExample.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/LeadByExample.java new file mode 100644 index 00000000000..fd731315614 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/LeadByExample.java @@ -0,0 +1,58 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.keyword.SupportEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author LevelX2 + */ +public class LeadByExample extends CardImpl { + + public LeadByExample(UUID ownerId) { + super(ownerId, 134, "Lead by Example", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{G}"); + this.expansionSetCode = "OGW"; + + // Support 2. + getSpellAbility().addEffect(new SupportEffect(this, 2, false)); + } + + public LeadByExample(final LeadByExample card) { + super(card); + } + + @Override + public LeadByExample copy() { + return new LeadByExample(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/LoamLarva.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/LoamLarva.java new file mode 100644 index 00000000000..2db8cf797db --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/LoamLarva.java @@ -0,0 +1,66 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterBasicLandCard; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author LevelX2 + */ +public class LoamLarva extends CardImpl { + + public LoamLarva(UUID ownerId) { + super(ownerId, 135, "Loam Larva", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{G}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Insect"); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // When Loam Larva enters the battlefield, you may search your library for a basic land card, reveal it, then shuffle your library and put that card on top of it. + TargetCardInLibrary target = new TargetCardInLibrary(new FilterBasicLandCard()); + this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutOnLibraryEffect(target, true, true), true)); + } + + public LoamLarva(final LoamLarva card) { + super(card); + } + + @Override + public LoamLarva copy() { + return new LoamLarva(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/MakeAStand.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/MakeAStand.java new file mode 100644 index 00000000000..35489afef6e --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/MakeAStand.java @@ -0,0 +1,67 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class MakeAStand extends CardImpl { + + public MakeAStand(UUID ownerId) { + super(ownerId, 26, "Make a Stand", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{2}{W}"); + this.expansionSetCode = "OGW"; + + // Creature you control get +1/+0 and gain indestructible until end of turn. + Effect effect1 = new BoostControlledEffect(1, 0, Duration.EndOfTurn); + effect1.setText("Creature you control get +1/+0"); + this.getSpellAbility().addEffect(effect1); + Effect effect2 = new GainAbilityControlledEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn); + effect2.setText("and gain indestructible until end of turn"); + this.getSpellAbility().addEffect(effect2); + } + + public MakeAStand(final MakeAStand card) { + super(card); + } + + @Override + public MakeAStand copy() { + return new MakeAStand(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/MakindiAeronaut.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/MakindiAeronaut.java new file mode 100644 index 00000000000..20fdab32b59 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/MakindiAeronaut.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class MakindiAeronaut extends CardImpl { + + public MakindiAeronaut(UUID ownerId) { + super(ownerId, 27, "Makindi Aeronaut", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{W}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Kor"); + this.subtype.add("Scout"); + this.subtype.add("Ally"); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + } + + public MakindiAeronaut(final MakindiAeronaut card) { + super(card); + } + + @Override + public MakindiAeronaut copy() { + return new MakindiAeronaut(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/MalakirSoothsayer.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/MalakirSoothsayer.java new file mode 100644 index 00000000000..63f263083f1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/MalakirSoothsayer.java @@ -0,0 +1,92 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class MalakirSoothsayer extends CardImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Ally you control"); + + static { + filter.add(new SubtypePredicate("Ally")); + filter.add(Predicates.not(new TappedPredicate())); + } + + public MalakirSoothsayer(UUID ownerId) { + super(ownerId, 87, "Malakir Soothsayer", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{4}{B}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Vampire"); + this.subtype.add("Shaman"); + this.subtype.add("Ally"); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Cohort — {T}, Tap an untapped Ally you control: You draw a card and you lose a life. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new DrawCardSourceControllerEffect(1), + new TapSourceCost()); + ability.setAbilityWord(AbilityWord.COHORT); + ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, false))); + Effect effect = new LoseLifeSourceControllerEffect(1); + effect.setText("and you lose a life"); + ability.addEffect(effect); + this.addAbility(ability); + + } + + public MalakirSoothsayer(final MalakirSoothsayer card) { + super(card); + } + + @Override + public MalakirSoothsayer copy() { + return new MalakirSoothsayer(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/MatterReshaper.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/MatterReshaper.java new file mode 100644 index 00000000000..220c8f66c5f --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/MatterReshaper.java @@ -0,0 +1,117 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.Filter.ComparisonType; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author fireshoes + */ +public class MatterReshaper extends CardImpl { + + public MatterReshaper(UUID ownerId) { + super(ownerId, 6, "Matter Reshaper", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{C}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // When Matter Reshaper dies, reveal the top card of your library. You may put that card onto the battlefield + // if it's a permanent card with converted mana cost 3 or less. Otherwise, put that card into your hand. + this.addAbility(new DiesTriggeredAbility(new MatterReshaperEffect(), false)); + } + + public MatterReshaper(final MatterReshaper card) { + super(card); + } + + @Override + public MatterReshaper copy() { + return new MatterReshaper(this); + } +} + +class MatterReshaperEffect extends OneShotEffect { + + public MatterReshaperEffect() { + super(Outcome.Benefit); + staticText = "reveal the top card of your library. You may put that card onto the battlefield if it's a permanent card" + + " with converted mana cost 3 or less. Otherwise, put that card into your hand"; + } + + public MatterReshaperEffect(final MatterReshaperEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller != null && sourceObject != null && controller.getLibrary().size() > 0) { + Card card = controller.getLibrary().getFromTop(game); + if (card == null) { + return false; + } + controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game); + FilterPermanentCard filter = new FilterPermanentCard("permanent card with converted mana cost 3 or less"); + filter.add(new ConvertedManaCostPredicate(ComparisonType.LessThan, 4)); + if (filter.match(card, game)) { + if (controller.chooseUse(Outcome.PutCardInPlay, "Put " + card.getName() + " onto the battlefield (otherwise put in hand)?", source, game)) { + card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), source.getControllerId(), false); + return true; + } + } + card.moveToZone(Zone.HAND, source.getSourceId(), game, false); + return true; + } + return false; + } + + @Override + public MatterReshaperEffect copy() { + return new MatterReshaperEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/MawOfKozilek.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/MawOfKozilek.java new file mode 100644 index 00000000000..aec8357b84b --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/MawOfKozilek.java @@ -0,0 +1,71 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author fireshoes + */ +public class MawOfKozilek extends CardImpl { + + public MawOfKozilek(UUID ownerId) { + super(ownerId, 99, "Maw of Kozilek", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{R}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.subtype.add("Drone"); + this.power = new MageInt(2); + this.toughness = new MageInt(5); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // {C}: Maw of Kozilek gets +2/-2 until end of turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(2, -2, Duration.EndOfTurn), new ManaCostsImpl("{C}"))); + } + + public MawOfKozilek(final MawOfKozilek card) { + super(card); + } + + @Override + public MawOfKozilek copy() { + return new MawOfKozilek(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/MeanderingStream.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/MeanderingRiver.java similarity index 85% rename from Mage.Sets/src/mage/sets/oathofthegatewatch/MeanderingStream.java rename to Mage.Sets/src/mage/sets/oathofthegatewatch/MeanderingRiver.java index b5a97066877..09a3166e9f5 100644 --- a/Mage.Sets/src/mage/sets/oathofthegatewatch/MeanderingStream.java +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/MeanderingRiver.java @@ -39,13 +39,13 @@ import mage.constants.Rarity; * * @author fireshoes */ -public class MeanderingStream extends CardImpl { +public class MeanderingRiver extends CardImpl { - public MeanderingStream(UUID ownerId) { - super(ownerId, 173, "Meandering Stream", Rarity.UNCOMMON, new CardType[]{CardType.LAND}, ""); + public MeanderingRiver(UUID ownerId) { + super(ownerId, 173, "Meandering River", Rarity.UNCOMMON, new CardType[]{CardType.LAND}, ""); this.expansionSetCode = "OGW"; - // Meandering Stream enters the battlefield tapped. + // Meandering River enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); // {T}: Add {W} or {U} to your mana pool. @@ -53,12 +53,12 @@ public class MeanderingStream extends CardImpl { this.addAbility(new BlueManaAbility()); } - public MeanderingStream(final MeanderingStream card) { + public MeanderingRiver(final MeanderingRiver card) { super(card); } @Override - public MeanderingStream copy() { - return new MeanderingStream(this); + public MeanderingRiver copy() { + return new MeanderingRiver(this); } } diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/MightyLeap.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/MightyLeap.java new file mode 100644 index 00000000000..89387a29318 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/MightyLeap.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; + +/** + * + * @author fireshoes + */ +public class MightyLeap extends mage.sets.magic2011.MightyLeap { + + public MightyLeap(UUID ownerId) { + super(ownerId); + this.cardNumber = 28; + this.expansionSetCode = "OGW"; + } + + public MightyLeap(final MightyLeap card) { + super(card); + } + + @Override + public MightyLeap copy() { + return new MightyLeap(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/MundasVanguard.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/MundasVanguard.java index a6d7e934a9c..77fd534295d 100644 --- a/Mage.Sets/src/mage/sets/oathofthegatewatch/MundasVanguard.java +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/MundasVanguard.java @@ -41,19 +41,20 @@ import mage.constants.Rarity; import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; /** * * @author fireshoes */ public class MundasVanguard extends CardImpl { - - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Ally you control"); - + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("an untapped Ally you control"); + static { filter.add(new SubtypePredicate("Ally")); filter.add(Predicates.not(new TappedPredicate())); @@ -69,9 +70,9 @@ public class MundasVanguard extends CardImpl { this.toughness = new MageInt(3); // Cohort — {T}, Tap an untapped Ally you control: Put a +1/+1 counter on each creature you control. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersAllEffect(CounterType.P1P1.createInstance(), new FilterControlledCreaturePermanent()), + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersAllEffect(CounterType.P1P1.createInstance(), new FilterControlledCreaturePermanent()), new TapSourceCost()); - ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(filter))); + ability.addCost(new TapTargetCost(new TargetControlledPermanent(filter))); ability.setAbilityWord(AbilityWord.COHORT); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/NaturalState.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/NaturalState.java new file mode 100644 index 00000000000..a6e4f08f7df --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/NaturalState.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.Filter; +import mage.filter.common.FilterArtifactOrEnchantmentPermanent; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.target.TargetPermanent; + +/** + * + * @author LevelX2 + */ +public class NaturalState extends CardImpl { + + private static final FilterArtifactOrEnchantmentPermanent filter = new FilterArtifactOrEnchantmentPermanent("artifact or enchantment with converted mana cost 3 or less"); + + static { + filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.LessThan, 4)); + } + + public NaturalState(UUID ownerId) { + super(ownerId, 136, "Natural State", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{G}"); + this.expansionSetCode = "OGW"; + + // Destroy target artifact or enchantment with converted mana cost 3 or less. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + } + + public NaturalState(final NaturalState card) { + super(card); + } + + @Override + public NaturalState copy() { + return new NaturalState(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/Negate.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/Negate.java new file mode 100644 index 00000000000..069782b75ed --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/Negate.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; + +/** + * + * @author fireshoes + */ +public class Negate extends mage.sets.magic2010.Negate { + + public Negate(UUID ownerId) { + super(ownerId); + this.cardNumber = 59; + this.expansionSetCode = "OGW"; + } + + public Negate(final Negate card) { + super(card); + } + + @Override + public Negate copy() { + return new Negate(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/NetcasterSpider.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/NetcasterSpider.java new file mode 100644 index 00000000000..2dd39b5f673 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/NetcasterSpider.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; + +/** + * + * @author fireshoes + */ +public class NetcasterSpider extends mage.sets.magic2015.NetcasterSpider { + + public NetcasterSpider(UUID ownerId) { + super(ownerId); + this.cardNumber = 137; + this.expansionSetCode = "OGW"; + } + + public NetcasterSpider(final NetcasterSpider card) { + super(card); + } + + @Override + public NetcasterSpider copy() { + return new NetcasterSpider(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/NissasJudgment.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/NissasJudgment.java new file mode 100644 index 00000000000..78baa1d2215 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/NissasJudgment.java @@ -0,0 +1,128 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.keyword.SupportEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.filter.predicate.permanent.CounterPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; + +/** + * + * @author LevelX2 + */ +public class NissasJudgment extends CardImpl { + + private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); + + static { + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + } + + public NissasJudgment(UUID ownerId) { + super(ownerId, 139, "Nissa's Judgment", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{4}{G}"); + this.expansionSetCode = "OGW"; + + // Support 2. + Effect effect = new SupportEffect(this, 2, false); + effect.setApplyEffectsAfter(); + getSpellAbility().addEffect(effect); + + // 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, filter, true)); + getSpellAbility().addEffect(effect); + } + + public NissasJudgment(final NissasJudgment card) { + super(card); + } + + @Override + public NissasJudgment copy() { + return new NissasJudgment(this); + } +} + +class NissasJudgmentEffect extends OneShotEffect { + + private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); + private final static FilterCreaturePermanent filterWithCounter = new FilterCreaturePermanent(); + + static { + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + filterWithCounter.add(new CounterPredicate(CounterType.P1P1)); + } + + public NissasJudgmentEffect() { + super(Outcome.Damage); + this.staticText = "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"; + } + + public NissasJudgmentEffect(final NissasJudgmentEffect effect) { + super(effect); + } + + @Override + public NissasJudgmentEffect copy() { + return new NissasJudgmentEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (targetCreature != null) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filterWithCounter, controller.getId(), game)) { + if (permanent.getPower().getValue() > 0) { + targetCreature.damage(permanent.getPower().getValue(), permanent.getId(), game, false, true); + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/NullCaller.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/NullCaller.java new file mode 100644 index 00000000000..017ae428e5c --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/NullCaller.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.ExileFromGraveCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreatureCard; +import mage.game.permanent.token.ZombieToken; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author LevelX2 + */ +public class NullCaller extends CardImpl { + + public NullCaller(UUID ownerId) { + super(ownerId, 88, "Null Caller", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Vampire"); + this.subtype.add("Shaman"); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // {3}{B}, Exile a creature card from your graveyard: Put a 2/2 black Zombie creature token onto the battlefield tapped. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new CreateTokenEffect(new ZombieToken(), 1, true, false), + new ManaCostsImpl<>("{3}{B}")); + ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard")))); + this.addAbility(ability); + + } + + public NullCaller(final NullCaller card) { + super(card); + } + + @Override + public NullCaller copy() { + return new NullCaller(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/OathOfChandra.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/OathOfChandra.java new file mode 100644 index 00000000000..3b0dd86e8d8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/OathOfChandra.java @@ -0,0 +1,153 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.target.common.TargetCreaturePermanent; +import mage.watchers.Watcher; + +/** + * + * @author LevelX2 + */ +public class OathOfChandra extends CardImpl { + + private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); + + static { + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + } + + public OathOfChandra(UUID ownerId) { + super(ownerId, 113, "Oath of Chandra", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); + this.expansionSetCode = "OGW"; + this.supertype.add("Legendary"); + + // When Oath of Chandra enters the battlefield, it deals 3 damage to target creature an opponent controls. + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(3), false); + ability.addTarget(new TargetCreaturePermanent(filter)); + 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 ConditionalTriggeredAbility(new BeginningOfEndStepTriggeredAbility( + new DamagePlayersEffect(Outcome.Damage, new StaticValue(2), TargetController.OPPONENT), + TargetController.ANY, false), OathOfChandraCondition.getInstance(), + "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()); + } + + public OathOfChandra(final OathOfChandra card) { + super(card); + } + + @Override + public OathOfChandra copy() { + return new OathOfChandra(this); + } +} + +class OathOfChandraCondition implements Condition { + + private static final OathOfChandraCondition fInstance = new OathOfChandraCondition(); + + public static Condition getInstance() { + return fInstance; + } + + @Override + public boolean apply(Game game, Ability source) { + OathOfChandraWatcher watcher = (OathOfChandraWatcher) game.getState().getWatchers().get("OathOfChandraWatcher"); + return watcher != null && watcher.enteredPlaneswalkerForPlayer(source.getControllerId()); + } + + @Override + public String toString() { + return "if a planeswalker entered the battlefield under your control this turn"; + } + +} + +class OathOfChandraWatcher extends Watcher { + + private final Set players = new HashSet<>(); + + public OathOfChandraWatcher() { + super("OathOfChandraWatcher", WatcherScope.GAME); + } + + public OathOfChandraWatcher(final OathOfChandraWatcher watcher) { + super(watcher); + this.players.addAll(watcher.players); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ZONE_CHANGE) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getToZone().equals(Zone.BATTLEFIELD) + && zEvent.getTarget().getCardType().contains(CardType.PLANESWALKER)) { + players.add(zEvent.getTarget().getControllerId()); + } + } + } + + @Override + public void reset() { + players.clear(); + } + + public boolean enteredPlaneswalkerForPlayer(UUID playerId) { + return players.contains(playerId); + } + + @Override + public OathOfChandraWatcher copy() { + return new OathOfChandraWatcher(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/OathOfGideon.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/OathOfGideon.java new file mode 100644 index 00000000000..ab557ac3339 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/OathOfGideon.java @@ -0,0 +1,118 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +/** + * + * @author LevelX2 + */ +public class OathOfGideon extends CardImpl { + + public OathOfGideon(UUID ownerId) { + super(ownerId, 30, "Oath of Gideon", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); + this.expansionSetCode = "OGW"; + this.supertype.add("Legendary"); + + // When Oath of Gideon enters the battlefield, put two 1/1 Kor Ally creature tokens onto the battlefield. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new KorAllyToken(), 2), false)); + + // Each planeswalker you control enters the battlefield with an additional loyalty counter on it. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new OathOfGideonReplacementEffect())); + } + + public OathOfGideon(final OathOfGideon card) { + super(card); + } + + @Override + public OathOfGideon copy() { + return new OathOfGideon(this); + } +} + +class OathOfGideonReplacementEffect extends ReplacementEffectImpl { + + OathOfGideonReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "Each planeswalker you control enters the battlefield with an additional loyalty counter on it"; + } + + OathOfGideonReplacementEffect(OathOfGideonReplacementEffect effect) { + super(effect); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); + return creature != null && creature.getControllerId().equals(source.getControllerId()) + && creature.getCardType().contains(CardType.PLANESWALKER) + && !event.getTargetId().equals(source.getSourceId()); + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); + if (creature != null) { + creature.addCounters(CounterType.LOYALTY.createInstance(), game); + } + return false; + } + + @Override + public OathOfGideonReplacementEffect copy() { + return new OathOfGideonReplacementEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/OathOfJace.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/OathOfJace.java new file mode 100644 index 00000000000..62f9b6961f6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/OathOfJace.java @@ -0,0 +1,102 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.filter.common.FilterPlaneswalkerPermanent; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author LevelX2 + */ +public class OathOfJace extends CardImpl { + + public OathOfJace(UUID ownerId) { + super(ownerId, 60, "Oath of Jace", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + this.expansionSetCode = "OGW"; + this.supertype.add("Legendary"); + + // When Oath of Jace enters the battlefield, draw three cards, then discard two cards. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawDiscardControllerEffect(3, 2), false)); + + // At the beginning of your upkeep, scry X, where X is the number of planeswalkers you control. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new OathOfJaceEffect(), TargetController.YOU, false)); + + } + + public OathOfJace(final OathOfJace card) { + super(card); + } + + @Override + public OathOfJace copy() { + return new OathOfJace(this); + } +} + +class OathOfJaceEffect extends OneShotEffect { + + public OathOfJaceEffect() { + super(Outcome.DrawCard); + this.staticText = "scry X, where X is the number of planeswalkers you control"; + } + + public OathOfJaceEffect(final OathOfJaceEffect effect) { + super(effect); + } + + @Override + public OathOfJaceEffect copy() { + return new OathOfJaceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + int planeswalker = game.getBattlefield().countAll(new FilterPlaneswalkerPermanent(), source.getControllerId(), game); + if (planeswalker > 0) { + controller.scry(planeswalker, source, game); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/OathOfNissa.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/OathOfNissa.java new file mode 100644 index 00000000000..3c22c7857a4 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/OathOfNissa.java @@ -0,0 +1,183 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.AsThoughManaEffect; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.AsThoughEffectType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.ManaType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.players.ManaPoolItem; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetCard; + +/** + * + * @author LevelX2 + */ +public class OathOfNissa extends CardImpl { + + public OathOfNissa(UUID ownerId) { + super(ownerId, 140, "Oath of Nissa", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{G}"); + this.expansionSetCode = "OGW"; + this.supertype.add("Legendary"); + + // When Oath of Nissa enters the battlefield, look at the top three cards of your library. You may reveal a creature, land, or planeswalker 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 OathOfNissaEffect())); + + // You may spend mana as though it were mana of any color to cast planeswalker spells. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new OathOfNissaSpendAnyManaEffect())); + } + + public OathOfNissa(final OathOfNissa card) { + super(card); + } + + @Override + public OathOfNissa copy() { + return new OathOfNissa(this); + } +} + +class OathOfNissaEffect extends OneShotEffect { + + private final static FilterCard filter = new FilterCard("a creature, land, or planeswalker card"); + + static { + filter.add(Predicates.or(new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.PLANESWALKER), + new CardTypePredicate(CardType.LAND))); + } + + public OathOfNissaEffect() { + super(Outcome.DrawCard); + this.staticText = "look at the top three cards of your library. You may reveal a creature, land, or planeswalker card from among them and put it into your hand. Put the rest on the bottom of your library in any order"; + } + + public OathOfNissaEffect(final OathOfNissaEffect effect) { + super(effect); + } + + @Override + public OathOfNissaEffect copy() { + return new OathOfNissaEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller != null && sourceObject != null) { + Cards topCards = new CardsImpl(); + topCards.addAll(controller.getLibrary().getTopCards(game, 3)); + if (!topCards.isEmpty()) { + controller.lookAtCards(sourceObject.getIdName(), topCards, game); + int number = topCards.count(filter, source.getSourceId(), source.getControllerId(), game); + if (number > 0) { + if (controller.chooseUse(outcome, "Reveal a creature, land, or planeswalker card from the looked at cards and put it into your hand?", source, game)) { + Card card; + if (number == 1) { + card = topCards.getCards(filter, source.getSourceId(), source.getControllerId(), game).iterator().next(); + } else { + Target target = new TargetCard(Zone.LIBRARY, filter); + controller.chooseTarget(outcome, target, source, game); + card = topCards.get(target.getFirstTarget(), game); + } + if (card != null) { + controller.moveCards(card, Zone.HAND, source, game); + controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game); + topCards.remove(card); + } + } + controller.putCardsOnBottomOfLibrary(topCards, game, source, true); + } + } + return true; + } + return false; + } +} + +class OathOfNissaSpendAnyManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect { + + public OathOfNissaSpendAnyManaEffect() { + super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.Custom, Outcome.Benefit); + staticText = "you may spend mana as though it were mana of any color to cast planeswalker spells"; + } + + public OathOfNissaSpendAnyManaEffect(final OathOfNissaSpendAnyManaEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public OathOfNissaSpendAnyManaEffect copy() { + return new OathOfNissaSpendAnyManaEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + if (source.getControllerId().equals(affectedControllerId)) { + MageObject mageObject = game.getObject(objectId); + if (mageObject != null) { + if (mageObject.getCardType().contains(CardType.PLANESWALKER)) { + return true; + } + } + } + return false; + } + + @Override + public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + return mana.getFirstAvailable(); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/OblivionStrike.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/OblivionStrike.java new file mode 100644 index 00000000000..ab726803a14 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/OblivionStrike.java @@ -0,0 +1,63 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class OblivionStrike extends CardImpl { + + public OblivionStrike(UUID ownerId) { + super(ownerId, 75, "Oblivion Strike", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{3}{B}"); + this.expansionSetCode = "OGW"; + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + // Exile target creature. + getSpellAbility().addEffect(new ExileTargetEffect()); + getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public OblivionStrike(final OblivionStrike card) { + super(card); + } + + @Override + public OblivionStrike copy() { + return new OblivionStrike(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/OnduWarCleric.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/OnduWarCleric.java new file mode 100644 index 00000000000..254fd2e6e72 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/OnduWarCleric.java @@ -0,0 +1,85 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +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.common.TapTargetCost; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author fireshoes + */ +public class OnduWarCleric extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("an untapped Ally you control"); + + static { + filter.add(new SubtypePredicate("Ally")); + filter.add(Predicates.not(new TappedPredicate())); + } + + public OnduWarCleric(UUID ownerId) { + super(ownerId, 31, "Ondu War Cleric", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{W}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Human"); + this.subtype.add("Cleric"); + this.subtype.add("Ally"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Cohort — {T}, Tap an untapped Ally you control: You gain 2 life. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(2), new TapSourceCost()); + ability.addCost(new TapTargetCost(new TargetControlledPermanent(filter))); + ability.setAbilityWord(AbilityWord.COHORT); + this.addAbility(ability); + } + + public OnduWarCleric(final OnduWarCleric card) { + super(card); + } + + @Override + public OnduWarCleric copy() { + return new OnduWarCleric(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/OverwhelmingDenial.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/OverwhelmingDenial.java new file mode 100644 index 00000000000..1ff83b3a091 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/OverwhelmingDenial.java @@ -0,0 +1,77 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CantBeCounteredSourceEffect; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.abilities.keyword.SurgeAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetSpell; + +/** + * + * @author fireshoes + */ +public class OverwhelmingDenial extends CardImpl { + + public OverwhelmingDenial(UUID ownerId) { + super(ownerId, 61, "Overwhelming Denial", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{2}{U}{U}"); + this.expansionSetCode = "OGW"; + + // Overwhelming Denial can't be countered by spell or abilities. + Effect effect = new CantBeCounteredSourceEffect(); + effect.setText("{this} can't be countered by spells or abilities"); + Ability ability = new SimpleStaticAbility(Zone.STACK, effect); + ability.setRuleAtTheTop(true); + this.addAbility(ability); + + // Counter target spell. + this.getSpellAbility().addTarget(new TargetSpell()); + this.getSpellAbility().addEffect(new CounterTargetEffect()); + + // Has to be placed last here, because added spellAbility objects (e.g. effects) have to be copied from this + // Surge {U}{U} (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn) + addAbility(new SurgeAbility(this, "{U}{U}")); + } + + public OverwhelmingDenial(final OverwhelmingDenial card) { + super(card); + } + + @Override + public OverwhelmingDenial copy() { + return new OverwhelmingDenial(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/PressIntoService.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/PressIntoService.java new file mode 100644 index 00000000000..3d33c135327 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/PressIntoService.java @@ -0,0 +1,78 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +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; +import mage.abilities.effects.keyword.SupportEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; + +/** + * + * @author fireshoes + */ +public class PressIntoService extends CardImpl { + + public PressIntoService(UUID ownerId) { + super(ownerId, 114, "Press into Service", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{4}{R}"); + this.expansionSetCode = "OGW"; + + // Support 2. + getSpellAbility().addEffect(new SupportEffect(this, 2, false)); + + // Gain control of target creature until end of turn. Untap that creature. It gains haste until end of turn. + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + Effect effect = new GainControlTargetEffect(Duration.EndOfTurn); + effect.setTargetPointer(new SecondTargetPointer()); // First target is used by Support + this.getSpellAbility().addEffect(effect); + effect = new UntapTargetEffect(); + effect.setTargetPointer(new SecondTargetPointer()); // First target is used by Support + this.getSpellAbility().addEffect(effect); + effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); + effect.setTargetPointer(new SecondTargetPointer()); // First target is used by Suppor + this.getSpellAbility().addEffect(effect); + } + + public PressIntoService(final PressIntoService card) { + super(card); + } + + @Override + public PressIntoService copy() { + return new PressIntoService(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/PulseOfMurasa.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/PulseOfMurasa.java new file mode 100644 index 00000000000..52f467f75fc --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/PulseOfMurasa.java @@ -0,0 +1,74 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.target.common.TargetCardInGraveyard; + +/** + * + * @author LevelX2 + */ +public class PulseOfMurasa extends CardImpl { + + private static final FilterCard filter = new FilterCard("creature or land card in a graveyard"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.LAND))); + } + + public PulseOfMurasa(UUID ownerId) { + super(ownerId, 141, "Pulse of Murasa", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{2}{G}"); + this.expansionSetCode = "OGW"; + + // Return target creature or land card from a graveyard to its owner's hand. + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetCardInGraveyard(filter)); + // You gain 6 life. + getSpellAbility().addEffect(new GainLifeEffect(6)); + } + + public PulseOfMurasa(final PulseOfMurasa card) { + super(card); + } + + @Override + public PulseOfMurasa copy() { + return new PulseOfMurasa(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/PyromancersAssault.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/PyromancersAssault.java new file mode 100644 index 00000000000..20b0ac73ed9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/PyromancersAssault.java @@ -0,0 +1,105 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.target.common.TargetCreatureOrPlayer; +import mage.watchers.common.CastSpellLastTurnWatcher; + +/** + * + * @author fireshoes + */ +public class PyromancersAssault extends CardImpl { + + public PyromancersAssault(UUID ownerId) { + super(ownerId, 115, "Pyromancer's Assault", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); + this.expansionSetCode = "OGW"; + + // Whenever you cast your second spell each turn, Pyromancer's Assault deals 2 damage to target creature or player. + Ability ability = new PyromancersAssaultTriggeredAbility(); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(ability, new CastSpellLastTurnWatcher()); + } + + public PyromancersAssault(final PyromancersAssault card) { + super(card); + } + + @Override + public PyromancersAssault copy() { + return new PyromancersAssault(this); + } +} + +class PyromancersAssaultTriggeredAbility extends TriggeredAbilityImpl { + + public PyromancersAssaultTriggeredAbility() { + super(Zone.BATTLEFIELD, new DamageTargetEffect(2)); + } + + public PyromancersAssaultTriggeredAbility(final PyromancersAssaultTriggeredAbility ability) { + super(ability); + } + + @Override + public PyromancersAssaultTriggeredAbility copy() { + return new PyromancersAssaultTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.SPELL_CAST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getPlayerId().equals(controllerId)) { + CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get("CastSpellLastTurnWatcher"); + if (watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) == 2) { + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever you cast your second spell each turn, {this} deals 2 damage to target creature or player."; + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/RealityHemorrhage.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/RealityHemorrhage.java new file mode 100644 index 00000000000..3de8d16fc04 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/RealityHemorrhage.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author fireshoes + */ +public class RealityHemorrhage extends CardImpl { + + public RealityHemorrhage(UUID ownerId) { + super(ownerId, 100, "Reality Hemorrhage", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{R}"); + this.expansionSetCode = "OGW"; + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // Reality Hemorrhage deals 2 damage to target creature or player. + this.getSpellAbility().addEffect(new DamageTargetEffect(2)); + this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); + } + + public RealityHemorrhage(final RealityHemorrhage card) { + super(card); + } + + @Override + public RealityHemorrhage copy() { + return new RealityHemorrhage(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/RealitySmasher.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/RealitySmasher.java new file mode 100644 index 00000000000..a0eecdff654 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/RealitySmasher.java @@ -0,0 +1,126 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CounterUnlessPaysEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterSpell; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.stack.Spell; +import mage.game.stack.StackObject; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author LevelX2 + */ +public class RealitySmasher extends CardImpl { + + public RealitySmasher(UUID ownerId) { + super(ownerId, 7, "Reality Smasher", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{4}{C}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + // Haste + this.addAbility(HasteAbility.getInstance()); + // Whenever Reality Smasher becomes the target of a spell an opponent controls, counter that spell unless its controller discards a card. + this.addAbility(new RealitySmasherTriggeredAbility()); + } + + public RealitySmasher(final RealitySmasher card) { + super(card); + } + + @Override + public RealitySmasher copy() { + return new RealitySmasher(this); + } +} + +class RealitySmasherTriggeredAbility extends TriggeredAbilityImpl { + + private static final FilterSpell spellCard = new FilterSpell("a spell"); + + public RealitySmasherTriggeredAbility() { + super(Zone.BATTLEFIELD, new CounterUnlessPaysEffect(new DiscardCardCost()), false); + } + + public RealitySmasherTriggeredAbility(final RealitySmasherTriggeredAbility ability) { + super(ability); + } + + @Override + public RealitySmasherTriggeredAbility copy() { + return new RealitySmasherTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.TARGETED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + StackObject spell = game.getStack().getStackObject(event.getSourceId()); + if (spell == null || !(spell instanceof Spell)) { + return false; + } else { + if (event.getTargetId().equals(this.getSourceId()) + && game.getOpponents(this.controllerId).contains(event.getPlayerId()) + && spellCard.match(spell, getSourceId(), getControllerId(), game)) { + for (Effect effect : getEffects()) { + effect.setTargetPointer(new FixedTarget(spell.getId())); + } + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever {this} becomes the target of a spell an opponent controls, counter that spell unless its controller discards a card."; + } + +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/ReaverDrone.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/ReaverDrone.java new file mode 100644 index 00000000000..a98422b459a --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/ReaverDrone.java @@ -0,0 +1,86 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition.CountType; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorlessPredicate; +import mage.filter.predicate.permanent.AnotherPredicate; + +/** + * + * @author fireshoes + */ +public class ReaverDrone extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another colorless creature"); + + static { + filter.add(new AnotherPredicate()); + filter.add(new ColorlessPredicate()); + } + + public ReaverDrone(UUID ownerId) { + super(ownerId, 76, "Reaver Drone", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{B}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.subtype.add("Drone"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // At the beginning of your upkeep, you lose 1 life unless you control another colorless creature. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new ConditionalOneShotEffect( + new LoseLifeSourceControllerEffect(1), + new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter, CountType.MORE_THAN, 0, true)), + "you lose 1 life unless you control another colorless creature"), TargetController.YOU, false)); + } + + public ReaverDrone(final ReaverDrone card) { + super(card); + } + + @Override + public ReaverDrone copy() { + return new ReaverDrone(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/RecklessBushwhacker.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/RecklessBushwhacker.java index 9b3490448e0..2665e64d30d 100644 --- a/Mage.Sets/src/mage/sets/oathofthegatewatch/RecklessBushwhacker.java +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/RecklessBushwhacker.java @@ -41,6 +41,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; /** * @@ -48,6 +49,12 @@ import mage.filter.common.FilterControlledCreaturePermanent; */ public class RecklessBushwhacker extends CardImpl { + private final static FilterControlledCreaturePermanent FILTER = new FilterControlledCreaturePermanent("other creatures you control"); + + static { + FILTER.add(new AnotherPredicate()); + } + public RecklessBushwhacker(UUID ownerId) { super(ownerId, 116, "Reckless Bushwhacker", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{R}"); this.expansionSetCode = "OGW"; @@ -57,18 +64,18 @@ public class RecklessBushwhacker extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(1); + // Surge {1}{R} (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn) + addAbility(new SurgeAbility(this, "{1}{R}")); + // Haste 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, new FilterControlledCreaturePermanent(), true)); + ability.addEffect(new GainAbilityControlledEffect(HasteAbility.getInstance(), Duration.EndOfTurn, FILTER, true)); this.addAbility(new ConditionalTriggeredAbility(ability, SurgedCondition.getInstance(), "When {this} enters the battlefield, if its surge cost was paid, other creatures you control get +1/+0 and gain haste until end of turn.")); - // Has to be placed last here, because added spellAbility objects (e.g. effects) have to be copied from this - // Surge {1}{R} (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn) - addAbility(new SurgeAbility(this, "{1}{R}")); } public RecklessBushwhacker(final RecklessBushwhacker card) { diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/ReflectorMage.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/ReflectorMage.java new file mode 100644 index 00000000000..c7b05e1e41d --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/ReflectorMage.java @@ -0,0 +1,172 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.turn.Step; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class ReflectorMage extends CardImpl { + + private final static FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + } + + public ReflectorMage(UUID ownerId) { + super(ownerId, 157, "Reflector Mage", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{W}{U}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Human"); + this.subtype.add("Wizard"); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // 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)); + this.addAbility(ability); + } + + public ReflectorMage(final ReflectorMage card) { + super(card); + } + + @Override + public ReflectorMage copy() { + return new ReflectorMage(this); + } +} + +class ReflectorMageEffect extends OneShotEffect { + + public ReflectorMageEffect() { + super(Outcome.Benefit); + this.staticText = "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"; + } + + public ReflectorMageEffect(final ReflectorMageEffect effect) { + super(effect); + } + + @Override + public ReflectorMageEffect copy() { + return new ReflectorMageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (targetCreature != null) { + controller.moveCards(targetCreature, Zone.HAND, source, game); + game.addEffect(new ExclusionRitualReplacementEffect(targetCreature.getName(), targetCreature.getOwnerId()), source); + } + return true; + } + return false; + } +} + +class ExclusionRitualReplacementEffect extends ContinuousRuleModifyingEffectImpl { + + private final String creatureName; + private final UUID ownerId; + + ExclusionRitualReplacementEffect(String creatureName, UUID ownerId) { + super(Duration.Custom, Outcome.Detriment); + staticText = "That creature's owner can't cast spells with the same name as that creature until your next turn"; + this.creatureName = creatureName; + this.ownerId = ownerId; + } + + ExclusionRitualReplacementEffect(final ExclusionRitualReplacementEffect effect) { + super(effect); + this.creatureName = effect.creatureName; + this.ownerId = effect.ownerId; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Card card = game.getCard(event.getSourceId()); + if (card != null) { + return card.getName().equals(creatureName); + } + return false; + } + + @Override + public boolean isInactive(Ability source, Game game) { + if (game.getPhase().getStep().getType() == PhaseStep.UNTAP && game.getStep().getStepPart() == Step.StepPart.PRE) { + if (game.getActivePlayerId().equals(source.getControllerId()) || game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving()) { + return true; + } + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public ExclusionRitualReplacementEffect copy() { + return new ExclusionRitualReplacementEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/ReliefCaptain.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/ReliefCaptain.java new file mode 100644 index 00000000000..f09f489951b --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/ReliefCaptain.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.keyword.SupportAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class ReliefCaptain extends CardImpl { + + public ReliefCaptain(UUID ownerId) { + super(ownerId, 32, "Relief Captain", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Kor"); + this.subtype.add("Knight"); + this.subtype.add("Ally"); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // When Relief Captain enters the battlefield, support 3. + this.addAbility(new SupportAbility(this, 3)); + } + + public ReliefCaptain(final ReliefCaptain card) { + super(card); + } + + @Override + public ReliefCaptain copy() { + return new ReliefCaptain(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/RoilingWaters.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/RoilingWaters.java new file mode 100644 index 00000000000..7b78a21f1f7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/RoilingWaters.java @@ -0,0 +1,78 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DrawCardTargetEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.target.TargetPlayer; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; + +/** + * + * @author LevelX2 + */ +public class RoilingWaters extends CardImpl { + + private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponents control"); + + static { + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + } + + public RoilingWaters(UUID ownerId) { + super(ownerId, 62, "Roiling Waters", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{5}{U}{U}"); + this.expansionSetCode = "OGW"; + + // Return up to two target creatures your opponents control to their owners' hands. + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2, filter, false)); + // Target player draws two cards. + Effect effect = new DrawCardTargetEffect(2); + effect.setTargetPointer(new SecondTargetPointer()); + getSpellAbility().addEffect(effect); + getSpellAbility().addTarget(new TargetPlayer()); + } + + public RoilingWaters(final RoilingWaters card) { + super(card); + } + + @Override + public RoilingWaters copy() { + return new RoilingWaters(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/RuinInTheirWake.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/RuinInTheirWake.java new file mode 100644 index 00000000000..03735bc69f7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/RuinInTheirWake.java @@ -0,0 +1,122 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterBasicLandCard; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author LevelX2 + */ +public class RuinInTheirWake extends CardImpl { + + public RuinInTheirWake(UUID ownerId) { + super(ownerId, 122, "Ruin in Their Wake", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{1}{G}"); + this.expansionSetCode = "OGW"; + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + // Search your library for a basic land card and reveal it. You may put that card onto the battlefield tapped if you control a land named Wastes. Otherwise, put that card into your hand. Then shuffle your library. + getSpellAbility().addEffect(new RuinInTheirWakeEffect()); + } + + public RuinInTheirWake(final RuinInTheirWake card) { + super(card); + } + + @Override + public RuinInTheirWake copy() { + return new RuinInTheirWake(this); + } +} + +class RuinInTheirWakeEffect extends OneShotEffect { + + private final static FilterLandPermanent filterWastes = new FilterLandPermanent(); + + static { + filterWastes.add(new NamePredicate("Wastes")); + } + + public RuinInTheirWakeEffect() { + super(Outcome.Benefit); + this.staticText = "Search your library for a basic land card and reveal it. You may put that card onto the battlefield tapped if you control a land named Wastes. Otherwise, put that card into your hand. Then shuffle your library"; + } + + public RuinInTheirWakeEffect(final RuinInTheirWakeEffect effect) { + super(effect); + } + + @Override + public RuinInTheirWakeEffect copy() { + return new RuinInTheirWakeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller != null && sourceObject != null) { + TargetCardInLibrary target = new TargetCardInLibrary(new FilterBasicLandCard()); + if (controller.searchLibrary(target, game)) { + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + Cards cardsToReveal = new CardsImpl(card); + controller.revealCards(sourceObject.getIdName(), cardsToReveal, game); + boolean controlWastes = game.getBattlefield().countAll(filterWastes, controller.getId(), game) > 0; + if (controlWastes && controller.chooseUse(outcome, "Put " + card.getLogName() + " onto battlefield tapped?", source, game)) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, true, null); + } else { + controller.moveCards(card, Zone.HAND, source, game); + } + } + } + controller.shuffleLibrary(game); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/RuinsOfOranRief.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/RuinsOfOranRief.java new file mode 100644 index 00000000000..a974099ac34 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/RuinsOfOranRief.java @@ -0,0 +1,83 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.mana.ColorlessManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorlessPredicate; +import mage.filter.predicate.permanent.EnteredThisTurnPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class RuinsOfOranRief extends CardImpl { + + private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("colorless creature that entered the battlefield this turn"); + + static { + filter.add(new ColorlessPredicate()); + filter.add(new EnteredThisTurnPredicate()); + } + + public RuinsOfOranRief(UUID ownerId) { + super(ownerId, 176, "Ruins of Oran-Rief", Rarity.RARE, new CardType[]{CardType.LAND}, ""); + this.expansionSetCode = "OGW"; + + // Ruins of Oran-Rief enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + // {T}: Add {C} to your mana pool. + this.addAbility(new ColorlessManaAbility()); + // {T}: Put a +1/+1 counter on target colorless creature that entered the battlefield this turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent(filter)); + + this.addAbility(ability); + } + + public RuinsOfOranRief(final RuinsOfOranRief card) { + super(card); + } + + @Override + public RuinsOfOranRief copy() { + return new RuinsOfOranRief(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/SaddlebackLagac.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/SaddlebackLagac.java new file mode 100644 index 00000000000..2654f8c0563 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/SaddlebackLagac.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.SupportEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class SaddlebackLagac extends CardImpl { + + private final static FilterCreaturePermanent FILTER = new FilterCreaturePermanent("target creatures"); + + static { + FILTER.add(new AnotherPredicate()); + } + + public SaddlebackLagac(UUID ownerId) { + super(ownerId, 142, "Saddleback Lagac", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{G}"); + this.expansionSetCode = "OGW"; + this.subtype.add("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)); + this.addAbility(ability); + + } + + public SaddlebackLagac(final SaddlebackLagac card) { + super(card); + } + + @Override + public SaddlebackLagac copy() { + return new SaddlebackLagac(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/SearingLight.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/SearingLight.java new file mode 100644 index 00000000000..84f83922dc7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/SearingLight.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import static mage.filter.Filter.ComparisonType.LessThan; +import mage.filter.common.FilterAttackingOrBlockingCreature; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class SearingLight extends CardImpl { + + private static final FilterAttackingOrBlockingCreature filter = new FilterAttackingOrBlockingCreature("attacking or blocking creature with power 2 or less"); + + static { + filter.add(new PowerPredicate(LessThan, 3)); + } + + public SearingLight(UUID ownerId) { + super(ownerId, 33, "Searing Light", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{W}"); + this.expansionSetCode = "OGW"; + + // Destroying target attacking or blocking creature with power 2 or less. + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + } + + public SearingLight(final SearingLight card) { + super(card); + } + + @Override + public SearingLight copy() { + return new SearingLight(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/SeedGuardian.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/SeedGuardian.java new file mode 100644 index 00000000000..0a201204be9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/SeedGuardian.java @@ -0,0 +1,115 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.filter.common.FilterCreatureCard; +import mage.game.Game; +import mage.game.permanent.token.Token; +import mage.players.Player; + +/** + * + * @author LevelX2 + */ +public class SeedGuardian extends CardImpl { + + public SeedGuardian(UUID ownerId) { + super(ownerId, 143, "Seed Guardian", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{G}{G}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Elemental"); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Reach + this.addAbility(ReachAbility.getInstance()); + // When Seed Guardian dies, put an X/X green Elemental creature token onto the battlefield, where X is the number of creature cards in your graveyard. + this.addAbility(new DiesTriggeredAbility(new SeedGuardianEffect(), false)); + } + + public SeedGuardian(final SeedGuardian card) { + super(card); + } + + @Override + public SeedGuardian copy() { + return new SeedGuardian(this); + } +} + +class SeedGuardianEffect extends OneShotEffect { + + public SeedGuardianEffect() { + super(Outcome.PutCreatureInPlay); + this.staticText = "put an X/X green Elemental creature token onto the battlefield, where X is the number of creature cards in your graveyard"; + } + + public SeedGuardianEffect(final SeedGuardianEffect effect) { + super(effect); + } + + @Override + public SeedGuardianEffect copy() { + return new SeedGuardianEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + int creaturesInGraveyard = controller.getGraveyard().count(new FilterCreatureCard(), game); + return new CreateTokenEffect(new SeedGuardianToken(creaturesInGraveyard)).apply(game, source); + } + return false; + } +} + +class SeedGuardianToken extends Token { + + public SeedGuardianToken(int xValue) { + super("Elemental", "X/X green Elemental creature token"); + setTokenType(2); + setOriginalExpansionSetCode("OGW"); + cardType.add(CardType.CREATURE); + color.setGreen(true); + subtype.add("Elemental"); + power = new MageInt(xValue); + toughness = new MageInt(xValue); + + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/SeersLantern.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/SeersLantern.java new file mode 100644 index 00000000000..0a1cd543647 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/SeersLantern.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.mana.ColorlessManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author fireshoes + */ +public class SeersLantern extends CardImpl { + + public SeersLantern(UUID ownerId) { + super(ownerId, 165, "Seer's Lantern", Rarity.COMMON, new CardType[]{CardType.ARTIFACT}, "{3}"); + this.expansionSetCode = "OGW"; + + // {T}: Add {C} to your mana pool. + this.addAbility(new ColorlessManaAbility()); + + // {2}, {T}: Scry 1. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ScryEffect(1), new GenericManaCost(2)); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + public SeersLantern(final SeersLantern card) { + super(card); + } + + @Override + public SeersLantern copy() { + return new SeersLantern(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/ShoulderToShoulder.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/ShoulderToShoulder.java index ceda4b5720e..c8c2701cda4 100644 --- a/Mage.Sets/src/mage/sets/oathofthegatewatch/ShoulderToShoulder.java +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/ShoulderToShoulder.java @@ -45,7 +45,7 @@ public class ShoulderToShoulder extends CardImpl { this.expansionSetCode = "OGW"; // Support 2. - getSpellAbility().addEffect(new SupportEffect(this, 2)); + getSpellAbility().addEffect(new SupportEffect(this, 2, false)); // Draw a card. getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/SifterOfSkulls.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/SifterOfSkulls.java new file mode 100644 index 00000000000..b3cb29160f2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/SifterOfSkulls.java @@ -0,0 +1,85 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.permanent.token.EldraziScionToken; + +/** + * + * @author fireshoes + */ +public class SifterOfSkulls extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another nontoken creature you control"); + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + filter.add(new AnotherPredicate()); + filter.add(Predicates.not(new TokenPredicate())); + } + + public SifterOfSkulls(UUID ownerId) { + super(ownerId, 77, "Sifter of Skulls", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // Whenever another nontoken creature you control dies, put a 1/1 colorless Eldrazi Scion creature token onto the battlefield. + // It has "Sacrifice this creature: Add {C} to your mana pool." + Effect effect = new CreateTokenEffect(new EldraziScionToken()); + effect.setText("put a 1/1 colorless Eldrazi Scion creature token onto the battlefield. It has \"Sacrifice this creature: Add {C} to your mana pool.\""); + this.addAbility(new DiesCreatureTriggeredAbility(effect, false, filter)); + } + + public SifterOfSkulls(final SifterOfSkulls card) { + super(card); + } + + @Override + public SifterOfSkulls copy() { + return new SifterOfSkulls(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/SkyScourer.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/SkyScourer.java new file mode 100644 index 00000000000..fc641a21058 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/SkyScourer.java @@ -0,0 +1,80 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.ColorlessPredicate; + +/** + * + * @author LevelX2 + */ +public class SkyScourer extends CardImpl { + + private static final FilterSpell filterSpell = new FilterSpell("a colorless spell"); + + static { + filterSpell.add(new ColorlessPredicate()); + } + + public SkyScourer(UUID ownerId) { + super(ownerId, 78, "Sky Scourer", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{B}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.subtype.add("Drone"); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + // Flying + this.addAbility(FlyingAbility.getInstance()); + // Whenever you cast a colorless spell, Sky Scourer gets +1/+0 until end of turn. + this.addAbility(new SpellCastControllerTriggeredAbility(new BoostSourceEffect(1, 0, Duration.EndOfTurn), filterSpell, false)); + + } + + public SkyScourer(final SkyScourer card) { + super(card); + } + + @Override + public SkyScourer copy() { + return new SkyScourer(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/SlaughterDrone.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/SlaughterDrone.java new file mode 100644 index 00000000000..ee0e3324d42 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/SlaughterDrone.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LevelX2 + */ +public class SlaughterDrone extends CardImpl { + + public SlaughterDrone(UUID ownerId) { + super(ownerId, 79, "Slaughter Drone", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{B}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.subtype.add("Drone"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + // {C}: Slaughter Drone gains deathtouch until end of turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilitySourceEffect(DeathtouchAbility.getInstance(), Duration.EndOfTurn), + new ManaCostsImpl<>("{C}"))); + + } + + public SlaughterDrone(final SlaughterDrone card) { + super(card); + } + + @Override + public SlaughterDrone copy() { + return new SlaughterDrone(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/SlipThroughSpace.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/SlipThroughSpace.java new file mode 100644 index 00000000000..8c8ef618bfb --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/SlipThroughSpace.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class SlipThroughSpace extends CardImpl { + + public SlipThroughSpace(UUID ownerId) { + super(ownerId, 47, "Slip Through Space", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{U}"); + this.expansionSetCode = "OGW"; + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // Target creature can't be blocked this turn. + this.getSpellAbility().addEffect(new CantBeBlockedTargetEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + } + + public SlipThroughSpace(final SlipThroughSpace card) { + super(card); + } + + @Override + public SlipThroughSpace copy() { + return new SlipThroughSpace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/SparkmagesGambit.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/SparkmagesGambit.java new file mode 100644 index 00000000000..436f1718460 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/SparkmagesGambit.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.combat.CantBlockTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class SparkmagesGambit extends CardImpl { + + public SparkmagesGambit(UUID ownerId) { + super(ownerId, 117, "Sparkmage's Gambit", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{1}{R}"); + this.expansionSetCode = "OGW"; + + // Sparkmage's Gambit deals 1 damage to each of up to two target creatures. Those creatures can't block this turn. + Effect effect = new DamageTargetEffect(1); + effect.setText("{this} deals 1 damage to each of up to two target creatures"); + this.getSpellAbility().addEffect(effect); + effect = new CantBlockTargetEffect(Duration.EndOfTurn); + effect.setText("Those creatures can't block this turn"); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2)); + } + + public SparkmagesGambit(final SparkmagesGambit card) { + super(card); + } + + @Override + public SparkmagesGambit copy() { + return new SparkmagesGambit(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/SpawnbinderMage.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/SpawnbinderMage.java new file mode 100644 index 00000000000..e5e6b268cce --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/SpawnbinderMage.java @@ -0,0 +1,87 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +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.common.TapTargetCost; +import mage.abilities.effects.common.TapTargetEffect; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class SpawnbinderMage extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("an untapped Ally you control"); + + static { + filter.add(new SubtypePredicate("Ally")); + filter.add(Predicates.not(new TappedPredicate())); + } + + public SpawnbinderMage(UUID ownerId) { + super(ownerId, 35, "Spawnbinder Mage", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{W}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Human"); + this.subtype.add("Wizard"); + this.subtype.add("Ally"); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Cohort — {T}, Tap an untapped Ally you control: Tap target creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), new TapSourceCost()); + ability.addCost(new TapTargetCost(new TargetControlledPermanent(filter))); + ability.addTarget(new TargetCreaturePermanent()); + ability.setAbilityWord(AbilityWord.COHORT); + this.addAbility(ability); + } + + public SpawnbinderMage(final SpawnbinderMage card) { + super(card); + } + + @Override + public SpawnbinderMage copy() { + return new SpawnbinderMage(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/StalkingDrone.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/StalkingDrone.java new file mode 100644 index 00000000000..97091bcb5a0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/StalkingDrone.java @@ -0,0 +1,70 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LevelX2 + */ +public class StalkingDrone extends CardImpl { + + public StalkingDrone(UUID ownerId) { + super(ownerId, 124, "Stalking Drone", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{G}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.subtype.add("Drone"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + // {C}: Stalking Drone gets +1/+2 until end of turn. Activate this ability only once each turn. + this.addAbility(new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 2, Duration.EndOfTurn), new ManaCostsImpl("{C}"))); + } + + public StalkingDrone(final StalkingDrone card) { + super(card); + } + + @Override + public StalkingDrone copy() { + return new StalkingDrone(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/SteppeGlider.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/SteppeGlider.java new file mode 100644 index 00000000000..bd69cd042b4 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/SteppeGlider.java @@ -0,0 +1,93 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +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.effects.Effect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.CounterPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class SteppeGlider extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature with a +1/+1 counter on it"); + + static { + filter.add(new CounterPredicate(CounterType.P1P1)); + } + + public SteppeGlider(UUID ownerId) { + super(ownerId, 36, "Steppe Glider", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{4}{W}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Elemental"); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // {1}{W}: Target creature with a +1/+1 counter on it gains flying and vigilance until end of turn. + Effect effect = new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn); + effect.setText("Target creature with a +1/+1 counter on it gains flying"); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{1}{W}")); + effect = new GainAbilityTargetEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn); + effect.setText("and vigilance until end of turn"); + ability.addEffect(effect); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public SteppeGlider(final SteppeGlider card) { + super(card); + } + + @Override + public SteppeGlider copy() { + return new SteppeGlider(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/StoneHavenOutfitter.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/StoneHavenOutfitter.java new file mode 100644 index 00000000000..31db6ad4a2f --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/StoneHavenOutfitter.java @@ -0,0 +1,80 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.EquippedPredicate; + +/** + * + * @author LevelX2 + */ +public class StoneHavenOutfitter extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("equipped creatures"); + + static { + filter.add(new EquippedPredicate()); + } + + public StoneHavenOutfitter(UUID ownerId) { + super(ownerId, 37, "Stone Haven Outfitter", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{W}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Kor"); + this.subtype.add("Artificer"); + this.subtype.add("Ally"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Equipped creatures you control get +1/+1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, filter, false))); + + // Whenever an equipped creature you control dies, draw a card. + this.addAbility(new DiesCreatureTriggeredAbility(new DrawCardSourceControllerEffect(1), false, filter)); + } + + public StoneHavenOutfitter(final StoneHavenOutfitter card) { + super(card); + } + + @Override + public StoneHavenOutfitter copy() { + return new StoneHavenOutfitter(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/StoneforgeAcolyte.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/StoneforgeAcolyte.java new file mode 100644 index 00000000000..51456c16c8e --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/StoneforgeAcolyte.java @@ -0,0 +1,92 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +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.common.TapTargetCost; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author fireshoes + */ +public class StoneforgeAcolyte extends CardImpl { + + private static final FilterControlledPermanent filterAlly = new FilterControlledPermanent("an untapped Ally you control"); + private static final FilterCard filterEquipment = new FilterCard("an Equipment card"); + + static { + filterAlly.add(new SubtypePredicate("Ally")); + filterAlly.add(Predicates.not(new TappedPredicate())); + filterEquipment.add(new SubtypePredicate("Equipment")); + } + + public StoneforgeAcolyte(UUID ownerId) { + super(ownerId, 38, "Stoneforge Acolyte", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{W}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Kor"); + this.subtype.add("Artificer"); + this.subtype.add("Ally"); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Cohort — {T}, Tap an untapped Ally you control: Look at the top four cards of your library. + // You may reveal an Equipment card from among them and put it into your hand. Put the rest on the bottom of your library in any order. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new LookLibraryAndPickControllerEffect(new StaticValue(4), false, new StaticValue(1), filterEquipment, false), + new TapSourceCost()); + ability.addCost(new TapTargetCost(new TargetControlledPermanent(filterAlly))); + ability.setAbilityWord(AbilityWord.COHORT); + this.addAbility(ability); + } + + public StoneforgeAcolyte(final StoneforgeAcolyte card) { + super(card); + } + + @Override + public StoneforgeAcolyte copy() { + return new StoneforgeAcolyte(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/StoneforgeMasterwork.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/StoneforgeMasterwork.java new file mode 100644 index 00000000000..6f07a4d6935 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/StoneforgeMasterwork.java @@ -0,0 +1,113 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.util.CardUtil; + +/** + * + * @author LevelX2 + */ +public class StoneforgeMasterwork extends CardImpl { + + public StoneforgeMasterwork(UUID ownerId) { + super(ownerId, 166, "Stoneforge Masterwork", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{1}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Equipment"); + + // Equipped creature gets +1/+1 for each other creature you control that shares a creature type with it. + StoneforgeMasterworkDynamicValue countEnchantments = new StoneforgeMasterworkDynamicValue(); + Effect effect = new BoostEquippedEffect(countEnchantments, countEnchantments); + effect.setText("Equipped creature gets +1/+1 for each other creature you control that shares a creature type with it"); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + // Equip {2} + this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(2))); + } + + public StoneforgeMasterwork(final StoneforgeMasterwork card) { + super(card); + } + + @Override + public StoneforgeMasterwork copy() { + return new StoneforgeMasterwork(this); + } +} + +class StoneforgeMasterworkDynamicValue implements DynamicValue { + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Permanent equipment = game.getPermanent(sourceAbility.getSourceId()); + int xValue = 0; + if (equipment != null && equipment.getAttachedTo() != null) { + Permanent equipped = game.getPermanent(equipment.getAttachedTo()); + if (equipped != null) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), sourceAbility.getControllerId(), game)) { + if (!permanent.getId().equals(equipped.getId())) { + if (CardUtil.shareSubtypes(equipped, permanent)) { + xValue++; + } + } + } + } + } + return xValue; + } + + @Override + public StoneforgeMasterworkDynamicValue copy() { + return new StoneforgeMasterworkDynamicValue(); + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return "other creature you control that shares a creature type with it"; + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/StormchaserMage.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/StormchaserMage.java new file mode 100644 index 00000000000..152141edf93 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/StormchaserMage.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.ProwessAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class StormchaserMage extends CardImpl { + + public StormchaserMage(UUID ownerId) { + super(ownerId, 159, "Stormchaser Mage", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{U}{R}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Human"); + this.subtype.add("Wizard"); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // Haste + this.addAbility(HasteAbility.getInstance()); + // Prowess + this.addAbility(new ProwessAbility()); + } + + public StormchaserMage(final StormchaserMage card) { + super(card); + } + + @Override + public StormchaserMage copy() { + return new StormchaserMage(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/StriderHarness.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/StriderHarness.java new file mode 100644 index 00000000000..ba35ddc0939 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/StriderHarness.java @@ -0,0 +1,54 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class StriderHarness extends mage.sets.scarsofmirrodin.StriderHarness { + + public StriderHarness(UUID ownerId) { + super(ownerId); + this.cardNumber = 167; + this.expansionSetCode = "OGW"; + this.rarity = Rarity.UNCOMMON; + } + + public StriderHarness(final StriderHarness card) { + super(card); + } + + @Override + public StriderHarness copy() { + return new StriderHarness(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/SubmergedBoneyard.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/SubmergedBoneyard.java new file mode 100644 index 00000000000..76699867e0d --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/SubmergedBoneyard.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class SubmergedBoneyard extends CardImpl { + + public SubmergedBoneyard(UUID ownerId) { + super(ownerId, 178, "Submerged Boneyard", Rarity.UNCOMMON, new CardType[]{CardType.LAND}, ""); + this.expansionSetCode = "OGW"; + + // Submerged Boneyard enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {U} or {B} to your mana pool. + this.addAbility(new BlueManaAbility()); + this.addAbility(new BlackManaAbility()); + } + + public SubmergedBoneyard(final SubmergedBoneyard card) { + super(card); + } + + @Override + public SubmergedBoneyard copy() { + return new SubmergedBoneyard(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/SweepAway.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/SweepAway.java new file mode 100644 index 00000000000..050687c16fe --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/SweepAway.java @@ -0,0 +1,101 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class SweepAway extends CardImpl { + + public SweepAway(UUID ownerId) { + super(ownerId, 64, "Sweep Away", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{2}{U}"); + this.expansionSetCode = "OGW"; + + // Return target creature to its owner's hand. If that creature is attacking, you may put it on top of its owner's library instead. + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addEffect(new SweepAwayEffect()); + } + + public SweepAway(final SweepAway card) { + super(card); + } + + @Override + public SweepAway copy() { + return new SweepAway(this); + } +} + +class SweepAwayEffect extends OneShotEffect { + + public SweepAwayEffect() { + super(Outcome.Benefit); + staticText = "Return target creature to its owner's hand. If that creature is attacking, you may put it on top of its owner's library instead"; + } + + public SweepAwayEffect(final SweepAwayEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); + if (permanent != null && controller != null) { + if (permanent.isAttacking()) { + if (controller.chooseUse(Outcome.Neutral, "Put " + permanent.getIdName() + " on top of its owner's library (otherwise return to hand)?", source, game)) { + new PutOnLibraryTargetEffect(true).apply(game, source); + } + } else { + new ReturnToHandTargetEffect(true).apply(game, source); + } + return true; + } + return false; + } + + @Override + public SweepAwayEffect copy() { + return new SweepAwayEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/SylvanAdvocate.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/SylvanAdvocate.java new file mode 100644 index 00000000000..e06552a0b33 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/SylvanAdvocate.java @@ -0,0 +1,93 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition.CountType; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.CardTypePredicate; + +/** + * + * @author fireshoes + */ +public class SylvanAdvocate extends CardImpl { + + private static final String rule1 = "As long as you control six or more lands, {this}"; + private static final String rule2 = "and land creatures you control get +2/+2."; + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("land creatures"); + + static { + filter.add(new CardTypePredicate(CardType.LAND)); + } + + public SylvanAdvocate(UUID ownerId) { + super(ownerId, 144, "Sylvan Advocate", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{G}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Elf"); + this.subtype.add("Druid"); + this.subtype.add("Ally"); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // As long as you control six or more lands, Sylvan Advocate and land creatures you control get +2/+2. + ConditionalContinuousEffect effect1 = new ConditionalContinuousEffect(new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), + new PermanentsOnTheBattlefieldCondition(new FilterControlledLandPermanent(), CountType.MORE_THAN, 5), rule1); + ConditionalContinuousEffect effect2 = new ConditionalContinuousEffect(new BoostControlledEffect(2, 2, Duration.WhileOnBattlefield, filter, true), + new PermanentsOnTheBattlefieldCondition(new FilterControlledLandPermanent(), CountType.MORE_THAN, 5), rule2); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect1); + ability.addEffect(effect2); + this.addAbility(ability); + } + + public SylvanAdvocate(final SylvanAdvocate card) { + super(card); + } + + @Override + public SylvanAdvocate copy() { + return new SylvanAdvocate(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/TajuruPathwarden.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/TajuruPathwarden.java new file mode 100644 index 00000000000..9fbb6a89e0e --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/TajuruPathwarden.java @@ -0,0 +1,67 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class TajuruPathwarden extends CardImpl { + + public TajuruPathwarden(UUID ownerId) { + super(ownerId, 145, "Tajuru Pathwarden", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{G}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Elf"); + this.subtype.add("Warrior"); + this.subtype.add("Ally"); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + // Trample + this.addAbility(TrampleAbility.getInstance()); + } + + public TajuruPathwarden(final TajuruPathwarden card) { + super(card); + } + + @Override + public TajuruPathwarden copy() { + return new TajuruPathwarden(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/TarSnare.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/TarSnare.java new file mode 100644 index 00000000000..7bc5011a0c7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/TarSnare.java @@ -0,0 +1,61 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class TarSnare extends CardImpl { + + public TarSnare(UUID ownerId) { + super(ownerId, 90, "Tar Snare", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{2}{B}"); + this.expansionSetCode = "OGW"; + + // Target creature gets -3/-2 until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(-3, -2, Duration.EndOfTurn)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public TarSnare(final TarSnare card) { + super(card); + } + + @Override + public TarSnare copy() { + return new TarSnare(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/TearsOfValakut.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/TearsOfValakut.java new file mode 100644 index 00000000000..e22fd6a9c32 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/TearsOfValakut.java @@ -0,0 +1,81 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CantBeCounteredSourceEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class TearsOfValakut extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + + public TearsOfValakut(UUID ownerId) { + super(ownerId, 118, "Tears of Valakut", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{1}{R}"); + this.expansionSetCode = "OGW"; + + // Tears of Valakut can't be countered by spells or abilities. + Effect effect = new CantBeCounteredSourceEffect(); + effect.setText("{this} can't be countered by spells or abilities"); + Ability ability = new SimpleStaticAbility(Zone.STACK, effect); + ability.setRuleAtTheTop(true); + this.addAbility(ability); + + // Tears of Valakut deals 5 damage to target creature with flying. + this.getSpellAbility().addEffect(new DamageTargetEffect(5)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + } + + public TearsOfValakut(final TearsOfValakut card) { + super(card); + } + + @Override + public TearsOfValakut copy() { + return new TearsOfValakut(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/ThoughtHarvester.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/ThoughtHarvester.java new file mode 100644 index 00000000000..12d409cee3f --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/ThoughtHarvester.java @@ -0,0 +1,84 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.ExileCardsFromTopOfLibraryTargetEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.ColorlessPredicate; +import mage.target.common.TargetOpponent; + +/** + * + * @author fireshoes + */ +public class ThoughtHarvester extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a colorless spell"); + + static { + filter.add(new ColorlessPredicate()); + } + + public ThoughtHarvester(UUID ownerId) { + super(ownerId, 48, "Thought Harvester", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{U}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.subtype.add("Drone"); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever you cast a colorless spell, target opponent exiles the top card of his or her library. + Ability ability = new SpellCastControllerTriggeredAbility(new ExileCardsFromTopOfLibraryTargetEffect(1, "target opponent"), filter, false); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + public ThoughtHarvester(final ThoughtHarvester card) { + super(card); + } + + @Override + public ThoughtHarvester copy() { + return new ThoughtHarvester(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/ThoughtKnotSeer.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/ThoughtKnotSeer.java new file mode 100644 index 00000000000..b11b41e287e --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/ThoughtKnotSeer.java @@ -0,0 +1,83 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DrawCardTargetEffect; +import mage.abilities.effects.common.ExileCardYouChooseTargetOpponentEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.target.common.TargetOpponent; + +/** + * + * @author fireshoes + */ +public class ThoughtKnotSeer extends CardImpl { + + private static final FilterCard filter = new FilterCard("a nonland card"); + + static { + filter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); + } + + public ThoughtKnotSeer(UUID ownerId) { + super(ownerId, 9, "Thought-Knot Seer", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{C}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // When Thought-Knot Seer enters the battlefield, target opponent reveals his or her hand. You choose a nonland card from it and exile that card. + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileCardYouChooseTargetOpponentEffect(filter), false); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + + // When Thought-Knot Seer leaves the battlefield, target opponent draws a card. + ability = new LeavesBattlefieldTriggeredAbility(new DrawCardTargetEffect(1), false); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + public ThoughtKnotSeer(final ThoughtKnotSeer card) { + super(card); + } + + @Override + public ThoughtKnotSeer copy() { + return new ThoughtKnotSeer(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/TimberGorge.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/TimberGorge.java new file mode 100644 index 00000000000..0ee584e7d17 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/TimberGorge.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.RedManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class TimberGorge extends CardImpl { + + public TimberGorge(UUID ownerId) { + super(ownerId, 179, "Timber Gorge", Rarity.UNCOMMON, new CardType[]{CardType.LAND}, ""); + this.expansionSetCode = "OGW"; + + // Timber Gorge enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {R} or {G} to your mana pool. + this.addAbility(new RedManaAbility()); + this.addAbility(new GreenManaAbility()); + } + + public TimberGorge(final TimberGorge card) { + super(card); + } + + @Override + public TimberGorge copy() { + return new TimberGorge(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/UmaraEntangler.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/UmaraEntangler.java new file mode 100644 index 00000000000..00dcf898d46 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/UmaraEntangler.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.keyword.ProwessAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class UmaraEntangler extends CardImpl { + + public UmaraEntangler(UUID ownerId) { + super(ownerId, 65, "Umara Entangler", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{U}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Merfolk"); + this.subtype.add("Rogue"); + this.subtype.add("Ally"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Prowess + this.addAbility(new ProwessAbility()); + } + + public UmaraEntangler(final UmaraEntangler card) { + super(card); + } + + @Override + public UmaraEntangler copy() { + return new UmaraEntangler(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/UnityOfPurpose.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/UnityOfPurpose.java new file mode 100644 index 00000000000..0b3b74d9350 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/UnityOfPurpose.java @@ -0,0 +1,71 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.common.UntapAllControllerEffect; +import mage.abilities.effects.keyword.SupportEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.CounterPredicate; + +/** + * + * @author fireshoes + */ +public class UnityOfPurpose extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("each creature you control with a +1/+1 counter on it"); + + static { + filter.add(new CounterPredicate(CounterType.P1P1)); + } + + public UnityOfPurpose(UUID ownerId) { + super(ownerId, 66, "Unity of Purpose", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{3}{U}"); + this.expansionSetCode = "OGW"; + + // Support 2. + getSpellAbility().addEffect(new SupportEffect(this, 2, false)); + + // Untap each creature you control with a +1/+1 counter on it. + this.getSpellAbility().addEffect(new UntapAllControllerEffect(filter, "Untap each creature you control with a +1/+1 counter on it")); + } + + public UnityOfPurpose(final UnityOfPurpose card) { + super(card); + } + + @Override + public UnityOfPurpose copy() { + return new UnityOfPurpose(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/UnnaturalEndurance.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/UnnaturalEndurance.java new file mode 100644 index 00000000000..89d25d2850b --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/UnnaturalEndurance.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.RegenerateTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class UnnaturalEndurance extends CardImpl { + + public UnnaturalEndurance(UUID ownerId) { + super(ownerId, 80, "Unnatural Endurance", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{B}"); + this.expansionSetCode = "OGW"; + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + // Target creature gets +2/+0 until end of turn. Regenerate it. + this.getSpellAbility().addEffect(new BoostTargetEffect(2, 0, Duration.EndOfTurn)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + Effect effect = new RegenerateTargetEffect(); + effect.setText("Regenerate it"); + this.getSpellAbility().addEffect(effect); + } + + public UnnaturalEndurance(final UnnaturalEndurance card) { + super(card); + } + + @Override + public UnnaturalEndurance copy() { + return new UnnaturalEndurance(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/UntamedHunger.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/UntamedHunger.java new file mode 100644 index 00000000000..52bb9207534 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/UntamedHunger.java @@ -0,0 +1,82 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class UntamedHunger extends CardImpl { + + public UntamedHunger(UUID ownerId) { + super(ownerId, 91, "Untamed Hunger", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature gets +2/+1 and has menace. + ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, 1)); + Effect effect = new GainAbilityAttachedEffect(new MenaceAbility(), AttachmentType.AURA); + effect.setText("and has menace"); + ability.addEffect(effect); + this.addAbility(ability); + } + + public UntamedHunger(final UntamedHunger card) { + super(card); + } + + @Override + public UntamedHunger copy() { + return new UntamedHunger(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/VampireEnvoy.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/VampireEnvoy.java new file mode 100644 index 00000000000..39dc5fa0cc5 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/VampireEnvoy.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.BecomesTappedSourceTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author LevelX2 + */ +public class VampireEnvoy extends CardImpl { + + public VampireEnvoy(UUID ownerId) { + super(ownerId, 92, "Vampire Envoy", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Vampire"); + this.subtype.add("Cleric"); + this.subtype.add("Ally"); + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Vampire Envoy becomes tapped, you gain 1 life. + this.addAbility(new BecomesTappedSourceTriggeredAbility(new GainLifeEffect(1))); + } + + public VampireEnvoy(final VampireEnvoy card) { + super(card); + } + + @Override + public VampireEnvoy copy() { + return new VampireEnvoy(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/VileRedeemer.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/VileRedeemer.java new file mode 100644 index 00000000000..0b8814de591 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/VileRedeemer.java @@ -0,0 +1,160 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.HashMap; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CastSourceTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.keyword.DevoidAbility; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.PermanentToken; +import mage.game.permanent.token.EldraziScionToken; +import mage.players.Player; +import mage.watchers.Watcher; + +/** + * + * @author LevelX2 + */ +public class VileRedeemer extends CardImpl { + + public VileRedeemer(UUID ownerId) { + super(ownerId, 125, "Vile Redeemer", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{G}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + // Flash + this.addAbility(FlashAbility.getInstance()); + // When you cast Vile Redeemer, you may pay {C}. If you do put a 1/1 colorless Eldrazi Scion creature token onto the battlefield for each nontoken creature that died under your control this turn. They have "Sacrifice this creature: Add {C} to your mana pool." + this.addAbility( + new CastSourceTriggeredAbility(new DoIfCostPaid(new VileRedeemerEffect(), new ManaCostsImpl("{C}"), "Pay {C} to put 1/1 colorless Eldrazi Scion creature tokens onto the battlefield?"), false), + new VileRedeemerNonTokenCreaturesDiedWatcher()); + } + + public VileRedeemer(final VileRedeemer card) { + super(card); + } + + @Override + public VileRedeemer copy() { + return new VileRedeemer(this); + } +} + +class VileRedeemerEffect extends OneShotEffect { + + public VileRedeemerEffect() { + super(Outcome.PutCreatureInPlay); + this.staticText = "put a 1/1 colorless Eldrazi Scion creature token onto the battlefield for each nontoken creature that died under your control this turn. They have \"Sacrifice this creature: Add {C} to your mana pool"; + } + + public VileRedeemerEffect(final VileRedeemerEffect effect) { + super(effect); + } + + @Override + public VileRedeemerEffect copy() { + return new VileRedeemerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + VileRedeemerNonTokenCreaturesDiedWatcher watcher = (VileRedeemerNonTokenCreaturesDiedWatcher) game.getState().getWatchers().get("VileRedeemerNonTokenCreaturesDiedWatcher"); + if (watcher != null) { + int amount = watcher.getAmountOfNontokenCreatureDiedThisTurn(controller.getId()); + if (amount > 0) { + return new CreateTokenEffect(new EldraziScionToken(), amount).apply(game, source); + } + } + return true; + } + return false; + } +} + +class VileRedeemerNonTokenCreaturesDiedWatcher extends Watcher { + + private final HashMap amountOfCreaturesThatDied = new HashMap<>(); + + public VileRedeemerNonTokenCreaturesDiedWatcher() { + super("VileRedeemerNonTokenCreaturesDiedWatcher", WatcherScope.GAME); + } + + public VileRedeemerNonTokenCreaturesDiedWatcher(final VileRedeemerNonTokenCreaturesDiedWatcher watcher) { + super(watcher); + this.amountOfCreaturesThatDied.putAll(watcher.amountOfCreaturesThatDied); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ZONE_CHANGE) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.isDiesEvent() && zEvent.getTarget() != null + && zEvent.getTarget().getCardType().contains(CardType.CREATURE) + && !(zEvent.getTarget() instanceof PermanentToken)) { + int count = amountOfCreaturesThatDied.containsKey(zEvent.getTarget().getControllerId()) ? amountOfCreaturesThatDied.get(zEvent.getTarget().getControllerId()) : 0; + amountOfCreaturesThatDied.put(zEvent.getTarget().getControllerId(), ++count); + } + } + } + + @Override + public void reset() { + amountOfCreaturesThatDied.clear(); + } + + public int getAmountOfNontokenCreatureDiedThisTurn(UUID playerId) { + return amountOfCreaturesThatDied.containsKey(playerId) ? amountOfCreaturesThatDied.get(playerId) : 0; + } + + @Override + public VileRedeemerNonTokenCreaturesDiedWatcher copy() { + return new VileRedeemerNonTokenCreaturesDiedWatcher(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/VinesOfTheRecluse.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/VinesOfTheRecluse.java new file mode 100644 index 00000000000..d38f34e5b86 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/VinesOfTheRecluse.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class VinesOfTheRecluse extends CardImpl { + + public VinesOfTheRecluse(UUID ownerId) { + super(ownerId, 146, "Vines of the Recluse", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{G}"); + this.expansionSetCode = "OGW"; + + // Target creature gets +1/+2 and gains reach until end of turn. + Effect effect = new BoostTargetEffect(1, 2, Duration.EndOfTurn); + effect.setText("Target creature gets +1/+2"); + this.getSpellAbility().addEffect(effect); + effect = new GainAbilityTargetEffect(ReachAbility.getInstance(), Duration.EndOfTurn); + effect.setText("and gains reach until end of turn"); + this.getSpellAbility().addEffect(effect); + // Untap it. + effect = new UntapTargetEffect(); + effect.setText("untap it"); + this.getSpellAbility().addEffect(effect); + + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + } + + public VinesOfTheRecluse(final VinesOfTheRecluse card) { + super(card); + } + + @Override + public VinesOfTheRecluse copy() { + return new VinesOfTheRecluse(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/VisionsOfBrutality.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/VisionsOfBrutality.java new file mode 100644 index 00000000000..81e6c705146 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/VisionsOfBrutality.java @@ -0,0 +1,125 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageAttachedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.combat.CantBlockAttachedEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class VisionsOfBrutality extends CardImpl { + + public VisionsOfBrutality(UUID ownerId) { + super(ownerId, 81, "Visions of Brutality", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Aura"); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature can't block. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBlockAttachedEffect(AttachmentType.AURA))); + + // Whenever enchanted creature deals damage, its controller loses that much life. + this.addAbility(new DealsDamageAttachedTriggeredAbility(Zone.BATTLEFIELD, new VisionsOfBrutalityEffect(), false)); + } + + public VisionsOfBrutality(final VisionsOfBrutality card) { + super(card); + } + + @Override + public VisionsOfBrutality copy() { + return new VisionsOfBrutality(this); + } +} + +class VisionsOfBrutalityEffect extends OneShotEffect { + + public VisionsOfBrutalityEffect() { + super(Outcome.Benefit); + this.staticText = "its controller loses that much life"; + } + + public VisionsOfBrutalityEffect(final VisionsOfBrutalityEffect effect) { + super(effect); + } + + @Override + public VisionsOfBrutalityEffect copy() { + return new VisionsOfBrutalityEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Permanent enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (enchantment != null && enchantment.getAttachedTo() != null) { + Permanent enchanted = game.getPermanentOrLKIBattlefield(enchantment.getAttachedTo()); + if (enchanted != null) { + Player controllerEnchanted = game.getPlayer(enchanted.getControllerId()); + if (controllerEnchanted != null) { + int damage = (Integer) getValue("damage"); + if (damage > 0) { + controllerEnchanted.loseLife(damage, game); + } + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/VoidGrafter.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/VoidGrafter.java new file mode 100644 index 00000000000..e4384dcfc89 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/VoidGrafter.java @@ -0,0 +1,86 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.HexproofAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class VoidGrafter extends CardImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature you control"); + + static { + filter.add(new AnotherPredicate()); + } + + public VoidGrafter(UUID ownerId) { + super(ownerId, 150, "Void Grafter", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{G}{U}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.subtype.add("Drone"); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // Flash + 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(filter)); + this.addAbility(ability); + } + + public VoidGrafter(final VoidGrafter card) { + super(card); + } + + @Override + public VoidGrafter copy() { + return new VoidGrafter(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/VoidShatter.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/VoidShatter.java new file mode 100644 index 00000000000..b937b5f410f --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/VoidShatter.java @@ -0,0 +1,65 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.common.CounterTargetWithReplacementEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetSpell; + +/** + * + * @author fireshoes + */ +public class VoidShatter extends CardImpl { + + public VoidShatter(UUID ownerId) { + super(ownerId, 49, "Void Shatter", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{1}{U}{U}"); + this.expansionSetCode = "OGW"; + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + + // Counter target spell. If that spell is countered this way, exile it instead of putting it into its owner's graveyard. + this.getSpellAbility().addEffect(new CounterTargetWithReplacementEffect(Zone.EXILED)); + this.getSpellAbility().addTarget(new TargetSpell()); + } + + public VoidShatter(final VoidShatter card) { + super(card); + } + + @Override + public VoidShatter copy() { + return new VoidShatter(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/WallOfResurgence.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/WallOfResurgence.java new file mode 100644 index 00000000000..4316f9e5e46 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/WallOfResurgence.java @@ -0,0 +1,94 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.counters.CounterType; +import mage.filter.common.FilterControlledLandPermanent; +import mage.game.permanent.token.Token; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author LevelX2 + */ +public class WallOfResurgence extends CardImpl { + + public WallOfResurgence(UUID ownerId) { + super(ownerId, 39, "Wall of Resurgence", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{W}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Wall"); + this.power = new MageInt(0); + this.toughness = new MageInt(6); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + // When Wall of Resurgence enters the battlefield, you may put three +1/+1 counters on target land you control. If you do, that land becomes a 0/0 Elemental creature with haste that's still a land. + Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance(3)), true); + Effect effect = new BecomesCreatureTargetEffect(new WallOfResurgenceToken(), false, true, Duration.Custom); + effect.setText("If you do, that land becomes a 0/0 Elemental creature with haste that's still a land"); + ability.addEffect(effect); + ability.addTarget(new TargetControlledPermanent(new FilterControlledLandPermanent())); + this.addAbility(ability); + } + + public WallOfResurgence(final WallOfResurgence card) { + super(card); + } + + @Override + public WallOfResurgence copy() { + return new WallOfResurgence(this); + } +} + +class WallOfResurgenceToken extends Token { + + public WallOfResurgenceToken() { + super("", "0/0 Elemental creature with haste"); + this.cardType.add(CardType.CREATURE); + + this.subtype.add("Elemental"); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + this.addAbility(HasteAbility.getInstance()); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/WanderingFumarole.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/WanderingFumarole.java new file mode 100644 index 00000000000..66773d0e607 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/WanderingFumarole.java @@ -0,0 +1,93 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; +import mage.abilities.effects.common.continuous.SwitchPowerToughnessSourceEffect; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.RedManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.permanent.token.Token; + +/** + * + * @author fireshoes + */ +public class WanderingFumarole extends CardImpl { + + public WanderingFumarole(UUID ownerId) { + super(ownerId, 182, "Wandering Fumarole", Rarity.RARE, new CardType[]{CardType.LAND}, ""); + this.expansionSetCode = "OGW"; + + // Wandering Fumarole enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {U} or {R} to your mana pool. + this.addAbility(new BlueManaAbility()); + this.addAbility(new RedManaAbility()); + + // {2}{U}{R}: Until end of turn, Wandering Fumarole becomes a 1/4 blue and red Elemental creature with + // "0: Switch this creature's power and toughness until end of turn." It's still a land. + Effect effect = new BecomesCreatureSourceEffect(new WanderingFumaroleToken(), "land", Duration.EndOfTurn); + effect.setText("{this} becomes a 1/4 blue and red Elemental creature with \"0: Switch this creature's power and toughness until end of turn.\" It's still a land"); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{2}{U}{R}"))); + } + + public WanderingFumarole(final WanderingFumarole card) { + super(card); + } + + @Override + public WanderingFumarole copy() { + return new WanderingFumarole(this); + } +} + +class WanderingFumaroleToken extends Token { + + public WanderingFumaroleToken() { + super("", "1/4 blue and red Elemental creature with \"0: Switch this creature's power and toughness until end of turn.\""); + cardType.add(CardType.CREATURE); + subtype.add("Elemental"); + color.setRed(true); + color.setWhite(true); + power = new MageInt(1); + toughness = new MageInt(4); + addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new SwitchPowerToughnessSourceEffect(Duration.EndOfTurn), new ManaCostsImpl("{0}"))); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/WardenOfGeometries.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/WardenOfGeometries.java new file mode 100644 index 00000000000..2198574aaab --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/WardenOfGeometries.java @@ -0,0 +1,66 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.mana.ColorlessManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author LevelX2 + */ +public class WardenOfGeometries extends CardImpl { + + public WardenOfGeometries(UUID ownerId) { + super(ownerId, 11, "Warden of Geometries", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Eldrazi"); + this.subtype.add("Drone"); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + // {T}: Add {C} to your mana pool. + this.addAbility(new ColorlessManaAbility()); + } + + public WardenOfGeometries(final WardenOfGeometries card) { + super(card); + } + + @Override + public WardenOfGeometries copy() { + return new WardenOfGeometries(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/WarpingWail.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/WarpingWail.java new file mode 100644 index 00000000000..973603499c0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/WarpingWail.java @@ -0,0 +1,99 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.Mode; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.Filter; +import mage.filter.Filter.ComparisonType; +import mage.filter.FilterSpell; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.predicate.mageobject.ToughnessPredicate; +import mage.game.permanent.token.EldraziScionToken; +import mage.target.TargetSpell; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class WarpingWail extends CardImpl { + + private static final FilterCreaturePermanent filterCreature = new FilterCreaturePermanent("creature with power or toughness 1 or less"); + private static final FilterSpell filterSorcery = new FilterSpell("sorcery spell"); + + static { + filterCreature.add(Predicates.or( + new PowerPredicate(Filter.ComparisonType.LessThan, 2), + new ToughnessPredicate(ComparisonType.LessThan, 2))); + filterSorcery.add(new CardTypePredicate(CardType.SORCERY)); + } + + public WarpingWail(UUID ownerId) { + super(ownerId, 12, "Warping Wail", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{1}{C}"); + this.expansionSetCode = "OGW"; + + // Choose one — Exile target creature with power or toughness 1 or less. + 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)); + + // Counter target sorcery spell. + Mode mode = new Mode(); + mode.getEffects().add(new CounterTargetEffect()); + mode.getTargets().add(new TargetSpell(filterSorcery)); + this.getSpellAbility().addMode(mode); + + // Put a 1/1 colorless Eldrazi Scion creature token onto the battlefield. It has "Sacrifice this creature: Add {C} to your mana pool." + mode = new Mode(); + effect = new CreateTokenEffect(new EldraziScionToken()); + effect.setText("Put a 1/1 colorless Eldrazi Scion creature token onto the battlefield. It has \"Sacrifice this creature: Add {C} to your mana pool.\""); + mode.getEffects().add(effect); + this.getSpellAbility().addMode(mode); + } + + public WarpingWail(final WarpingWail card) { + super(card); + } + + @Override + public WarpingWail copy() { + return new WarpingWail(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/WeaponsTrainer.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/WeaponsTrainer.java new file mode 100644 index 00000000000..6cbcbd7a1e4 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/WeaponsTrainer.java @@ -0,0 +1,80 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author fireshoes + */ +public class WeaponsTrainer extends CardImpl { + + private static final String rule = "Other creatures you control get +1/+0 as long as you control an Equipment."; + private static final FilterControlledPermanent filter = new FilterControlledPermanent("an Equipment"); + + static { + filter.add(new SubtypePredicate("Equipment")); + } + + public WeaponsTrainer(UUID ownerId) { + super(ownerId, 160, "Weapons Trainer", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{R}{W}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Human"); + this.subtype.add("Soldier"); + this.subtype.add("Ally"); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Other creatures you control get +1/+0 as long as you control an Equipment. + ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new BoostControlledEffect(1, 0, Duration.WhileOnBattlefield, true), + new PermanentsOnTheBattlefieldCondition(filter), rule); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public WeaponsTrainer(final WeaponsTrainer card) { + super(card); + } + + @Override + public WeaponsTrainer copy() { + return new WeaponsTrainer(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/WitnessTheEnd.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/WitnessTheEnd.java new file mode 100644 index 00000000000..5a1247f112b --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/WitnessTheEnd.java @@ -0,0 +1,70 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.ExileFromZoneTargetEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.keyword.DevoidAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.target.common.TargetOpponent; + +/** + * + * @author LevelX2 + */ +public class WitnessTheEnd extends CardImpl { + + public WitnessTheEnd(UUID ownerId) { + super(ownerId, 82, "Witness the End", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{3}{B}"); + this.expansionSetCode = "OGW"; + + // Devoid + this.addAbility(new DevoidAbility(this.color)); + // Target opponent exiles two cards from his or her hand and loses 2 life. + getSpellAbility().addEffect(new ExileFromZoneTargetEffect(Zone.HAND, null, "", new FilterCard("cards"), 2)); + Effect effect = new LoseLifeTargetEffect(2); + effect.setText("and loses 2 life"); + getSpellAbility().addTarget(new TargetOpponent()); + getSpellAbility().addEffect(effect); + } + + public WitnessTheEnd(final WitnessTheEnd card) { + super(card); + } + + @Override + public WitnessTheEnd copy() { + return new WitnessTheEnd(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/ZadasCommando.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/ZadasCommando.java new file mode 100644 index 00000000000..00d4bf79c52 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/ZadasCommando.java @@ -0,0 +1,91 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +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.common.TapTargetCost; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetOpponent; + +/** + * + * @author fireshoes + */ +public class ZadasCommando extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("an untapped Ally you control"); + + static { + filter.add(new SubtypePredicate("Ally")); + filter.add(Predicates.not(new TappedPredicate())); + } + + public ZadasCommando(UUID ownerId) { + super(ownerId, 120, "Zada's Commando", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{R}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Goblin"); + this.subtype.add("Archer"); + this.subtype.add("Ally"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // First Strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // Cohort — {T}, Tap an untapped Ally you control: Zada's Commando deals 1 damage to target opponent. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new TapSourceCost()); + ability.addCost(new TapTargetCost(new TargetControlledPermanent(filter))); + ability.addTarget(new TargetOpponent()); + ability.setAbilityWord(AbilityWord.COHORT); + this.addAbility(ability); + } + + public ZadasCommando(final ZadasCommando card) { + super(card); + } + + @Override + public ZadasCommando copy() { + return new ZadasCommando(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/ZendikarResurgent.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/ZendikarResurgent.java new file mode 100644 index 00000000000..55312a06467 --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/ZendikarResurgent.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.common.TapForManaAllTriggeredManaAbility; +import mage.abilities.effects.common.AddManaOfAnyTypeProducedEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.SetTargetPointer; +import mage.filter.FilterSpell; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.mageobject.CardTypePredicate; + +/** + * + * @author fireshoes + */ +public class ZendikarResurgent extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a creature spell"); + + static { + filter.add(new CardTypePredicate(CardType.CREATURE)); + } + + public ZendikarResurgent(UUID ownerId) { + super(ownerId, 147, "Zendikar Resurgent", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{5}{G}{G}"); + this.expansionSetCode = "OGW"; + + // Whenever you tap a land for mana, add one mana to your mana pool of any type that land produced. (The types of mana are white, blue, black, red, green, and colorless.) + AddManaOfAnyTypeProducedEffect effect = new AddManaOfAnyTypeProducedEffect(); + effect.setText("add one mana to your mana pool of any type that land produced"); + this.addAbility(new TapForManaAllTriggeredManaAbility( + effect, + new FilterControlledLandPermanent("you tap a land"), + SetTargetPointer.PERMANENT)); + + // Whenever you cast a creature spell, draw a card. + this.addAbility(new SpellCastControllerTriggeredAbility(new DrawCardSourceControllerEffect(1), filter, false)); + } + + public ZendikarResurgent(final ZendikarResurgent card) { + super(card); + } + + @Override + public ZendikarResurgent copy() { + return new ZendikarResurgent(this); + } +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/ZulaportChainmage.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/ZulaportChainmage.java new file mode 100644 index 00000000000..744c035f03c --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/ZulaportChainmage.java @@ -0,0 +1,88 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetOpponent; + +/** + * + * @author LevelX2 + */ +public class ZulaportChainmage extends CardImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Ally you control"); + + static { + filter.add(new SubtypePredicate("Ally")); + filter.add(Predicates.not(new TappedPredicate())); + } + + public ZulaportChainmage(UUID ownerId) { + super(ownerId, 93, "Zulaport Chainmage", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.expansionSetCode = "OGW"; + this.subtype.add("Human"); + this.subtype.add("Shaman"); + this.subtype.add("Ally"); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // Cohort — {T}, Tap an untapped Ally you control: Target opponent loses 2 life. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new LoseLifeTargetEffect(2), + new TapSourceCost()); + ability.setAbilityWord(AbilityWord.COHORT); + ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, false))); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + public ZulaportChainmage(final ZulaportChainmage card) { + super(card); + } + + @Override + public ZulaportChainmage copy() { + return new ZulaportChainmage(this); + } +} diff --git a/Mage.Sets/src/mage/sets/odyssey/AboshansDesire.java b/Mage.Sets/src/mage/sets/odyssey/AboshansDesire.java index 442e6facd3f..43e0d926873 100644 --- a/Mage.Sets/src/mage/sets/odyssey/AboshansDesire.java +++ b/Mage.Sets/src/mage/sets/odyssey/AboshansDesire.java @@ -38,6 +38,7 @@ import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.ShroudAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.AttachmentType; import mage.constants.CardType; import mage.constants.Duration; @@ -66,11 +67,12 @@ public class AboshansDesire extends CardImpl { Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); // Enchanted creature has flying. - ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield)); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield))); // Threshold - Enchanted creature has shroud as long as seven or more cards are in your graveyard. - ability.addEffect(new ConditionalContinuousEffect(new GainAbilityAttachedEffect(ShroudAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield), - new CardsInControllerGraveCondition(7), - "Threshold - Enchanted creature gets shroud as long as seven or more cards are in your graveyard")); + ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new GainAbilityAttachedEffect(ShroudAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield), + new CardsInControllerGraveCondition(7), "enchanted creature has shroud as long as seven or more cards are in your graveyard")); + ability.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/odyssey/BarbarianRing.java b/Mage.Sets/src/mage/sets/odyssey/BarbarianRing.java index d8db1ef94a1..cf6d31eb857 100644 --- a/Mage.Sets/src/mage/sets/odyssey/BarbarianRing.java +++ b/Mage.Sets/src/mage/sets/odyssey/BarbarianRing.java @@ -33,11 +33,12 @@ import mage.abilities.condition.common.CardsInControllerGraveCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalGainActivatedAbility; +import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.mana.RedManaAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; @@ -59,14 +60,14 @@ public class BarbarianRing extends CardImpl { this.addAbility(redManaAbility); // Threshold - {R}, {T}, Sacrifice Barbarian Ring: Barbarian Ring deals 2 damage to target creature or player. Activate this ability only if seven or more cards are in your graveyard. - Ability thresholdAbility = new ConditionalGainActivatedAbility(Zone.BATTLEFIELD, + Ability thresholdAbility = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new ManaCostsImpl("{R}"), - new CardsInControllerGraveCondition(7), - "Threshold - {R}, {T}, Sacrifice {this}: {this} deals 2 damage to target creature or player. Activate this ability only if seven or more cards are in your graveyard."); + new CardsInControllerGraveCondition(7)); thresholdAbility.addCost(new TapSourceCost()); thresholdAbility.addCost(new SacrificeSourceCost()); thresholdAbility.addTarget(new TargetCreatureOrPlayer()); + thresholdAbility.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(thresholdAbility); } diff --git a/Mage.Sets/src/mage/sets/odyssey/Bloodcurdler.java b/Mage.Sets/src/mage/sets/odyssey/Bloodcurdler.java index d8caa1fcb2c..0df99ec3130 100644 --- a/Mage.Sets/src/mage/sets/odyssey/Bloodcurdler.java +++ b/Mage.Sets/src/mage/sets/odyssey/Bloodcurdler.java @@ -43,6 +43,7 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -65,18 +66,19 @@ public class Bloodcurdler extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // At the beginning of your upkeep, put the top card of your library into your graveyard. this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new PutTopCardOfLibraryIntoGraveControllerEffect(1), TargetController.YOU, false)); Condition thresholdCondition = new CardsInControllerGraveCondition(7); // Threshold - As long as seven or more cards are in your graveyard, Bloodcurdler gets +1/+1 and has "At the beginning of your end step, exile two cards from your graveyard." - Ability thresholdAbility = new SimpleStaticAbility(Zone.BATTLEFIELD, - new ConditionalContinuousEffect(new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), thresholdCondition, - "Threshold - If seven or more cards are in your graveyard, {this} gets +1/+1")); + Ability thresholdAbility = new SimpleStaticAbility(Zone.BATTLEFIELD, + new ConditionalContinuousEffect(new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), thresholdCondition, + "If seven or more cards are in your graveyard, {this} gets +1/+1")); ContinuousEffect effect = new GainAbilitySourceEffect(new BeginningOfEndStepTriggeredAbility(new ExileCardFromOwnGraveyardControllerEffect(2), TargetController.YOU, false)); thresholdAbility.addEffect(new ConditionalContinuousEffect(effect, thresholdCondition, - "and has \"At the beginning of your end step, exile two cards from your graveyard.\"")); + "and has \"At the beginning of your end step, exile two cards from your graveyard.\"")); + thresholdAbility.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(thresholdAbility); } diff --git a/Mage.Sets/src/mage/sets/odyssey/CabalInquisitor.java b/Mage.Sets/src/mage/sets/odyssey/CabalInquisitor.java index a0a48bb3b26..a0245601cdf 100644 --- a/Mage.Sets/src/mage/sets/odyssey/CabalInquisitor.java +++ b/Mage.Sets/src/mage/sets/odyssey/CabalInquisitor.java @@ -41,6 +41,7 @@ import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.EffectType; import mage.constants.Rarity; @@ -68,10 +69,11 @@ public 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 ActivateAsSorceryConditionalActivatedAbility(Zone.BATTLEFIELD, new DiscardTargetEffect(1), new ManaCostsImpl("{1}{B}"), new CardsInControllerGraveCondition(7), "

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 ActivateAsSorceryConditionalActivatedAbility(Zone.BATTLEFIELD, new DiscardTargetEffect(1), new ManaCostsImpl("{1}{B}"), new CardsInControllerGraveCondition(7)); ability.addTarget(new TargetPlayer()); ability.addCost(new TapSourceCost()); ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(2, new FilterCard("cards from your graveyard")))); + ability.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(ability); } @@ -87,24 +89,21 @@ public class CabalInquisitor extends CardImpl { class ActivateAsSorceryConditionalActivatedAbility extends ActivatedAbilityImpl { - + private Condition condition; - private String ruleText = "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."; private static final Effects emptyEffects = new Effects(); - public ActivateAsSorceryConditionalActivatedAbility(Zone zone, Effect effect, ManaCosts cost, Condition condition, String rule) { + public ActivateAsSorceryConditionalActivatedAbility(Zone zone, Effect effect, ManaCosts cost, Condition condition) { super(zone, effect, cost); this.condition = condition; - this.ruleText = rule; - timing = TimingRule.SORCERY; + timing = TimingRule.SORCERY; } public ActivateAsSorceryConditionalActivatedAbility(final ActivateAsSorceryConditionalActivatedAbility ability) { super(ability); this.condition = ability.condition; - this.ruleText = ability.ruleText; } @Override @@ -130,6 +129,6 @@ class ActivateAsSorceryConditionalActivatedAbility extends ActivatedAbilityImpl @Override public String getRule() { - return ruleText; + return super.getRule() + " Activate this ability only any time you could cast a sorcery, and only if seven or more cards are in your graveyard."; } } diff --git a/Mage.Sets/src/mage/sets/odyssey/CabalPit.java b/Mage.Sets/src/mage/sets/odyssey/CabalPit.java index 306c46f7c61..bdfb9db7f9d 100644 --- a/Mage.Sets/src/mage/sets/odyssey/CabalPit.java +++ b/Mage.Sets/src/mage/sets/odyssey/CabalPit.java @@ -33,11 +33,12 @@ import mage.abilities.condition.common.CardsInControllerGraveCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalGainActivatedAbility; +import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.mana.BlackManaAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -60,14 +61,14 @@ public 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 ConditionalGainActivatedAbility(Zone.BATTLEFIELD, + Ability thresholdAbility = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(-2,-2, Duration.EndOfTurn), new ManaCostsImpl("{B}"), - new CardsInControllerGraveCondition(7), - "Threshold - {B}, {T}, Sacrifice {this}: Target creature gets -2/-2 until end of turn. Activate this ability only if seven or more cards are in your graveyard."); + new CardsInControllerGraveCondition(7)); thresholdAbility.addCost(new TapSourceCost()); thresholdAbility.addCost(new SacrificeSourceCost()); thresholdAbility.addTarget(new TargetCreaturePermanent()); + thresholdAbility.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(thresholdAbility); } diff --git a/Mage.Sets/src/mage/sets/odyssey/CentaurGarden.java b/Mage.Sets/src/mage/sets/odyssey/CentaurGarden.java index a5517dece9b..e28e2f98f03 100644 --- a/Mage.Sets/src/mage/sets/odyssey/CentaurGarden.java +++ b/Mage.Sets/src/mage/sets/odyssey/CentaurGarden.java @@ -33,11 +33,12 @@ import mage.abilities.condition.common.CardsInControllerGraveCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalGainActivatedAbility; +import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.mana.GreenManaAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -60,14 +61,14 @@ public 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 ConditionalGainActivatedAbility(Zone.BATTLEFIELD, + Ability thresholdAbility = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(+3,+3, Duration.EndOfTurn), new ManaCostsImpl("{G}"), - new CardsInControllerGraveCondition(7), - "Threshold - {G}, {T}, Sacrifice {this}: Target creature gets +3/+3 until end of turn. Activate this ability only if seven or more cards are in your graveyard."); + new CardsInControllerGraveCondition(7)); thresholdAbility.addCost(new TapSourceCost()); thresholdAbility.addCost(new SacrificeSourceCost()); thresholdAbility.addTarget(new TargetCreaturePermanent()); + thresholdAbility.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(thresholdAbility); } diff --git a/Mage.Sets/src/mage/sets/odyssey/CephalidColiseum.java b/Mage.Sets/src/mage/sets/odyssey/CephalidColiseum.java index f2bed0f7c83..a11f90c3096 100644 --- a/Mage.Sets/src/mage/sets/odyssey/CephalidColiseum.java +++ b/Mage.Sets/src/mage/sets/odyssey/CephalidColiseum.java @@ -33,12 +33,12 @@ import mage.abilities.condition.common.CardsInControllerGraveCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalGainActivatedAbility; +import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.DamageControllerEffect; -import mage.abilities.effects.common.DrawCardTargetEffect; -import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.abilities.effects.common.DrawDiscardTargetEffect; import mage.abilities.mana.BlueManaAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; @@ -60,15 +60,14 @@ public 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 ConditionalGainActivatedAbility(Zone.BATTLEFIELD, - new DrawCardTargetEffect(3), + Ability thresholdAbility = new ConditionalActivatedAbility(Zone.BATTLEFIELD, + new DrawDiscardTargetEffect(3, 3), new ManaCostsImpl("{U}"), - new CardsInControllerGraveCondition(7), - "Threshold - {U}, {T}, Sacrifice {this}: Target player draws three cards, then discards three cards. Activate this ability only if seven or more cards are in your graveyard."); - thresholdAbility.addEffect(new DiscardTargetEffect(3)); + new CardsInControllerGraveCondition(7)); thresholdAbility.addCost(new TapSourceCost()); thresholdAbility.addCost(new SacrificeSourceCost()); thresholdAbility.addTarget(new TargetPlayer()); + thresholdAbility.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(thresholdAbility); } diff --git a/Mage.Sets/src/mage/sets/odyssey/Chainflinger.java b/Mage.Sets/src/mage/sets/odyssey/Chainflinger.java index 32384719b61..4ed527b5321 100644 --- a/Mage.Sets/src/mage/sets/odyssey/Chainflinger.java +++ b/Mage.Sets/src/mage/sets/odyssey/Chainflinger.java @@ -34,9 +34,10 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.CardsInControllerGraveCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalGainActivatedAbility; +import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; @@ -62,13 +63,13 @@ public class Chainflinger extends CardImpl { ability.addTarget(new TargetCreatureOrPlayer()); this.addAbility(ability); // Threshold - {2}{R}, {tap}: Chainflinger deals 2 damage to target creature or player. Activate this ability only if seven or more cards are in your graveyard. - Ability thresholdAbility = new ConditionalGainActivatedAbility(Zone.BATTLEFIELD, + Ability thresholdAbility = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), - new ManaCostsImpl("2}{R}"), - new CardsInControllerGraveCondition(7), - "Threshold - {2}{R}, {t}: {this} deals 2 damage to target creature or player. Activate this ability only if seven or more cards are in your graveyard."); + new ManaCostsImpl("{2}{R}"), + new CardsInControllerGraveCondition(7)); thresholdAbility.addCost(new TapSourceCost()); thresholdAbility.addTarget(new TargetCreatureOrPlayer()); + thresholdAbility.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(thresholdAbility); } diff --git a/Mage.Sets/src/mage/sets/odyssey/ChildhoodHorror.java b/Mage.Sets/src/mage/sets/odyssey/ChildhoodHorror.java index eb8ccf8bd47..e297a009574 100644 --- a/Mage.Sets/src/mage/sets/odyssey/ChildhoodHorror.java +++ b/Mage.Sets/src/mage/sets/odyssey/ChildhoodHorror.java @@ -39,6 +39,7 @@ import mage.abilities.effects.common.combat.CantBlockSourceEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -66,7 +67,7 @@ public class ChildhoodHorror extends CardImpl { new ConditionalContinuousEffect( new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), - "Threshold - If seven or more cards are in your graveyard, Childhood Horror gets +2/+2" + "If seven or more cards are in your graveyard, Childhood Horror gets +2/+2" )); Effect effect = new ConditionalRestrictionEffect( @@ -74,7 +75,8 @@ public class ChildhoodHorror extends CardImpl { new CardsInControllerGraveCondition(7)); effect.setText("and can't block"); thresholdAbility.addEffect(effect); - this.addAbility(thresholdAbility); + thresholdAbility.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(thresholdAbility); } public ChildhoodHorror(final ChildhoodHorror card) { diff --git a/Mage.Sets/src/mage/sets/odyssey/Chlorophant.java b/Mage.Sets/src/mage/sets/odyssey/Chlorophant.java index 0a276940b4f..996a23a9151 100644 --- a/Mage.Sets/src/mage/sets/odyssey/Chlorophant.java +++ b/Mage.Sets/src/mage/sets/odyssey/Chlorophant.java @@ -29,14 +29,22 @@ package mage.sets.odyssey; import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.Rarity; import mage.constants.TargetController; +import mage.constants.Zone; import mage.counters.CounterType; /** @@ -56,9 +64,14 @@ public class Chlorophant extends CardImpl { // At the beginning of your upkeep, you may put a +1/+1 counter on Chlorophant. this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), TargetController.YOU, true)); // Threshold - As long as seven or more cards are in your graveyard, Chlorophant has "At the beginning of your upkeep, you may put another +1/+1 counter on Chlorophant." - this.addAbility(new ConditionalTriggeredAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), TargetController.YOU, true), - new CardsInControllerGraveCondition(7), - "Threshold As long as seven or more cards are in your graveyard, {this} has \"At the beginning of your upkeep, you may put another +1/+1 counter on {this}\"")); + Effect effect = new AddCountersSourceEffect(CounterType.P1P1.createInstance()); + effect.setText("At the beginning of your upkeep, you may put another +1/+1 counter on {this}."); + Ability gainedAbility = new BeginningOfUpkeepTriggeredAbility(effect, TargetController.YOU, true); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new GainAbilitySourceEffect(gainedAbility, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), + "As long as seven or more cards are in your graveyard, {this} has \"At the beginning of your upkeep, you may put another +1/+1 counter on {this}.\"")); + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); } public Chlorophant(final Chlorophant card) { diff --git a/Mage.Sets/src/mage/sets/odyssey/CrashingCentaur.java b/Mage.Sets/src/mage/sets/odyssey/CrashingCentaur.java index 7cbda61f07a..8f1f222f571 100644 --- a/Mage.Sets/src/mage/sets/odyssey/CrashingCentaur.java +++ b/Mage.Sets/src/mage/sets/odyssey/CrashingCentaur.java @@ -42,6 +42,7 @@ import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.ShroudAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -65,20 +66,20 @@ public class CrashingCentaur extends CardImpl { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilitySourceEffect(TrampleAbility.getInstance(),Duration.EndOfTurn), new ManaCostsImpl("{G}")); ability.addCost(new DiscardCardCost()); this.addAbility(ability); - + // Threshold - As long as seven or more cards are in your graveyard, Crashing Centaur gets +2/+2 and has shroud. Ability thresholdAbility = new SimpleStaticAbility( Zone.BATTLEFIELD, new ConditionalContinuousEffect( new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), - "Threshold - If seven or more cards are in your graveyard, {this} gets +2/+2")); + "If seven or more cards are in your graveyard, {this} gets +2/+2")); Effect effect = new ConditionalContinuousEffect( new GainAbilitySourceEffect(ShroudAbility.getInstance()), new CardsInControllerGraveCondition(7), "and has shroud"); thresholdAbility.addEffect(effect); + thresholdAbility.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(thresholdAbility); - } public CrashingCentaur(final CrashingCentaur card) { diff --git a/Mage.Sets/src/mage/sets/odyssey/CrystalQuarry.java b/Mage.Sets/src/mage/sets/odyssey/CrystalQuarry.java index a39dfba2bba..ef681940ce1 100644 --- a/Mage.Sets/src/mage/sets/odyssey/CrystalQuarry.java +++ b/Mage.Sets/src/mage/sets/odyssey/CrystalQuarry.java @@ -52,7 +52,7 @@ public class CrystalQuarry extends CardImpl { // {tap}: Add {C} to your mana pool. this.addAbility(new ColorlessManaAbility()); // {5}, {tap}: Add {W}{U}{B}{R}{G} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 1, 1, 1, 0, 0), new ManaCostsImpl("{5}")); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 1, 1, 1, 0, 0, 0), new ManaCostsImpl("{5}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/odyssey/DarkwaterCatacombs.java b/Mage.Sets/src/mage/sets/odyssey/DarkwaterCatacombs.java index 7910d65c942..8d8a771dd2b 100644 --- a/Mage.Sets/src/mage/sets/odyssey/DarkwaterCatacombs.java +++ b/Mage.Sets/src/mage/sets/odyssey/DarkwaterCatacombs.java @@ -49,7 +49,7 @@ public class DarkwaterCatacombs extends CardImpl { this.expansionSetCode = "ODY"; // {1}, {tap}: Add {U}{B} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 0, 1, 0, 0), new ManaCostsImpl("{1}")); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 0, 1, 0, 0, 0), new ManaCostsImpl("{1}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/odyssey/DarkwaterEgg.java b/Mage.Sets/src/mage/sets/odyssey/DarkwaterEgg.java index 52bd2d1bd08..ea5c1aa6760 100644 --- a/Mage.Sets/src/mage/sets/odyssey/DarkwaterEgg.java +++ b/Mage.Sets/src/mage/sets/odyssey/DarkwaterEgg.java @@ -51,7 +51,7 @@ public class DarkwaterEgg extends CardImpl { this.expansionSetCode = "ODY"; // {2}, {tap}, Sacrifice Darkwater Egg: Add {U}{B} to your mana pool. Draw a card. - ManaAbility ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 0, 1, 0, 0), new ManaCostsImpl("{2}")); + ManaAbility ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 0, 1, 0, 0, 0), new ManaCostsImpl("{2}")); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); ability.addEffect(new DrawCardSourceControllerEffect(1)); diff --git a/Mage.Sets/src/mage/sets/odyssey/DecayingSoil.java b/Mage.Sets/src/mage/sets/odyssey/DecayingSoil.java index aae708d61b4..9dab397a22c 100644 --- a/Mage.Sets/src/mage/sets/odyssey/DecayingSoil.java +++ b/Mage.Sets/src/mage/sets/odyssey/DecayingSoil.java @@ -42,6 +42,7 @@ import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; @@ -52,8 +53,8 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.other.OwnerPredicate; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; +import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.players.Player; @@ -82,12 +83,14 @@ public class DecayingSoil extends CardImpl { TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(); ability.addTarget(target); this.addAbility(ability); - + // Threshold - As long as seven or more cards are in your graveyard, Decaying Soil has "Whenever a nontoken creature is put into your graveyard from the battlefield, you may pay {1}. If you do, return that card to your hand." - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, - new ConditionalContinuousEffect(new GainAbilitySourceEffect(new DecayingSoilTriggeredAbility(new DecayingSoilEffect(), filter)), - new CardsInControllerGraveCondition(7), - "Threshold - As long as seven or more cards are in your graveyard, {this} has \"Whenever a nontoken creature is put into your graveyard from the battlefield, you may pay {1}. If you do, return that card to your hand"))); + ability = new SimpleStaticAbility(Zone.BATTLEFIELD, + new ConditionalContinuousEffect(new GainAbilitySourceEffect(new DecayingSoilTriggeredAbility(new DecayingSoilEffect(), filter)), + new CardsInControllerGraveCondition(7), + "As long as seven or more cards are in your graveyard, {this} has \"Whenever a nontoken creature is put into your graveyard from the battlefield, you may pay {1}. If you do, return that card to your hand.\"")); + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); } public DecayingSoil(final DecayingSoil card) { @@ -172,9 +175,9 @@ class DecayingSoilEffect extends OneShotEffect { if (player != null) { if (player.chooseUse(Outcome.Benefit, " - Pay " + cost.getText() + "?", source, game)) { cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { UUID target = this.getTargetPointer().getFirst(game, source); - if (target != null) { + if (target != null) { Card card = game.getCard(target); // check if it's still in graveyard if (card != null && game.getState().getZone(card.getId()).equals(Zone.GRAVEYARD)) { diff --git a/Mage.Sets/src/mage/sets/odyssey/DelayingShield.java b/Mage.Sets/src/mage/sets/odyssey/DelayingShield.java index 188a4374f4e..8e83b7f06f9 100644 --- a/Mage.Sets/src/mage/sets/odyssey/DelayingShield.java +++ b/Mage.Sets/src/mage/sets/odyssey/DelayingShield.java @@ -139,7 +139,7 @@ class DelayingShieldUpkeepEffect extends OneShotEffect { for (int i = numCounters; i > 0; i--) { if (controller.chooseUse(Outcome.Benefit, "Pay {1}{W}? (" + i + " counters left to pay)", source, game)) { Cost cost = new ManaCostsImpl<>("{1}{W}"); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { continue; } } diff --git a/Mage.Sets/src/mage/sets/odyssey/DirtyWererat.java b/Mage.Sets/src/mage/sets/odyssey/DirtyWererat.java index c29c20bb2f7..8e5537c30b4 100644 --- a/Mage.Sets/src/mage/sets/odyssey/DirtyWererat.java +++ b/Mage.Sets/src/mage/sets/odyssey/DirtyWererat.java @@ -42,6 +42,7 @@ import mage.abilities.effects.common.RegenerateSourceEffect; import mage.abilities.effects.common.combat.CantBlockSourceEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -73,13 +74,14 @@ public class DirtyWererat extends CardImpl { new ConditionalContinuousEffect( new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), - "Threshold - If seven or more cards are in your graveyard, Dirty Wererat gets +2/+2 and can't block" + "If seven or more cards are in your graveyard, {this} gets +2/+2" )); Effect effect = new ConditionalRestrictionEffect( new CantBlockSourceEffect(Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7)); effect.setText("and can't block"); thresholdAbility.addEffect(effect); + thresholdAbility.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(thresholdAbility); } diff --git a/Mage.Sets/src/mage/sets/odyssey/Divert.java b/Mage.Sets/src/mage/sets/odyssey/Divert.java index 0b23c2942c6..077cf041e35 100644 --- a/Mage.Sets/src/mage/sets/odyssey/Divert.java +++ b/Mage.Sets/src/mage/sets/odyssey/Divert.java @@ -92,7 +92,7 @@ class DivertEffect extends OneShotEffect { if (player != null) { cost.clearPaid(); if (!cost.pay(source, game, spell.getControllerId(), - spell.getControllerId(), false)) { + spell.getControllerId(), false, null)) { return spell.chooseNewTargets(game, source.getControllerId(), true, true, null); } } diff --git a/Mage.Sets/src/mage/sets/odyssey/DivineSacrament.java b/Mage.Sets/src/mage/sets/odyssey/DivineSacrament.java index c6650039d9b..ce9adfd77cd 100644 --- a/Mage.Sets/src/mage/sets/odyssey/DivineSacrament.java +++ b/Mage.Sets/src/mage/sets/odyssey/DivineSacrament.java @@ -35,6 +35,7 @@ import mage.abilities.condition.common.CardsInControllerGraveCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -47,7 +48,7 @@ import mage.filter.predicate.mageobject.ColorPredicate; * @author Beta_Steward (Honor of the Pure), LevelX2 (Demoralize), cbt */ public class DivineSacrament extends CardImpl { - + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("White creatures"); static { filter.add(new ColorPredicate(ObjectColor.WHITE)); @@ -65,8 +66,9 @@ public class DivineSacrament extends CardImpl { ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter, false), new CardsInControllerGraveCondition(7), - "Threshold - If seven or more cards are in your graveyard, white creatures get an additional +1/+1." + "If seven or more cards are in your graveyard, white creatures get an additional +1/+1." )); + ability.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/odyssey/Frightcrawler.java b/Mage.Sets/src/mage/sets/odyssey/Frightcrawler.java index 3a98e33ba1c..b430b104758 100644 --- a/Mage.Sets/src/mage/sets/odyssey/Frightcrawler.java +++ b/Mage.Sets/src/mage/sets/odyssey/Frightcrawler.java @@ -37,6 +37,7 @@ import mage.abilities.effects.common.combat.CantBlockSourceEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.FearAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -64,12 +65,13 @@ public class Frightcrawler extends CardImpl { new ConditionalContinuousEffect( new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), - "Threshold - If seven or more cards are in your graveyard, {this} gets +2/+2 " + "If seven or more cards are in your graveyard, {this} gets +2/+2 " )); thresholdAbility.addEffect(new ConditionalContinuousEffect( new CantBlockSourceEffect(Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), "and can't block.")); + thresholdAbility.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(thresholdAbility); } diff --git a/Mage.Sets/src/mage/sets/odyssey/HallowedHealer.java b/Mage.Sets/src/mage/sets/odyssey/HallowedHealer.java index 5d6a21c237a..709c59bf1b3 100644 --- a/Mage.Sets/src/mage/sets/odyssey/HallowedHealer.java +++ b/Mage.Sets/src/mage/sets/odyssey/HallowedHealer.java @@ -33,9 +33,10 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.CardsInControllerGraveCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalGainActivatedAbility; +import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.PreventDamageToTargetEffect; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -46,7 +47,7 @@ import mage.target.common.TargetCreatureOrPlayer; * * @author cbt33 */ - + public class HallowedHealer extends CardImpl { public HallowedHealer(UUID ownerId) { @@ -63,12 +64,12 @@ public class HallowedHealer extends CardImpl { ability.addTarget(new TargetCreatureOrPlayer()); this.addAbility(ability); // Threshold - {tap}: Prevent the next 4 damage that would be dealt to target creature or player this turn. Activate this ability only if seven or more cards are in your graveyard. - Ability thresholdAbility = new ConditionalGainActivatedAbility(Zone.BATTLEFIELD, - new PreventDamageToTargetEffect(Duration.EndOfTurn,4), - new TapSourceCost(), - new CardsInControllerGraveCondition(7), - "Threshold - {T}: Prevent the next 4 damage that would be dealt to target creature or player this turn. Activate this ability only if seven or more cards are in your graveyard."); + Ability thresholdAbility = new ConditionalActivatedAbility(Zone.BATTLEFIELD, + new PreventDamageToTargetEffect(Duration.EndOfTurn, 4), + new TapSourceCost(), + new CardsInControllerGraveCondition(7)); thresholdAbility.addTarget(new TargetCreatureOrPlayer()); + thresholdAbility.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(thresholdAbility); } diff --git a/Mage.Sets/src/mage/sets/odyssey/InfectedVermin.java b/Mage.Sets/src/mage/sets/odyssey/InfectedVermin.java index f7542d4aa79..f17999ad7b0 100644 --- a/Mage.Sets/src/mage/sets/odyssey/InfectedVermin.java +++ b/Mage.Sets/src/mage/sets/odyssey/InfectedVermin.java @@ -29,12 +29,14 @@ package mage.sets.odyssey; import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.CardsInControllerGraveCondition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.DamageEverythingEffect; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; @@ -56,11 +58,12 @@ public class InfectedVermin extends CardImpl { // {2}{B}: Infected Vermin deals 1 damage to each creature and each player. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, 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(Zone.BATTLEFIELD, + Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new DamageEverythingEffect(3), new ManaCostsImpl("{3}{B}"), - new CardsInControllerGraveCondition(7), - "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.")); + new CardsInControllerGraveCondition(7)); + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); } public InfectedVermin(final InfectedVermin card) { diff --git a/Mage.Sets/src/mage/sets/odyssey/KamahlsDesire.java b/Mage.Sets/src/mage/sets/odyssey/KamahlsDesire.java index ca69173073c..42b78beea04 100644 --- a/Mage.Sets/src/mage/sets/odyssey/KamahlsDesire.java +++ b/Mage.Sets/src/mage/sets/odyssey/KamahlsDesire.java @@ -38,6 +38,7 @@ import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.AttachmentType; import mage.constants.CardType; import mage.constants.Duration; @@ -65,13 +66,15 @@ public class KamahlsDesire extends CardImpl { this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); - + // Enchanted creature has first strike. - ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield)); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield))); // Threshold - Enchanted creature gets +3/+0 as long as seven or more cards are in your graveyard. - ability.addEffect(new ConditionalContinuousEffect(new BoostEnchantedEffect(3, 0, Duration.WhileOnBattlefield), - new CardsInControllerGraveCondition(7), - "Threshold - Enchanted creature gets +3/+0 as long as seven or more cards are in your graveyard")); + ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostEnchantedEffect(3, 0, Duration.WhileOnBattlefield), + new CardsInControllerGraveCondition(7), + "Enchanted creature gets +3/+0 as long as seven or more cards are in your graveyard")); + ability.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/odyssey/KrosanAvenger.java b/Mage.Sets/src/mage/sets/odyssey/KrosanAvenger.java index 464cc2650d0..fefc46b79ba 100644 --- a/Mage.Sets/src/mage/sets/odyssey/KrosanAvenger.java +++ b/Mage.Sets/src/mage/sets/odyssey/KrosanAvenger.java @@ -32,10 +32,11 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.common.CardsInControllerGraveCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalGainActivatedAbility; +import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.RegenerateSourceEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; @@ -58,13 +59,12 @@ public class KrosanAvenger extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); // Threshold - {1}{G}: Regenerate Krosan Avenger. Activate this ability only if seven or more cards are in your graveyard. - Ability thresholdAbility = new ConditionalGainActivatedAbility(Zone.BATTLEFIELD, - new RegenerateSourceEffect(), - new ManaCostsImpl("{1}{G}"), - new CardsInControllerGraveCondition(7), - "Threshold - {1}{G}: Regenerate {this}. Activate this ability only if seven or more cards are in your graveyard."); + Ability thresholdAbility = new ConditionalActivatedAbility(Zone.BATTLEFIELD, + new RegenerateSourceEffect(), + new ManaCostsImpl("{1}{G}"), + new CardsInControllerGraveCondition(7)); + thresholdAbility.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(thresholdAbility); - } public KrosanAvenger(final KrosanAvenger card) { diff --git a/Mage.Sets/src/mage/sets/odyssey/KrosanBeast.java b/Mage.Sets/src/mage/sets/odyssey/KrosanBeast.java index 02404632e9b..32158cc963b 100644 --- a/Mage.Sets/src/mage/sets/odyssey/KrosanBeast.java +++ b/Mage.Sets/src/mage/sets/odyssey/KrosanBeast.java @@ -35,6 +35,7 @@ import mage.abilities.condition.common.CardsInControllerGraveCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -61,8 +62,9 @@ public class KrosanBeast extends CardImpl { new ConditionalContinuousEffect( new BoostSourceEffect(7, 7, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), - "Threshold - {this} gets +7/+7 as long as seven or more cards are in your graveyard" + "{this} gets +7/+7 as long as seven or more cards are in your graveyard" )); + thresholdAbility.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(thresholdAbility); } diff --git a/Mage.Sets/src/mage/sets/odyssey/MetamorphicWurm.java b/Mage.Sets/src/mage/sets/odyssey/MetamorphicWurm.java index e405fa85ea2..a4568538124 100644 --- a/Mage.Sets/src/mage/sets/odyssey/MetamorphicWurm.java +++ b/Mage.Sets/src/mage/sets/odyssey/MetamorphicWurm.java @@ -35,6 +35,7 @@ import mage.abilities.condition.common.CardsInControllerGraveCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -61,8 +62,9 @@ public class MetamorphicWurm extends CardImpl { new ConditionalContinuousEffect( new BoostSourceEffect(4, 4, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), - "Threshold - {this} gets +4/+4 as long as seven or more cards are in your graveyard" + "{this} gets +4/+4 as long as seven or more cards are in your graveyard" )); + thresholdAbility.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(thresholdAbility); } diff --git a/Mage.Sets/src/mage/sets/odyssey/MossfireEgg.java b/Mage.Sets/src/mage/sets/odyssey/MossfireEgg.java index 693f6be1ed4..2a1d5c5308f 100644 --- a/Mage.Sets/src/mage/sets/odyssey/MossfireEgg.java +++ b/Mage.Sets/src/mage/sets/odyssey/MossfireEgg.java @@ -51,7 +51,7 @@ public class MossfireEgg extends CardImpl { this.expansionSetCode = "ODY"; // {2}, {tap}, Sacrifice Mossfire Egg: Add {R}{G} to your mana pool. Draw a card. - ManaAbility ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 0, 0, 0, 0, 0), new ManaCostsImpl("{2}")); + ManaAbility ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 0, 0, 0, 0, 0, 0), new ManaCostsImpl("{2}")); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); ability.addEffect(new DrawCardSourceControllerEffect(1)); diff --git a/Mage.Sets/src/mage/sets/odyssey/MossfireValley.java b/Mage.Sets/src/mage/sets/odyssey/MossfireValley.java index a407388bb13..1b93c1255b5 100644 --- a/Mage.Sets/src/mage/sets/odyssey/MossfireValley.java +++ b/Mage.Sets/src/mage/sets/odyssey/MossfireValley.java @@ -49,7 +49,7 @@ public class MossfireValley extends CardImpl { this.expansionSetCode = "ODY"; // {1}, {tap}: Add {R}{G} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 0, 0, 0, 0, 0), new ManaCostsImpl("{1}")); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 0, 0, 0, 0, 0, 0), new ManaCostsImpl("{1}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/odyssey/MysticCrusader.java b/Mage.Sets/src/mage/sets/odyssey/MysticCrusader.java index b914a851837..fc0bb16ebe5 100644 --- a/Mage.Sets/src/mage/sets/odyssey/MysticCrusader.java +++ b/Mage.Sets/src/mage/sets/odyssey/MysticCrusader.java @@ -39,6 +39,7 @@ import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.ProtectionAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -52,7 +53,7 @@ import mage.filter.predicate.mageobject.ColorPredicate; * @author cbt33 */ public class MysticCrusader extends CardImpl { - + static final FilterCard filter = new FilterCard("black and from red"); static { @@ -73,8 +74,11 @@ public class MysticCrusader extends CardImpl { this.addAbility(new ProtectionAbility(filter)); // Threshold - As long as seven or more cards are in your graveyard, Mystic Crusader gets +1/+1 and has flying. Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( - new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), "Threshold - As long as seven or more cards are in your graveyard, {this} gets +1/+1")); - ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance()), new CardsInControllerGraveCondition(7), "and has flying")); + new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), + "As long as seven or more cards are in your graveyard, {this} gets +1/+1")); + ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance()), + new CardsInControllerGraveCondition(7), "and has flying")); + ability.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/odyssey/MysticPenitent.java b/Mage.Sets/src/mage/sets/odyssey/MysticPenitent.java index 6648625b93a..226ddf257ca 100644 --- a/Mage.Sets/src/mage/sets/odyssey/MysticPenitent.java +++ b/Mage.Sets/src/mage/sets/odyssey/MysticPenitent.java @@ -38,6 +38,7 @@ import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -63,8 +64,11 @@ public class MysticPenitent extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // Threshold - As long as seven or more cards are in your graveyard, Mystic Penitent gets +1/+1 and has flying. Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( - new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), "Threshold - As long as seven or more cards are in your graveyard, {this} gets +1/+1")); - ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance()), new CardsInControllerGraveCondition(7), "and has flying")); + new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), + "As long as seven or more cards are in your graveyard, {this} gets +1/+1")); + ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance()), + new CardsInControllerGraveCondition(7), "and has flying")); + ability.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/odyssey/MysticVisionary.java b/Mage.Sets/src/mage/sets/odyssey/MysticVisionary.java index 4bedbb634db..7a01a384c43 100644 --- a/Mage.Sets/src/mage/sets/odyssey/MysticVisionary.java +++ b/Mage.Sets/src/mage/sets/odyssey/MysticVisionary.java @@ -36,6 +36,7 @@ import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; @@ -58,7 +59,9 @@ public class MysticVisionary extends CardImpl { // Threshold - Mystic Visionary has flying as long as seven or more cards are in your graveyard. Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( - new GainAbilitySourceEffect(FlyingAbility.getInstance()), new CardsInControllerGraveCondition(7), "Threshold - {this} has flying as long as seven or more cards are in your graveyard.")); + new GainAbilitySourceEffect(FlyingAbility.getInstance()), new CardsInControllerGraveCondition(7), + "{this} has flying as long as seven or more cards are in your graveyard.")); + ability.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/odyssey/MysticZealot.java b/Mage.Sets/src/mage/sets/odyssey/MysticZealot.java index 25f028652ef..6672ae7ccde 100644 --- a/Mage.Sets/src/mage/sets/odyssey/MysticZealot.java +++ b/Mage.Sets/src/mage/sets/odyssey/MysticZealot.java @@ -37,6 +37,7 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -60,8 +61,11 @@ public class MysticZealot extends CardImpl { // Threshold - As long as seven or more cards are in your graveyard, Mystic Zealot gets +1/+1 and has flying. Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( - new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), "Threshold - As long as seven or more cards are in your graveyard, {this} gets +1/+1")); - ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance()), new CardsInControllerGraveCondition(7), "and has flying")); + new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), + "As long as seven or more cards are in your graveyard, {this} gets +1/+1")); + ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance()), + new CardsInControllerGraveCondition(7), "and has flying")); + ability.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/odyssey/NantukoElder.java b/Mage.Sets/src/mage/sets/odyssey/NantukoElder.java index 8b72ec99cf2..746e55b804e 100644 --- a/Mage.Sets/src/mage/sets/odyssey/NantukoElder.java +++ b/Mage.Sets/src/mage/sets/odyssey/NantukoElder.java @@ -53,7 +53,7 @@ public class NantukoElder extends CardImpl { this.toughness = new MageInt(2); // {tap}: Add {C}{G} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 0, 0, 1,0 ), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 0, 0, 0, 0, 1), new TapSourceCost())); } diff --git a/Mage.Sets/src/mage/sets/odyssey/NimbleMongoose.java b/Mage.Sets/src/mage/sets/odyssey/NimbleMongoose.java index 062a6df78bb..b806c1a4401 100644 --- a/Mage.Sets/src/mage/sets/odyssey/NimbleMongoose.java +++ b/Mage.Sets/src/mage/sets/odyssey/NimbleMongoose.java @@ -32,12 +32,14 @@ import java.util.UUID; import mage.constants.CardType; import mage.constants.Rarity; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.CardsInControllerGraveCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.ShroudAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.Duration; import mage.constants.Zone; @@ -58,7 +60,12 @@ public class NimbleMongoose extends CardImpl { // Shroud this.addAbility(ShroudAbility.getInstance()); // Threshold - Nimble Mongoose gets +2/+2 as long as seven or more cards are in your graveyard. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), " Threshold - {this} gets +2/+2 as long as seven or more cards are in your graveyard"))); + + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), + "{this} gets +2/+2 as long as seven or more cards are in your graveyard")); + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); } public NimbleMongoose(final NimbleMongoose card) { diff --git a/Mage.Sets/src/mage/sets/odyssey/NomadDecoy.java b/Mage.Sets/src/mage/sets/odyssey/NomadDecoy.java index b2befb9492c..d76fe071e63 100644 --- a/Mage.Sets/src/mage/sets/odyssey/NomadDecoy.java +++ b/Mage.Sets/src/mage/sets/odyssey/NomadDecoy.java @@ -31,20 +31,20 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.CardsInControllerGraveCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.TapTargetEffect; -import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; import mage.target.common.TargetCreaturePermanent; /** + * * @author cbt33 */ @@ -64,14 +64,16 @@ public class NomadDecoy extends CardImpl { ability.addTarget(new TargetCreaturePermanent()); ability.addCost(new TapSourceCost()); 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 SimpleActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), new ManaCostsImpl("{W}{W}")); - thresholdAbility.addTarget(new TargetCreaturePermanent(2)); + Ability thresholdAbility = new ConditionalActivatedAbility(Zone.BATTLEFIELD, + new TapTargetEffect(), + new ManaCostsImpl("{W}{W}"), + new CardsInControllerGraveCondition(7)); thresholdAbility.addCost(new TapSourceCost()); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new GainAbilitySourceEffect(thresholdAbility), - new CardsInControllerGraveCondition(7), - "Threshold - {W}{W}, {T}: Tap two target creatures. Activate this ability only if seven or more cards are in your graveyard."))); + thresholdAbility.addTarget(new TargetCreaturePermanent(2)); + thresholdAbility.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(thresholdAbility); } public NomadDecoy(final NomadDecoy card) { diff --git a/Mage.Sets/src/mage/sets/odyssey/NomadStadium.java b/Mage.Sets/src/mage/sets/odyssey/NomadStadium.java index ab751c5a7b8..efc1b43529e 100644 --- a/Mage.Sets/src/mage/sets/odyssey/NomadStadium.java +++ b/Mage.Sets/src/mage/sets/odyssey/NomadStadium.java @@ -33,11 +33,12 @@ import mage.abilities.condition.common.CardsInControllerGraveCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalGainActivatedAbility; +import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.mana.WhiteManaAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; @@ -58,13 +59,13 @@ public 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 ConditionalGainActivatedAbility(Zone.BATTLEFIELD, + Ability thresholdAbility = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(4), new ManaCostsImpl("{W}"), - new CardsInControllerGraveCondition(7), - "Threshold - {W}, {T}, Sacrifice {this}: You gain 4 life. Activate this ability only if seven or more cards are in your graveyard."); + new CardsInControllerGraveCondition(7)); thresholdAbility.addCost(new TapSourceCost()); thresholdAbility.addCost(new SacrificeSourceCost()); + thresholdAbility.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(thresholdAbility); } diff --git a/Mage.Sets/src/mage/sets/odyssey/NutCollector.java b/Mage.Sets/src/mage/sets/odyssey/NutCollector.java index 1541dadc35f..2be1a11f985 100644 --- a/Mage.Sets/src/mage/sets/odyssey/NutCollector.java +++ b/Mage.Sets/src/mage/sets/odyssey/NutCollector.java @@ -29,6 +29,7 @@ package mage.sets.odyssey; import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.CardsInControllerGraveCondition; @@ -36,6 +37,7 @@ import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -50,9 +52,9 @@ import mage.game.permanent.token.SquirrelToken; * @author cbt33 */ public class NutCollector extends CardImpl { - + private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("squirrel"); - + static { filter.add(new SubtypePredicate("Squirrel")); } @@ -69,10 +71,11 @@ public class NutCollector extends CardImpl { // At the beginning of your upkeep, you may put a 1/1 green Squirrel creature token onto the battlefield. this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new SquirrelToken()), TargetController.YOU, true)); // Threshold - Squirrel creatures get +2/+2 as long as seven or more cards are in your graveyard. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, - new ConditionalContinuousEffect(new BoostAllEffect(2, 2, Duration.WhileOnBattlefield, filter, false), - new CardsInControllerGraveCondition(7), - "Threshold - Squirrel creatures get +2/+2 as long as seven or more cards are in your graveyard"))); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, + new ConditionalContinuousEffect(new BoostAllEffect(2, 2, Duration.WhileOnBattlefield, filter, false), + new CardsInControllerGraveCondition(7), "Squirrel creatures get +2/+2 as long as seven or more cards are in your graveyard")); + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); } public NutCollector(final NutCollector card) { diff --git a/Mage.Sets/src/mage/sets/odyssey/OvereagerApprentice.java b/Mage.Sets/src/mage/sets/odyssey/OvereagerApprentice.java index b7aaa015818..26e4ea4c71e 100644 --- a/Mage.Sets/src/mage/sets/odyssey/OvereagerApprentice.java +++ b/Mage.Sets/src/mage/sets/odyssey/OvereagerApprentice.java @@ -56,7 +56,7 @@ public class OvereagerApprentice extends CardImpl { this.toughness = new MageInt(2); // Discard a card, Sacrifice Overeager Apprentice: Add {B}{B}{B} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new BasicManaEffect(new Mana(0, 0, 0, 0, 3, 0, 0)), new DiscardCardCost()); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new BasicManaEffect(new Mana(0, 0, 0, 0, 3, 0, 0, 0)), new DiscardCardCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/odyssey/PatriarchsDesire.java b/Mage.Sets/src/mage/sets/odyssey/PatriarchsDesire.java index ff1601181e2..8f5b923c02d 100644 --- a/Mage.Sets/src/mage/sets/odyssey/PatriarchsDesire.java +++ b/Mage.Sets/src/mage/sets/odyssey/PatriarchsDesire.java @@ -29,16 +29,19 @@ package mage.sets.odyssey; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.CardsInControllerGraveCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; +import mage.constants.Zone; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; @@ -60,15 +63,16 @@ public class PatriarchsDesire extends CardImpl { this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); - + // Enchanted creature gets +2/-2. - ability.addEffect(new BoostEnchantedEffect(2, -2, Duration.WhileOnBattlefield)); - + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, -2, Duration.WhileOnBattlefield))); + // Threshold - Enchanted creature gets an additional +2/-2 as long as seven or more cards are in your graveyard. - ability.addEffect(new ConditionalContinuousEffect(new BoostEnchantedEffect(2, -2, - Duration.WhileOnBattlefield), - new CardsInControllerGraveCondition(7), - "

Threshold - Enchanted creature gets an additional +2/-2 as long as seven or more cards are in your graveyard." )); + ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostEnchantedEffect(2, -2, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), + "Enchanted creature gets an additional +2/-2 as long as seven or more cards are in your graveyard.")); + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); } public PatriarchsDesire(final PatriarchsDesire card) { diff --git a/Mage.Sets/src/mage/sets/odyssey/PilgrimOfVirtue.java b/Mage.Sets/src/mage/sets/odyssey/PilgrimOfVirtue.java index 0a223a2fa9d..a54f9efd19d 100644 --- a/Mage.Sets/src/mage/sets/odyssey/PilgrimOfVirtue.java +++ b/Mage.Sets/src/mage/sets/odyssey/PilgrimOfVirtue.java @@ -54,10 +54,10 @@ import mage.target.TargetSource; * @author cbt33, Plopman (Circle of Protection: Red) */ public class PilgrimOfVirtue extends CardImpl { - - static final FilterCard filter = new FilterCard("black"); - - static{ + + static final FilterCard filter = new FilterCard("black"); + + static { filter.add(new ColorPredicate(ObjectColor.BLACK)); } @@ -91,15 +91,16 @@ public class PilgrimOfVirtue extends CardImpl { class PilgrimOfVirtueEffect extends PreventionEffectImpl { private static final FilterObject filter = new FilterObject("black source"); - static{ + + static { filter.add(new ColorPredicate(ObjectColor.BLACK)); - } - private TargetSource target; + } + private final TargetSource target; public PilgrimOfVirtueEffect() { super(Duration.EndOfTurn); target = new TargetSource(filter); - + staticText = "The next time a black source of your choice would deal damage to you this turn, prevent that damage"; } diff --git a/Mage.Sets/src/mage/sets/odyssey/RepentantVampire.java b/Mage.Sets/src/mage/sets/odyssey/RepentantVampire.java index c2062edc5ef..3c87287e422 100644 --- a/Mage.Sets/src/mage/sets/odyssey/RepentantVampire.java +++ b/Mage.Sets/src/mage/sets/odyssey/RepentantVampire.java @@ -43,6 +43,7 @@ import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -79,13 +80,14 @@ public class RepentantVampire extends CardImpl { Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( new BecomesColorSourceEffect(ObjectColor.WHITE, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), - "Threshold - As long as seven or more cards are in your graveyard, {this} is white")); + "As long as seven or more cards are in your graveyard, {this} is white")); Ability gainedAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new TapSourceCost()); gainedAbility.addTarget(new TargetCreaturePermanent(filter)); ability.addEffect(new ConditionalContinuousEffect( new GainAbilitySourceEffect(gainedAbility, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), - "and has \"{t}: Destroy target black creature.\"")); + "and has \"{T}: Destroy target black creature.\"")); + ability.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/odyssey/ShadowbloodEgg.java b/Mage.Sets/src/mage/sets/odyssey/ShadowbloodEgg.java index c2de9c96901..a6b5297b2ab 100644 --- a/Mage.Sets/src/mage/sets/odyssey/ShadowbloodEgg.java +++ b/Mage.Sets/src/mage/sets/odyssey/ShadowbloodEgg.java @@ -51,7 +51,7 @@ public class ShadowbloodEgg extends CardImpl { this.expansionSetCode = "ODY"; // {2}, {tap}, Sacrifice Shadowblood Egg: Add {B}{R} to your mana pool. Draw a card. - ManaAbility ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 0, 1, 0, 0), new ManaCostsImpl("{2}")); + ManaAbility ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 0, 1, 0, 0, 0), new ManaCostsImpl("{2}")); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); ability.addEffect(new DrawCardSourceControllerEffect(1)); diff --git a/Mage.Sets/src/mage/sets/odyssey/ShadowbloodRidge.java b/Mage.Sets/src/mage/sets/odyssey/ShadowbloodRidge.java index 310e7bb2a16..e91f1e8e43e 100644 --- a/Mage.Sets/src/mage/sets/odyssey/ShadowbloodRidge.java +++ b/Mage.Sets/src/mage/sets/odyssey/ShadowbloodRidge.java @@ -49,7 +49,7 @@ public class ShadowbloodRidge extends CardImpl { this.expansionSetCode = "ODY"; // {1}, {tap}: Add {B}{R} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 0, 1, 0, 0), new ManaCostsImpl("{1}")); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 0, 1, 0, 0, 0), new ManaCostsImpl("{1}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/odyssey/SkycloudEgg.java b/Mage.Sets/src/mage/sets/odyssey/SkycloudEgg.java index 622f19765c1..81cd307b026 100644 --- a/Mage.Sets/src/mage/sets/odyssey/SkycloudEgg.java +++ b/Mage.Sets/src/mage/sets/odyssey/SkycloudEgg.java @@ -51,7 +51,7 @@ public class SkycloudEgg extends CardImpl { this.expansionSetCode = "ODY"; // {2}, {tap}, Sacrifice Skycloud Egg: Add {W}{U} to your mana pool. Draw a card. - ManaAbility ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 1, 0, 0, 0), new ManaCostsImpl("{2}")); + ManaAbility ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 1, 0, 0, 0, 0), new ManaCostsImpl("{2}")); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); ability.addEffect(new DrawCardSourceControllerEffect(1)); diff --git a/Mage.Sets/src/mage/sets/odyssey/SkycloudExpanse.java b/Mage.Sets/src/mage/sets/odyssey/SkycloudExpanse.java index 15d3f42c90b..e135e7e6150 100644 --- a/Mage.Sets/src/mage/sets/odyssey/SkycloudExpanse.java +++ b/Mage.Sets/src/mage/sets/odyssey/SkycloudExpanse.java @@ -49,7 +49,7 @@ public class SkycloudExpanse extends CardImpl { this.expansionSetCode = "ODY"; // {1}, {tap}: Add {W}{U} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 1, 0, 0, 0), new ManaCostsImpl("{1}")); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 1, 0, 0, 0, 0), new ManaCostsImpl("{1}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/odyssey/SpringingTiger.java b/Mage.Sets/src/mage/sets/odyssey/SpringingTiger.java index a386a1624ad..deaa3ddede2 100644 --- a/Mage.Sets/src/mage/sets/odyssey/SpringingTiger.java +++ b/Mage.Sets/src/mage/sets/odyssey/SpringingTiger.java @@ -35,6 +35,7 @@ import mage.abilities.condition.common.CardsInControllerGraveCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -60,8 +61,9 @@ public class SpringingTiger extends CardImpl { new ConditionalContinuousEffect( new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), - "Threshold - {this} gets +2/+2 as long as seven or more cards are in your graveyard" + "{this} gets +2/+2 as long as seven or more cards are in your graveyard" )); + thresholdAbility.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(thresholdAbility); } diff --git a/Mage.Sets/src/mage/sets/odyssey/SungrassEgg.java b/Mage.Sets/src/mage/sets/odyssey/SungrassEgg.java index 06a04ccfed1..6c73e8640a4 100644 --- a/Mage.Sets/src/mage/sets/odyssey/SungrassEgg.java +++ b/Mage.Sets/src/mage/sets/odyssey/SungrassEgg.java @@ -51,7 +51,7 @@ public class SungrassEgg extends CardImpl { this.expansionSetCode = "ODY"; // {2}, {tap}, Sacrifice Sungrass Egg: Add {G}{W} to your mana pool. Draw a card. - ManaAbility ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 1, 0, 0, 0), new ManaCostsImpl("{2}")); + ManaAbility ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 1, 0, 0, 0, 0), new ManaCostsImpl("{2}")); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); ability.addEffect(new DrawCardSourceControllerEffect(1)); diff --git a/Mage.Sets/src/mage/sets/odyssey/SungrassPrairie.java b/Mage.Sets/src/mage/sets/odyssey/SungrassPrairie.java index bd165747fb4..1144357afd0 100644 --- a/Mage.Sets/src/mage/sets/odyssey/SungrassPrairie.java +++ b/Mage.Sets/src/mage/sets/odyssey/SungrassPrairie.java @@ -49,7 +49,7 @@ public class SungrassPrairie extends CardImpl { this.expansionSetCode = "ODY"; // {1}, {tap}: Add {G}{W} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 1, 0, 0, 0), new ManaCostsImpl("{1}")); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 1, 0, 0, 0, 0), new ManaCostsImpl("{1}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/odyssey/UnifyingTheory.java b/Mage.Sets/src/mage/sets/odyssey/UnifyingTheory.java index be4bf8d5bf1..6bc6d87e0f1 100644 --- a/Mage.Sets/src/mage/sets/odyssey/UnifyingTheory.java +++ b/Mage.Sets/src/mage/sets/odyssey/UnifyingTheory.java @@ -95,7 +95,7 @@ class UnifyingTheoryEffect extends OneShotEffect { if (caster != null) { if (caster.chooseUse(Outcome.DrawCard, "Pay {2} to draw a card?", source, game)) { Cost cost = new ManaCostsImpl("{2}"); - if (cost.pay(source, game, source.getSourceId(), caster.getId(), false)) { + if (cost.pay(source, game, source.getSourceId(), caster.getId(), false, null)) { caster.drawCards(1, game); } } diff --git a/Mage.Sets/src/mage/sets/odyssey/WaywardAngel.java b/Mage.Sets/src/mage/sets/odyssey/WaywardAngel.java index 0c65b84ddad..3c703ea8b47 100644 --- a/Mage.Sets/src/mage/sets/odyssey/WaywardAngel.java +++ b/Mage.Sets/src/mage/sets/odyssey/WaywardAngel.java @@ -43,6 +43,7 @@ import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -73,23 +74,24 @@ public class WaywardAngel extends CardImpl { Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( new BoostSourceEffect(3, 3, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), - "Threshold - As long as seven or more cards are in your graveyard, {this} gets +3/+3,")); + "As long as seven or more cards are in your graveyard, {this} gets +3/+3")); ability.addEffect(new ConditionalContinuousEffect( new BecomesColorSourceEffect(ObjectColor.BLACK, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), - " is black,")); + ", is black")); ability.addEffect(new ConditionalContinuousEffect( new GainAbilitySourceEffect(TrampleAbility.getInstance()), new CardsInControllerGraveCondition(7), - " has trample,")); + ", has trample")); Ability gainedAbility = new BeginningOfUpkeepTriggeredAbility(new SacrificeControllerEffect(new FilterControlledCreaturePermanent(), 1, ""), TargetController.YOU, false); ability.addEffect(new ConditionalContinuousEffect( new GainAbilitySourceEffect(gainedAbility), new CardsInControllerGraveCondition(7), - " and has \"At the beginning of your upkeep, sacrifice a creature.\" ")); + "and has \"At the beginning of your upkeep, sacrifice a creature.\"")); + ability.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/odyssey/Werebear.java b/Mage.Sets/src/mage/sets/odyssey/Werebear.java index 165d82c9534..0a530c00347 100644 --- a/Mage.Sets/src/mage/sets/odyssey/Werebear.java +++ b/Mage.Sets/src/mage/sets/odyssey/Werebear.java @@ -36,6 +36,7 @@ import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.mana.GreenManaAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -65,10 +66,10 @@ public class Werebear extends CardImpl { new ConditionalContinuousEffect( new BoostSourceEffect(3, 3, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), - "Threshold - {this} gets +3/+3 as long as seven or more cards are in your graveyard" + "{this} gets +3/+3 as long as seven or more cards are in your graveyard" )); + thresholdAbility.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(thresholdAbility); - } public Werebear(final Werebear card) { diff --git a/Mage.Sets/src/mage/sets/onslaught/AkromasBlessing.java b/Mage.Sets/src/mage/sets/onslaught/AkromasBlessing.java index 4b301c061ec..262a42bd5bd 100644 --- a/Mage.Sets/src/mage/sets/onslaught/AkromasBlessing.java +++ b/Mage.Sets/src/mage/sets/onslaught/AkromasBlessing.java @@ -29,24 +29,15 @@ package mage.sets.onslaught; import java.util.UUID; import mage.MageObject; -import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.effects.common.continuous.GainProtectionFromColorAllEffect; import mage.abilities.keyword.CyclingAbility; -import mage.abilities.keyword.ProtectionAbility; import mage.cards.CardImpl; -import mage.choices.ChoiceColor; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Outcome; import mage.constants.Rarity; -import mage.filter.FilterCard; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.mageobject.ColorPredicate; -import mage.game.Game; -import mage.players.Player; + /** * @@ -60,7 +51,7 @@ public class AkromasBlessing extends CardImpl { // Choose a color. Creatures you control gain protection from the chosen color until end of turn. - this.getSpellAbility().addEffect(new AkromasBlessingChooseColorEffect()); + this.getSpellAbility().addEffect(new GainProtectionFromColorAllEffect(Duration.EndOfTurn, new FilterControlledCreaturePermanent("Creatures you control"))); // Cycling {W} this.addAbility(new CyclingAbility(new ManaCostsImpl("{W}"))); } @@ -74,46 +65,3 @@ public class AkromasBlessing extends CardImpl { return new AkromasBlessing(this); } } - -class AkromasBlessingChooseColorEffect extends OneShotEffect { - - public AkromasBlessingChooseColorEffect() { - super(Outcome.Benefit); - this.staticText = "Choose a color. Creatures you control gain protection from the chosen color until end of turn"; - } - - public AkromasBlessingChooseColorEffect(final AkromasBlessingChooseColorEffect effect) { - super(effect); - } - - @Override - public AkromasBlessingChooseColorEffect copy() { - return new AkromasBlessingChooseColorEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (sourceObject != null && controller != null) { - ChoiceColor choice = new ChoiceColor(); - while (!choice.isChosen()) { - controller.choose(outcome, choice, game); - if (!controller.canRespond()) { - return false; - } - } - if (choice.getColor() == null) { - return false; - } - game.informPlayers(sourceObject.getName() + ": " + controller.getLogName() + " has chosen " + choice.getChoice()); - FilterCard filterColor = new FilterCard(); - filterColor.add(new ColorPredicate(choice.getColor())); - filterColor.setMessage(choice.getChoice()); - ContinuousEffect effect = new GainAbilityAllEffect(new ProtectionAbility(new FilterCard(filterColor)), Duration.EndOfTurn, new FilterControlledCreaturePermanent()); - game.addEffect(effect, source); - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/sets/onslaught/AstralSlide.java b/Mage.Sets/src/mage/sets/onslaught/AstralSlide.java index dbdb507c03d..5802b12ed10 100644 --- a/Mage.Sets/src/mage/sets/onslaught/AstralSlide.java +++ b/Mage.Sets/src/mage/sets/onslaught/AstralSlide.java @@ -54,7 +54,6 @@ public class AstralSlide extends CardImpl { super(ownerId, 4, "Astral Slide", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); this.expansionSetCode = "ONS"; - // Whenever a player cycles a card, you may exile target creature. If you do, return that card to the battlefield under its owner's control at the beginning of the next end step. Ability ability = new CycleAllTriggeredAbility(new AstralSlideEffect(), true); ability.addTarget(new TargetCreaturePermanent()); @@ -71,7 +70,6 @@ public class AstralSlide extends CardImpl { } } - class AstralSlideEffect extends OneShotEffect { public AstralSlideEffect() { @@ -94,10 +92,7 @@ class AstralSlideEffect extends OneShotEffect { if (controller.moveCardToExileWithInfo(permanent, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true)) { //create delayed triggered ability AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnFromExileEffect(exileId, Zone.BATTLEFIELD, false)); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } } diff --git a/Mage.Sets/src/mage/sets/onslaught/ManaEchoes.java b/Mage.Sets/src/mage/sets/onslaught/ManaEchoes.java index 190644a4d8b..a213593f1cf 100644 --- a/Mage.Sets/src/mage/sets/onslaught/ManaEchoes.java +++ b/Mage.Sets/src/mage/sets/onslaught/ManaEchoes.java @@ -55,7 +55,7 @@ public class ManaEchoes extends CardImpl { this.expansionSetCode = "ONS"; // Whenever a creature enters the battlefield, you may add X mana of {C} to your mana pool, where X is the number of creatures you control that share a creature type with it. - this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, + this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new ManaEchoesEffect(), new FilterCreaturePermanent("a creature"), true, SetTargetPointer.PERMANENT, "")); } @@ -70,34 +70,34 @@ public class ManaEchoes extends CardImpl { } class ManaEchoesEffect extends OneShotEffect { - + public ManaEchoesEffect() { super(Outcome.Benefit); this.staticText = "you may add X mana of {C} to your mana pool, where X is the number of creatures you control that share a creature type with it"; } - + public ManaEchoesEffect(final ManaEchoesEffect effect) { super(effect); } - + @Override public ManaEchoesEffect copy() { return new ManaEchoesEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); + Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); if (controller != null && permanent != null) { int foundCreatures = 0; - for (Permanent perm: game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) { + for (Permanent perm : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) { if (CardUtil.shareSubtypes(permanent, perm)) { - foundCreatures ++; + foundCreatures++; } } if (foundCreatures > 0) { - controller.getManaPool().addMana(new Mana(0,0,0,0,0,foundCreatures,0), game, source); + controller.getManaPool().addMana(new Mana(0, 0, 0, 0, 0, 0, 0, foundCreatures), game, source); } return true; } diff --git a/Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java b/Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java index 53fd0d565b6..5f397a290e9 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java +++ b/Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java @@ -101,7 +101,7 @@ class BrainGorgersCounterSourceEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(outcome, "Sacrifice a creature to counter " + sourceObject.getIdName() + "?", source, game)) { - if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { + if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { game.informPlayers(player.getLogName() + " sacrifices a creature to counter " + sourceObject.getIdName() + "."); Spell spell = game.getStack().getSpell(source.getSourceId()); if (spell != null) { diff --git a/Mage.Sets/src/mage/sets/planarchaos/DashHopes.java b/Mage.Sets/src/mage/sets/planarchaos/DashHopes.java index d061e582a98..5c4a30e37be 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/DashHopes.java +++ b/Mage.Sets/src/mage/sets/planarchaos/DashHopes.java @@ -97,7 +97,7 @@ class DashHopesCounterSourceEffect extends OneShotEffect { cost.clearPaid(); if (cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(outcome, "Pay 5 life to counter " + sourceObject.getIdName() + "?", source, game)) { - if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { + if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { game.informPlayers(player.getLogName() + " pays 5 life to counter " + sourceObject.getIdName() + "."); Spell spell = game.getStack().getSpell(source.getSourceId()); if (spell != null) { diff --git a/Mage.Sets/src/mage/sets/planarchaos/DismalFailure.java b/Mage.Sets/src/mage/sets/planarchaos/DismalFailure.java new file mode 100644 index 00000000000..a6a9a3ab524 --- /dev/null +++ b/Mage.Sets/src/mage/sets/planarchaos/DismalFailure.java @@ -0,0 +1,99 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.planarchaos; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetSpell; + +/** + * + * @author LevelX2 + */ +public class DismalFailure extends CardImpl { + + public DismalFailure(UUID ownerId) { + super(ownerId, 39, "Dismal Failure", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{2}{U}{U}"); + this.expansionSetCode = "PLC"; + + // Counter target spell. Its controller discards a card. + this.getSpellAbility().addEffect(new DismalFailureEffect()); + this.getSpellAbility().addTarget(new TargetSpell()); + } + + public DismalFailure(final DismalFailure card) { + super(card); + } + + @Override + public DismalFailure copy() { + return new DismalFailure(this); + } +} + +class DismalFailureEffect extends OneShotEffect { + + public DismalFailureEffect() { + super(Outcome.Neutral); + this.staticText = "Counter target spell. Its controller discards a card"; + } + + public DismalFailureEffect(final DismalFailureEffect effect) { + super(effect); + } + + @Override + public DismalFailureEffect copy() { + return new DismalFailureEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + UUID targetId = source.getFirstTarget(); + Player controller = null; + boolean countered = false; + if (targetId != null) { + controller = game.getPlayer(game.getControllerId(targetId)); + } + if (targetId != null + && game.getStack().counter(targetId, source.getSourceId(), game)) { + countered = true; + } + if (controller != null) { + controller.discard(1, false, source, game); + } + return countered; + } +} diff --git a/Mage.Sets/src/mage/sets/planarchaos/FatalFrenzy.java b/Mage.Sets/src/mage/sets/planarchaos/FatalFrenzy.java index 0bbef4cfb3c..a912ce245a0 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/FatalFrenzy.java +++ b/Mage.Sets/src/mage/sets/planarchaos/FatalFrenzy.java @@ -99,10 +99,7 @@ class FatalFrenzyEffect extends OneShotEffect { SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice this", source.getControllerId()); sacrificeEffect.setTargetPointer(new FixedTarget(targetCreature, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } return true; } diff --git a/Mage.Sets/src/mage/sets/planarchaos/FreneticSliver.java b/Mage.Sets/src/mage/sets/planarchaos/FreneticSliver.java index bcc9c5e9fc7..28680d872d4 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/FreneticSliver.java +++ b/Mage.Sets/src/mage/sets/planarchaos/FreneticSliver.java @@ -35,7 +35,7 @@ import mage.abilities.condition.common.SourceOnBattlefieldCondition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ExileReturnToBattlefieldOwnerNextEndStepEffect; +import mage.abilities.effects.common.ExileReturnBattlefieldOwnerNextEndStepSourceEffect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.cards.CardImpl; import mage.constants.CardType; @@ -97,7 +97,7 @@ class FreneticSliverEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null) { if (player.flipCoin(game)) { - return new ExileReturnToBattlefieldOwnerNextEndStepEffect(true).apply(game, source); + return new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(true).apply(game, source); } else { Permanent perm = game.getPermanent(source.getSourceId()); if (perm != null) { diff --git a/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java b/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java index 31778c36699..29eae0ffc0c 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java +++ b/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java @@ -103,7 +103,7 @@ class CounterSourceEffect extends OneShotEffect { cost.clearPaid(); if (cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(outcome, "Discard three cards to counter " + sourceObject.getIdName() + "?", source, game)) { - if (cost.pay(source, game, source.getSourceId(), playerId, false)) { + if (cost.pay(source, game, source.getSourceId(), playerId, false, null)) { game.informPlayers(player.getLogName() + " discards 3 cards to counter " + sourceObject.getIdName() + "."); Spell spell = game.getStack().getSpell(source.getSourceId()); if (spell != null) { diff --git a/Mage.Sets/src/mage/sets/planarchaos/RadhaHeirToKeld.java b/Mage.Sets/src/mage/sets/planarchaos/RadhaHeirToKeld.java index 9e2eec190e9..c41d3211e57 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/RadhaHeirToKeld.java +++ b/Mage.Sets/src/mage/sets/planarchaos/RadhaHeirToKeld.java @@ -54,7 +54,7 @@ public class RadhaHeirToKeld extends CardImpl { this.toughness = new MageInt(2); // Whenever Radha, Heir to Keld attacks, you may add {R}{R} to your mana pool. - Ability ability = new AttacksTriggeredAbility(new BasicManaEffect(new Mana(2,0,0,0,0,0,0)), true); + Ability ability = new AttacksTriggeredAbility(new BasicManaEffect(new Mana(2,0,0,0,0,0,0, 0)), true); this.addAbility(ability); // {tap}: Add {G} to your mana pool. diff --git a/Mage.Sets/src/mage/sets/planarchaos/ShivanWumpus.java b/Mage.Sets/src/mage/sets/planarchaos/ShivanWumpus.java index 725ba9ff154..c84a23e79f0 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/ShivanWumpus.java +++ b/Mage.Sets/src/mage/sets/planarchaos/ShivanWumpus.java @@ -101,7 +101,7 @@ class ShivanWumpusEffect extends PutOnLibrarySourceEffect { if (player != null && cost.canPay(source, source.getSourceId(), playerId, game) && player.chooseUse(Outcome.Sacrifice, "Sacrifice a land?", source, game) - && cost.pay(source, game, source.getSourceId(), playerId, true)) { + && cost.pay(source, game, source.getSourceId(), playerId, true, null)) { costPaid = true; } } diff --git a/Mage.Sets/src/mage/sets/planarchaos/ShroudedLore.java b/Mage.Sets/src/mage/sets/planarchaos/ShroudedLore.java index a9ffdeab0bc..705affbb8bd 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/ShroudedLore.java +++ b/Mage.Sets/src/mage/sets/planarchaos/ShroudedLore.java @@ -118,7 +118,7 @@ class ShroudedLoreEffect extends OneShotEffect { if(!done) { if(cost.canPay(source, source.getSourceId(), you.getId(), game) && you.chooseUse(Outcome.Benefit, "Pay {B} to choose a different card ?", source, game)) { cost.clearPaid(); - if(!cost.pay(source, game, source.getSourceId(), you.getId(), false)) { + if(!cost.pay(source, game, source.getSourceId(), you.getId(), false, null)) { done = true; } } diff --git a/Mage.Sets/src/mage/sets/planarchaos/SimianSpiritGuide.java b/Mage.Sets/src/mage/sets/planarchaos/SimianSpiritGuide.java index 14b3897c0ee..195258ac368 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/SimianSpiritGuide.java +++ b/Mage.Sets/src/mage/sets/planarchaos/SimianSpiritGuide.java @@ -34,6 +34,7 @@ import mage.constants.Rarity; import mage.MageInt; import mage.Mana; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.effects.common.BasicManaEffect; import mage.abilities.mana.SimpleManaAbility; @@ -84,7 +85,7 @@ class ExileSourceFromHandCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Card card = game.getCard(sourceId); Player player = game.getPlayer(controllerId); if (player != null && player.getHand().contains(sourceId) && card != null) { diff --git a/Mage.Sets/src/mage/sets/planarchaos/UrborgTombOfYawgmoth.java b/Mage.Sets/src/mage/sets/planarchaos/UrborgTombOfYawgmoth.java index 5af6584bb8c..a8b09bd09f8 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/UrborgTombOfYawgmoth.java +++ b/Mage.Sets/src/mage/sets/planarchaos/UrborgTombOfYawgmoth.java @@ -52,9 +52,11 @@ public class UrborgTombOfYawgmoth extends CardImpl { this.supertype.add("Legendary"); // Each land is a Swamp in addition to its other land types. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(new BlackManaAbility(), Duration.WhileOnBattlefield, new FilterLandPermanent(),""))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AddCardSubtypeAllEffect())); - + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(new BlackManaAbility(), Duration.WhileOnBattlefield, new FilterLandPermanent(), + "Each land is a Swamp in addition to its other land types")); + ability.addEffect(new AddCardSubtypeAllEffect()); + this.addAbility(ability); + } public UrborgTombOfYawgmoth(final UrborgTombOfYawgmoth card) { @@ -67,14 +69,14 @@ public class UrborgTombOfYawgmoth extends CardImpl { } } - class AddCardSubtypeAllEffect extends ContinuousEffectImpl { private static final FilterLandPermanent filter = new FilterLandPermanent(); private static final String addedSubtype = "Swamp"; + public AddCardSubtypeAllEffect() { super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); - staticText = "Each land is a Swamp in addition to its other land types"; + staticText = ""; } public AddCardSubtypeAllEffect(final AddCardSubtypeAllEffect effect) { @@ -83,8 +85,8 @@ class AddCardSubtypeAllEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - for (Permanent perm: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { - if(perm != null && !perm.getSubtype().contains(addedSubtype)){ + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + if (perm != null && !perm.getSubtype().contains(addedSubtype)) { perm.getSubtype().add(addedSubtype); } } @@ -96,5 +98,4 @@ class AddCardSubtypeAllEffect extends ContinuousEffectImpl { return new AddCardSubtypeAllEffect(this); } - -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/planechase/BorosGarrison.java b/Mage.Sets/src/mage/sets/planechase/BorosGarrison.java index ad13fe1c655..86bc17f8657 100644 --- a/Mage.Sets/src/mage/sets/planechase/BorosGarrison.java +++ b/Mage.Sets/src/mage/sets/planechase/BorosGarrison.java @@ -61,7 +61,7 @@ public class BorosGarrison extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new ReturnToHandChosenControlledPermanentEffect(filter), false)); // {T}: Add {R}{W} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 1, 0, 0, 0), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 1, 0, 0, 0, 0), new TapSourceCost())); } public BorosGarrison(final BorosGarrison card) { diff --git a/Mage.Sets/src/mage/sets/planechase/DarkRitual.java b/Mage.Sets/src/mage/sets/planechase/DarkRitual.java index c972b4c29c5..2eb22a6b1f7 100644 --- a/Mage.Sets/src/mage/sets/planechase/DarkRitual.java +++ b/Mage.Sets/src/mage/sets/planechase/DarkRitual.java @@ -44,7 +44,7 @@ public class DarkRitual extends CardImpl { super(ownerId, 24, "Dark Ritual", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{B}"); this.expansionSetCode = "HOP"; - this.getSpellAbility().addEffect(new BasicManaEffect(new Mana(0, 0, 0, 0, 3, 0, 0))); + this.getSpellAbility().addEffect(new BasicManaEffect(new Mana(0, 0, 0, 0, 3, 0, 0, 0))); } public DarkRitual(final DarkRitual card) { diff --git a/Mage.Sets/src/mage/sets/planechase/GruulTurf.java b/Mage.Sets/src/mage/sets/planechase/GruulTurf.java index 8610a8ae2f6..6cba1ab5269 100644 --- a/Mage.Sets/src/mage/sets/planechase/GruulTurf.java +++ b/Mage.Sets/src/mage/sets/planechase/GruulTurf.java @@ -56,7 +56,7 @@ public class GruulTurf extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new ReturnToHandChosenControlledPermanentEffect(filter), false)); - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 0, 0, 0, 0, 0), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 0, 0, 0, 0, 0, 0), new TapSourceCost())); } public GruulTurf(final GruulTurf card) { diff --git a/Mage.Sets/src/mage/sets/planechase/RaziaBorosArchangel.java b/Mage.Sets/src/mage/sets/planechase/RaziaBorosArchangel.java index be5502dbe76..49aa60f7b73 100644 --- a/Mage.Sets/src/mage/sets/planechase/RaziaBorosArchangel.java +++ b/Mage.Sets/src/mage/sets/planechase/RaziaBorosArchangel.java @@ -82,7 +82,7 @@ public class RaziaBorosArchangel extends CardImpl { target.setTargetTag(1); ability.addTarget(target); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature (damage is redirected to)"); + FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature (damage is redirected to)"); filter.add(new AnotherTargetPredicate(2)); target = new TargetCreaturePermanent(filter); target.setTargetTag(2); @@ -133,9 +133,11 @@ class RaziaBorosArchangelEffect extends RedirectionEffect { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getTargetId().equals(getTargetPointer().getFirst(game, source))) { - if (redirectToObject.equals(new MageObjectReference(source.getTargets().get(1).getFirstTarget(), game))) { - redirectTarget = source.getTargets().get(1); - return true; + if (game.getControllerId(redirectToObject.getSourceId()) != null) { + if (redirectToObject.equals(new MageObjectReference(source.getTargets().get(1).getFirstTarget(), game))) { + redirectTarget = source.getTargets().get(1); + return true; + } } } return false; diff --git a/Mage.Sets/src/mage/sets/planechase/ThirstForKnowledge.java b/Mage.Sets/src/mage/sets/planechase/ThirstForKnowledge.java index a7106c6c677..76916dd11e4 100644 --- a/Mage.Sets/src/mage/sets/planechase/ThirstForKnowledge.java +++ b/Mage.Sets/src/mage/sets/planechase/ThirstForKnowledge.java @@ -96,7 +96,7 @@ class ThirstforKnowledgeEffect extends OneShotEffect { && you.chooseUse(Outcome.Discard, "Do you want to discard an artifact? If you don't, you must discard 2 cards", source, game)) { Cost cost = new DiscardTargetCost(new TargetCardInHand(filter)); if (cost.canPay(source, source.getSourceId(), you.getId(), game)) { - if (cost.pay(source, game, source.getSourceId(), you.getId(), false)) { + if (cost.pay(source, game, source.getSourceId(), you.getId(), false, null)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/planechase/VedalkenEngineer.java b/Mage.Sets/src/mage/sets/planechase/VedalkenEngineer.java index 2e3e3d640d6..10b3c452fbd 100644 --- a/Mage.Sets/src/mage/sets/planechase/VedalkenEngineer.java +++ b/Mage.Sets/src/mage/sets/planechase/VedalkenEngineer.java @@ -114,7 +114,7 @@ class VedalkenEngineerAbility extends ManaAbility { public VedalkenEngineerAbility(Cost cost, int amount, ConditionalManaBuilder manaBuilder) { super(Zone.BATTLEFIELD, new VedalkenEngineerEffect(amount, manaBuilder), cost); - this.netMana.add(new Mana(0,0,0,0,0,0, amount)); + this.netMana.add(new Mana(0,0,0,0,0,0, amount, 0)); } public VedalkenEngineerAbility(final VedalkenEngineerAbility ability) { diff --git a/Mage.Sets/src/mage/sets/planeshift/MorgueToad.java b/Mage.Sets/src/mage/sets/planeshift/MorgueToad.java index c12ceac6f83..35c78b5782a 100644 --- a/Mage.Sets/src/mage/sets/planeshift/MorgueToad.java +++ b/Mage.Sets/src/mage/sets/planeshift/MorgueToad.java @@ -53,7 +53,7 @@ public class MorgueToad extends CardImpl { this.toughness = new MageInt(2); // Sacrifice Morgue Toad: Add {U}{R} to your mana pool. - SimpleManaAbility ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 1, 0, 0, 0, 0), new SacrificeSourceCost()); + SimpleManaAbility ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 1, 0, 0, 0, 0, 0), new SacrificeSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/planeshift/PhyrexianTyranny.java b/Mage.Sets/src/mage/sets/planeshift/PhyrexianTyranny.java index d9f60ea27fc..4763d4385b4 100644 --- a/Mage.Sets/src/mage/sets/planeshift/PhyrexianTyranny.java +++ b/Mage.Sets/src/mage/sets/planeshift/PhyrexianTyranny.java @@ -127,7 +127,7 @@ class PhyrexianTyrannyEffect extends OneShotEffect { Player player = game.getPlayer(targetPointer.getFirst(game, source)); if (player != null) { Cost cost = new GenericManaCost(2); - if (!cost.pay(source, game, player.getId(), player.getId(), false)) { + if (!cost.pay(source, game, player.getId(), player.getId(), false, null)) { player.damage(2, source.getSourceId(), game, false, true); } return true; diff --git a/Mage.Sets/src/mage/sets/planeshift/QuirionExplorer.java b/Mage.Sets/src/mage/sets/planeshift/QuirionExplorer.java index bccab7725ad..680949940a6 100644 --- a/Mage.Sets/src/mage/sets/planeshift/QuirionExplorer.java +++ b/Mage.Sets/src/mage/sets/planeshift/QuirionExplorer.java @@ -29,10 +29,11 @@ package mage.sets.planeshift; import java.util.UUID; import mage.MageInt; -import mage.abilities.mana.AnyColorOpponentLandsProduceManaAbility; +import mage.abilities.mana.AnyColorLandsProduceManaAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; +import mage.constants.TargetController; /** * @@ -50,7 +51,7 @@ public class QuirionExplorer extends CardImpl { this.toughness = new MageInt(1); // {T}: Add to your mana pool one mana of any color that a land an opponent controls could produce. - this.addAbility(new AnyColorOpponentLandsProduceManaAbility()); + this.addAbility(new AnyColorLandsProduceManaAbility(TargetController.OPPONENT)); } public QuirionExplorer(final QuirionExplorer card) { diff --git a/Mage.Sets/src/mage/sets/prereleaseevents/DjinnIlluminatus.java b/Mage.Sets/src/mage/sets/prereleaseevents/DjinnIlluminatus.java new file mode 100644 index 00000000000..4bb6dca9ede --- /dev/null +++ b/Mage.Sets/src/mage/sets/prereleaseevents/DjinnIlluminatus.java @@ -0,0 +1,125 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prereleaseevents; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.ReplicateAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; +import mage.filter.common.FilterInstantOrSorcerySpell; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.game.stack.StackObject; + +/** + * + * @author LevelX2 + */ +public class DjinnIlluminatus extends CardImpl { + + public DjinnIlluminatus(UUID ownerId) { + super(ownerId, 28, "Djinn Illuminatus", Rarity.SPECIAL, new CardType[]{CardType.CREATURE}, "{5}{U/R}{U/R}"); + this.expansionSetCode = "PTC"; + this.subtype.add("Djinn"); + this.power = new MageInt(3); + this.toughness = new MageInt(5); + + // ({U/R} can be paid with either {U} or {R}.) + // Flying + this.addAbility(FlyingAbility.getInstance()); + // Each instant and sorcery spell you cast has replicate. The replicate cost is equal to its mana cost. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DjinnIlluminatusGainReplicateEffect())); + + } + + public DjinnIlluminatus(final DjinnIlluminatus card) { + super(card); + } + + @Override + public DjinnIlluminatus copy() { + return new DjinnIlluminatus(this); + } +} + +class DjinnIlluminatusGainReplicateEffect extends ContinuousEffectImpl { + + private final static FilterInstantOrSorcerySpell filter = new FilterInstantOrSorcerySpell(); + private final Map replicateAbilities = new HashMap<>(); + + public DjinnIlluminatusGainReplicateEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = "Each instant and sorcery spell you cast has replicate. The replicate cost is equal to its mana cost " + + "(When you cast it, copy it for each time you paid its replicate cost. You may choose new targets for the copies.)"; + } + + public DjinnIlluminatusGainReplicateEffect(final DjinnIlluminatusGainReplicateEffect effect) { + super(effect); + this.replicateAbilities.putAll(replicateAbilities); + } + + @Override + public DjinnIlluminatusGainReplicateEffect copy() { + return new DjinnIlluminatusGainReplicateEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (StackObject stackObject : game.getStack()) { + // only spells cast, so no copies of spells + if ((stackObject instanceof Spell) && !stackObject.isCopy() && stackObject.getControllerId().equals(source.getControllerId())) { + Spell spell = (Spell) stackObject; + if (filter.match(stackObject, game)) { + ReplicateAbility replicateAbility = replicateAbilities.get(spell.getId()); + if (replicateAbility == null) { + replicateAbility = new ReplicateAbility(spell.getCard(), spell.getSpellAbility().getManaCosts().getText()); + replicateAbilities.put(spell.getId(), replicateAbility); + } + game.getState().addOtherAbility(spell.getCard(), replicateAbility, false); // Do not copy because paid and # of activations state is handled in the baility + } + } + } + if (game.getStack().isEmpty()) { + replicateAbilities.clear(); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/prereleaseevents/Glory.java b/Mage.Sets/src/mage/sets/prereleaseevents/Glory.java new file mode 100644 index 00000000000..33a30193b97 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prereleaseevents/Glory.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prereleaseevents; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.GainProtectionFromColorAllEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class Glory extends CardImpl { + + public Glory(UUID ownerId) { + super(ownerId, 17, "Glory", Rarity.SPECIAL, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); + this.expansionSetCode = "PTC"; + this.subtype.add("Incarnation"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // {2}{W}: Choose a color. Creatures you control gain protection from the chosen color until end of turn. Activate this ability only if Glory is in your graveyard. + Effect effect = new GainProtectionFromColorAllEffect(Duration.EndOfTurn, new FilterControlledCreaturePermanent("Creatures you control")); + effect.setText("Choose a color. Creatures you control gain protection from the chosen color until end of turn. Activate this ability only if {this} is in your graveyard."); + this.addAbility(new SimpleActivatedAbility(Zone.GRAVEYARD, effect, new ManaCostsImpl("{2}{W}"))); + } + + public Glory(final Glory card) { + super(card); + } + + @Override + public Glory copy() { + return new Glory(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/AvatarOfHope.java b/Mage.Sets/src/mage/sets/prophecy/AvatarOfHope.java index 13716f9a91c..caf303a3c11 100644 --- a/Mage.Sets/src/mage/sets/prophecy/AvatarOfHope.java +++ b/Mage.Sets/src/mage/sets/prophecy/AvatarOfHope.java @@ -130,12 +130,12 @@ class AdjustingCostsEffect extends CostModificationEffectImpl { Mana mana = spellAbility.getManaCostsToPay().getMana(); Player player = game.getPlayer(source.getControllerId()); - if (mana.getColorless() > 0 && player != null && player.getLife() < 4) { - int newCount = mana.getColorless() - 6; + if (mana.getGeneric() > 0 && player != null && player.getLife() < 4) { + int newCount = mana.getGeneric() - 6; if (newCount < 0) { newCount = 0; } - mana.setColorless(newCount); + mana.setGeneric(newCount); spellAbility.getManaCostsToPay().load(mana.toString()); return true; } diff --git a/Mage.Sets/src/mage/sets/prophecy/AvatarOfMight.java b/Mage.Sets/src/mage/sets/prophecy/AvatarOfMight.java index 8008f96f3df..f542af804fb 100644 --- a/Mage.Sets/src/mage/sets/prophecy/AvatarOfMight.java +++ b/Mage.Sets/src/mage/sets/prophecy/AvatarOfMight.java @@ -91,12 +91,12 @@ class AvatarOfMightCostReductionEffect extends CostModificationEffectImpl { public boolean apply(Game game, Ability source, Ability abilityToModify) { SpellAbility spellAbility = (SpellAbility) abilityToModify; Mana mana = spellAbility.getManaCostsToPay().getMana(); - if (mana.getColorless() > 0) { - int newCount = mana.getColorless() - 6; + if (mana.getGeneric() > 0) { + int newCount = mana.getGeneric() - 6; if (newCount < 0) { newCount = 0; } - mana.setColorless(newCount); + mana.setGeneric(newCount); spellAbility.getManaCostsToPay().load(mana.toString()); return true; } diff --git a/Mage.Sets/src/mage/sets/prophecy/AvatarOfWill.java b/Mage.Sets/src/mage/sets/prophecy/AvatarOfWill.java index 2dbd76b18b1..4a29fbadd8a 100644 --- a/Mage.Sets/src/mage/sets/prophecy/AvatarOfWill.java +++ b/Mage.Sets/src/mage/sets/prophecy/AvatarOfWill.java @@ -90,12 +90,12 @@ class AvatarOfWillCostReductionEffect extends CostModificationEffectImpl { public boolean apply(Game game, Ability source, Ability abilityToModify) { SpellAbility spellAbility = (SpellAbility) abilityToModify; Mana mana = spellAbility.getManaCostsToPay().getMana(); - if (mana.getColorless() > 0) { - int newCount = mana.getColorless() - 6; + if (mana.getGeneric() > 0) { + int newCount = mana.getGeneric() - 6; if (newCount < 0) { newCount = 0; } - mana.setColorless(newCount); + mana.setGeneric(newCount); spellAbility.getManaCostsToPay().load(mana.toString()); return true; } diff --git a/Mage.Sets/src/mage/sets/prophecy/RhysticStudy.java b/Mage.Sets/src/mage/sets/prophecy/RhysticStudy.java index d0864c9e789..8e852eb94d9 100644 --- a/Mage.Sets/src/mage/sets/prophecy/RhysticStudy.java +++ b/Mage.Sets/src/mage/sets/prophecy/RhysticStudy.java @@ -92,7 +92,7 @@ class RhysticStudyDrawEffect extends OneShotEffect { if (controller != null && opponent != null && sourceObject != null) { Cost cost = new GenericManaCost(1); String message = "Would you like to pay {1} to prevent the opponent to draw a card?"; - if (!(opponent.chooseUse(Outcome.Benefit, message, source, game) && cost.pay(source, game, source.getSourceId(), opponent.getId(), false))) { + if (!(opponent.chooseUse(Outcome.Benefit, message, source, game) && cost.pay(source, game, source.getSourceId(), opponent.getId(), false, null))) { if(controller.chooseUse(Outcome.DrawCard, "Draw a card (" + sourceObject.getLogName() +")", source, game)) { controller.drawCards(1, game); } diff --git a/Mage.Sets/src/mage/sets/prophecy/StealStrength.java b/Mage.Sets/src/mage/sets/prophecy/StealStrength.java index c0dc42b53d9..514b0001b8c 100644 --- a/Mage.Sets/src/mage/sets/prophecy/StealStrength.java +++ b/Mage.Sets/src/mage/sets/prophecy/StealStrength.java @@ -37,6 +37,8 @@ import mage.constants.Layer; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.SubLayer; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; @@ -53,7 +55,17 @@ public class StealStrength extends CardImpl { // Target creature gets +1/+1 until end of turn. Another target creature gets -1/-1 until end of turn. this.getSpellAbility().addEffect(new StealStrengthEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(2)); + + 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); } public StealStrength(final StealStrength card) { @@ -89,7 +101,7 @@ class StealStrengthEffect extends ContinuousEffectImpl { permanent.addPower(1); permanent.addToughness(1); } - permanent = game.getPermanent(source.getTargets().get(0).getTargets().get(1)); + permanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); if (permanent != null) { permanent.addPower(-1); permanent.addToughness(-1); diff --git a/Mage.Sets/src/mage/sets/ravnica/BorosSignet.java b/Mage.Sets/src/mage/sets/ravnica/BorosSignet.java index b9cc7abe96a..08bc30e33c7 100644 --- a/Mage.Sets/src/mage/sets/ravnica/BorosSignet.java +++ b/Mage.Sets/src/mage/sets/ravnica/BorosSignet.java @@ -49,7 +49,7 @@ public class BorosSignet extends CardImpl { super(ownerId, 255, "Boros Signet", Rarity.COMMON, new CardType[]{CardType.ARTIFACT}, "{2}"); this.expansionSetCode = "RAV"; - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 1, 0, 0, 0), new GenericManaCost(1)); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 1, 0, 0, 0, 0), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/ravnica/DimirAqueduct.java b/Mage.Sets/src/mage/sets/ravnica/DimirAqueduct.java index ff766fcc289..3d5c2d083c8 100644 --- a/Mage.Sets/src/mage/sets/ravnica/DimirAqueduct.java +++ b/Mage.Sets/src/mage/sets/ravnica/DimirAqueduct.java @@ -57,7 +57,7 @@ public class DimirAqueduct extends CardImpl { // When Dimir Aqueduct enters the battlefield, return a land you control to its owner's hand. this.addAbility(new EntersBattlefieldTriggeredAbility(new ReturnToHandChosenControlledPermanentEffect(filter))); // {tap}: Add {U}{B} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 0, 1, 0, 0), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 0, 1, 0, 0, 0), new TapSourceCost())); } public DimirAqueduct(final DimirAqueduct card) { diff --git a/Mage.Sets/src/mage/sets/ravnica/DimirSignet.java b/Mage.Sets/src/mage/sets/ravnica/DimirSignet.java index 5e36b1dc56a..ed0e9ffe16e 100644 --- a/Mage.Sets/src/mage/sets/ravnica/DimirSignet.java +++ b/Mage.Sets/src/mage/sets/ravnica/DimirSignet.java @@ -48,7 +48,7 @@ public class DimirSignet extends CardImpl { public DimirSignet (UUID ownerId) { super(ownerId, 260, "Dimir Signet", Rarity.COMMON, new CardType[]{CardType.ARTIFACT}, "{2}"); this.expansionSetCode = "RAV"; - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 0, 1, 0, 0), new GenericManaCost(1)); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 0, 1, 0, 0, 0), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/ravnica/GolgariRotFarm.java b/Mage.Sets/src/mage/sets/ravnica/GolgariRotFarm.java index c88529f1666..1adf8ea58e2 100644 --- a/Mage.Sets/src/mage/sets/ravnica/GolgariRotFarm.java +++ b/Mage.Sets/src/mage/sets/ravnica/GolgariRotFarm.java @@ -57,7 +57,7 @@ public class GolgariRotFarm extends CardImpl { // When Golgari Rot Farm enters the battlefield, return a land you control to its owner's hand. this.addAbility(new EntersBattlefieldTriggeredAbility(new ReturnToHandChosenControlledPermanentEffect(filter))); // {tap}: Add {B}{G} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 0, 1, 0, 0), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 0, 1, 0, 0, 0), new TapSourceCost())); } public GolgariRotFarm(final GolgariRotFarm card) { diff --git a/Mage.Sets/src/mage/sets/ravnica/GolgariSignet.java b/Mage.Sets/src/mage/sets/ravnica/GolgariSignet.java index 9ced3c4ed6b..82bf51ff708 100644 --- a/Mage.Sets/src/mage/sets/ravnica/GolgariSignet.java +++ b/Mage.Sets/src/mage/sets/ravnica/GolgariSignet.java @@ -49,7 +49,7 @@ public class GolgariSignet extends CardImpl { public GolgariSignet (UUID ownerId) { super(ownerId, 262, "Golgari Signet", Rarity.COMMON, new CardType[]{CardType.ARTIFACT}, "{2}"); this.expansionSetCode = "RAV"; - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 0, 1, 0, 0), new GenericManaCost(1)); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 0, 1, 0, 0, 0), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/ravnica/SeismicSpike.java b/Mage.Sets/src/mage/sets/ravnica/SeismicSpike.java index 3d3a1710bba..eaaa28c2a48 100644 --- a/Mage.Sets/src/mage/sets/ravnica/SeismicSpike.java +++ b/Mage.Sets/src/mage/sets/ravnica/SeismicSpike.java @@ -50,7 +50,7 @@ public class SeismicSpike extends CardImpl { // Destroy target land. Add {R}{R} to your mana pool. this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetLandPermanent()); - this.getSpellAbility().addEffect(new BasicManaEffect(new Mana(2, 0, 0, 0, 0, 0, 0))); + this.getSpellAbility().addEffect(new BasicManaEffect(new Mana(2, 0, 0, 0, 0, 0, 0, 0))); } public SeismicSpike(final SeismicSpike card) { diff --git a/Mage.Sets/src/mage/sets/ravnica/SelesnyaSanctuary.java b/Mage.Sets/src/mage/sets/ravnica/SelesnyaSanctuary.java index 0a7d541e614..c65c09c8f9e 100644 --- a/Mage.Sets/src/mage/sets/ravnica/SelesnyaSanctuary.java +++ b/Mage.Sets/src/mage/sets/ravnica/SelesnyaSanctuary.java @@ -59,7 +59,7 @@ public class SelesnyaSanctuary extends CardImpl { // When Selesnya Sanctuary enters the battlefield, return a land you control to its owner's hand. this.addAbility(new EntersBattlefieldTriggeredAbility(new ReturnToHandChosenControlledPermanentEffect(filter), false)); // {tap}: Add {G}{W} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 1, 0, 0, 0), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 1, 0, 0, 0, 0), new TapSourceCost())); } public SelesnyaSanctuary(final SelesnyaSanctuary card) { diff --git a/Mage.Sets/src/mage/sets/ravnica/SelesnyaSignet.java b/Mage.Sets/src/mage/sets/ravnica/SelesnyaSignet.java index 161bbfdef95..05e1ea08660 100644 --- a/Mage.Sets/src/mage/sets/ravnica/SelesnyaSignet.java +++ b/Mage.Sets/src/mage/sets/ravnica/SelesnyaSignet.java @@ -49,7 +49,7 @@ public class SelesnyaSignet extends CardImpl { public SelesnyaSignet (UUID ownerId) { super(ownerId, 270, "Selesnya Signet", Rarity.COMMON, new CardType[]{CardType.ARTIFACT}, "{2}"); this.expansionSetCode = "RAV"; - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 1, 0, 0, 0), new GenericManaCost(1)); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 1, 0, 0, 0, 0), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/ravnica/Sunforger.java b/Mage.Sets/src/mage/sets/ravnica/Sunforger.java index cd82d127e30..5c0fbb8d9e7 100644 --- a/Mage.Sets/src/mage/sets/ravnica/Sunforger.java +++ b/Mage.Sets/src/mage/sets/ravnica/Sunforger.java @@ -32,6 +32,7 @@ import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -149,7 +150,7 @@ class UnattachSourceCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent attachment = game.getPermanent(sourceId); Permanent permanent = game.getPermanent(attachment.getAttachedTo()); if (permanent != null) { diff --git a/Mage.Sets/src/mage/sets/returntoravnica/AxebaneGuardian.java b/Mage.Sets/src/mage/sets/returntoravnica/AxebaneGuardian.java index 883a16c8fc7..d9cc5594118 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/AxebaneGuardian.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/AxebaneGuardian.java @@ -66,7 +66,7 @@ public class AxebaneGuardian extends CardImpl { this.addAbility(DefenderAbility.getInstance()); // {tap}: Add X mana in any combination of colors to your mana pool, where X is the number of creatures with defender you control. - this.addAbility(new DynamicManaAbility(new Mana(0,0,0,0,0,0,1), new PermanentsOnBattlefieldCount(filter), new TapSourceCost(), + this.addAbility(new DynamicManaAbility(new Mana(0,0,0,0,0,0,1, 0), new PermanentsOnBattlefieldCount(filter), new TapSourceCost(), "Add X mana in any combination of colors to your mana pool, where X is the number of creatures with defender you control.")); } diff --git a/Mage.Sets/src/mage/sets/returntoravnica/GraveBetrayal.java b/Mage.Sets/src/mage/sets/returntoravnica/GraveBetrayal.java index dab0ee466f1..63e58fc0191 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/GraveBetrayal.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/GraveBetrayal.java @@ -110,10 +110,7 @@ class GraveBetrayalTriggeredAbility extends TriggeredAbilityImpl { Effect effect = new GraveBetrayalEffect(); effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game))); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); - delayedAbility.setSourceId(this.getSourceId()); - delayedAbility.setControllerId(this.getControllerId()); - delayedAbility.setSourceObject(this.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, this); return true; } } diff --git a/Mage.Sets/src/mage/sets/returntoravnica/GroveOfTheGuardian.java b/Mage.Sets/src/mage/sets/returntoravnica/GroveOfTheGuardian.java index cb6ffe31384..bb0590b313b 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/GroveOfTheGuardian.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/GroveOfTheGuardian.java @@ -28,9 +28,6 @@ package mage.sets.returntoravnica; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.Mana; import mage.abilities.Ability; @@ -43,6 +40,8 @@ import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.VigilanceAbility; import mage.abilities.mana.SimpleManaAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; @@ -66,7 +65,7 @@ public class GroveOfTheGuardian extends CardImpl { this.expansionSetCode = "RTR"; // {T}: Add {C} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 0, 0, 1, 0), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 0, 0, 0, 0, 1), new TapSourceCost())); // {3}{G}{W}, {T}, Tap two untapped creatures you control, Sacrifice Grove of the Guardian: Put an 8/8 green and white Elemental creature token with vigilance onto the battlefield. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new ElementalToken(), 1), new ManaCostsImpl("{3}{G}{W}")); @@ -86,6 +85,7 @@ public class GroveOfTheGuardian extends CardImpl { } private class ElementalToken extends Token { + ElementalToken() { super("Elemental", "an 8/8 green and white Elemental creature token with vigilance"); diff --git a/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java b/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java index 4d3c0b2fa75..56ca27938e5 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java @@ -116,10 +116,7 @@ class JaceArchitectOfThoughtStartEffect1 extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { DelayedTriggeredAbility delayedAbility = new JaceArchitectOfThoughtDelayedTriggeredAbility(game.getTurnNum()); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } } diff --git a/Mage.Sets/src/mage/sets/returntoravnica/RitesOfReaping.java b/Mage.Sets/src/mage/sets/returntoravnica/RitesOfReaping.java index b51d0f6adc1..07494f51551 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/RitesOfReaping.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/RitesOfReaping.java @@ -37,6 +37,8 @@ import mage.constants.SubLayer; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffectImpl; import mage.cards.CardImpl; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; @@ -54,7 +56,17 @@ public class RitesOfReaping extends CardImpl { // Target creature gets +3/+3 until end of turn. Another target creature gets -3/-3 until end of turn. this.getSpellAbility().addEffect(new RitesOfReapingEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(2)); + + 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); } public RitesOfReaping(final RitesOfReaping card) { @@ -90,7 +102,7 @@ class RitesOfReapingEffect extends ContinuousEffectImpl { permanent.addPower(3); permanent.addToughness(3); } - permanent = game.getPermanent(source.getTargets().get(0).getTargets().get(1)); + permanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); if (permanent != null) { permanent.addPower(-3); permanent.addToughness(-3); diff --git a/Mage.Sets/src/mage/sets/returntoravnica/RoguesPassage.java b/Mage.Sets/src/mage/sets/returntoravnica/RoguesPassage.java index 67671fd3796..ddbc990666d 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/RoguesPassage.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/RoguesPassage.java @@ -28,10 +28,6 @@ package mage.sets.returntoravnica; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.Mana; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -40,6 +36,9 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; import mage.abilities.mana.SimpleManaAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.target.common.TargetCreaturePermanent; /** @@ -52,7 +51,7 @@ public class RoguesPassage extends CardImpl { this.expansionSetCode = "RTR"; // {T}: Add {C} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 0, 0, 1, 0), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 0, 0, 0, 0, 1), new TapSourceCost())); // {4}, {T}: Target creature can't be blocked this turn. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CantBeBlockedTargetEffect(), new ManaCostsImpl("{4}")); diff --git a/Mage.Sets/src/mage/sets/returntoravnica/SoulTithe.java b/Mage.Sets/src/mage/sets/returntoravnica/SoulTithe.java index 3c20ab8aee8..e9fef2da6fd 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/SoulTithe.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/SoulTithe.java @@ -111,7 +111,7 @@ class SoulTitheEffect extends OneShotEffect { int cmc = permanent.getManaCost().convertedManaCost(); if (player.chooseUse(Outcome.Benefit, "Pay {" + cmc + "} for " + permanent.getName() + "? (otherwise you sacrifice it)", source, game)) { Cost cost = new GenericManaCost(cmc); - if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { + if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/revisededition/LibraryOfLeng.java b/Mage.Sets/src/mage/sets/revisededition/LibraryOfLeng.java new file mode 100644 index 00000000000..ea198f03c13 --- /dev/null +++ b/Mage.Sets/src/mage/sets/revisededition/LibraryOfLeng.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.revisededition; + +import java.util.UUID; + +/** + * + * @author LevelX2 + */ +public class LibraryOfLeng extends mage.sets.limitedbeta.LibraryOfLeng { + + public LibraryOfLeng(UUID ownerId) { + super(ownerId); + this.cardNumber = 261; + this.expansionSetCode = "3ED"; + } + + public LibraryOfLeng(final LibraryOfLeng card) { + super(card); + } + + @Override + public LibraryOfLeng copy() { + return new LibraryOfLeng(this); + } +} diff --git a/Mage.Sets/src/mage/sets/revisededition/SolRing.java b/Mage.Sets/src/mage/sets/revisededition/SolRing.java index 22116a788e3..047b824e3eb 100644 --- a/Mage.Sets/src/mage/sets/revisededition/SolRing.java +++ b/Mage.Sets/src/mage/sets/revisededition/SolRing.java @@ -25,16 +25,15 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.revisededition; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.Mana; import mage.abilities.effects.common.BasicManaEffect; import mage.abilities.mana.BasicManaAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; /** * @@ -42,13 +41,13 @@ import mage.cards.CardImpl; */ public class SolRing extends CardImpl { - public SolRing (UUID ownerId) { + public SolRing(UUID ownerId) { super(ownerId, 274, "Sol Ring", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT}, "{1}"); this.expansionSetCode = "3ED"; this.addAbility(new SolRingAbility()); } - public SolRing (final SolRing card) { + public SolRing(final SolRing card) { super(card); } @@ -62,7 +61,7 @@ class SolRingAbility extends BasicManaAbility { public SolRingAbility() { super(new BasicManaEffect(Mana.ColorlessMana(2))); - this.netMana.add(new Mana(0,0,0,0,0,2,0)); + this.netMana.add(new Mana(0, 0, 0, 0, 0, 0, 0, 2)); } public SolRingAbility(final SolRingAbility ability) { diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/ArrogantBloodlord.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/ArrogantBloodlord.java index 1f262a497b2..8c3f04cdeb3 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/ArrogantBloodlord.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/ArrogantBloodlord.java @@ -28,21 +28,21 @@ package mage.sets.riseoftheeldrazi; import java.util.UUID; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.abilities.effects.OneShotEffect; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; -import mage.cards.CardImpl; /** * @@ -132,11 +132,8 @@ class ArrogantBloodlordEffect extends OneShotEffect { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { AtTheEndOfCombatDelayedTriggeredAbility delayedAbility = new AtTheEndOfCombatDelayedTriggeredAbility(new DestroyTargetEffect()); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(source.getSourceId())); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/DreamstoneHedron.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/DreamstoneHedron.java index 942a66fccff..752a8781951 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/DreamstoneHedron.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/DreamstoneHedron.java @@ -28,18 +28,18 @@ package mage.sets.riseoftheeldrazi; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.Mana; 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.DrawCardSourceControllerEffect; import mage.abilities.effects.common.BasicManaEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.mana.BasicManaAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; /** * @@ -71,18 +71,18 @@ public class DreamstoneHedron extends CardImpl { class DreamstoneHedronFirstManaAbility extends BasicManaAbility { - public DreamstoneHedronFirstManaAbility() { - super(new BasicManaEffect(new Mana(0, 0, 0, 0, 0, 3, 0))); - this.netMana.add(new Mana(0,0,0,0,0,3,0)); - } + public DreamstoneHedronFirstManaAbility() { + super(new BasicManaEffect(new Mana(0, 0, 0, 0, 0, 0, 0, 3))); + this.netMana.add(new Mana(0, 0, 0, 0, 0, 0, 0, 3)); + } - public DreamstoneHedronFirstManaAbility(final DreamstoneHedronFirstManaAbility ability) { - super(ability); - } + public DreamstoneHedronFirstManaAbility(final DreamstoneHedronFirstManaAbility ability) { + super(ability); + } - @Override - public DreamstoneHedronFirstManaAbility copy() { - return new DreamstoneHedronFirstManaAbility(this); + @Override + public DreamstoneHedronFirstManaAbility copy() { + return new DreamstoneHedronFirstManaAbility(this); + } } } -} diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/FlameSlash.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/FlameSlash.java index 1851647f65a..3ec35b89f67 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/FlameSlash.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/FlameSlash.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,19 +20,18 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.riseoftheeldrazi; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.target.common.TargetCreaturePermanent; /** @@ -45,6 +44,7 @@ public class FlameSlash extends CardImpl { super(ownerId, 145, "Flame Slash", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{R}"); this.expansionSetCode = "ROE"; + // Flame Slash deals 4 damage to target creature. this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addEffect(new DamageTargetEffect(4)); } diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/SplinterTwin.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/SplinterTwin.java index ee1aa00718b..507b3382c06 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/SplinterTwin.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/SplinterTwin.java @@ -111,10 +111,7 @@ class SplinterTwinEffect extends OneShotEffect { ExileTargetEffect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(new FixedTarget(addedToken, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } return true; } diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/TrainingGrounds.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/TrainingGrounds.java index 9919547c67c..86b5b6ad4cb 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/TrainingGrounds.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/TrainingGrounds.java @@ -92,8 +92,8 @@ class TrainingGroundsEffect extends CostModificationEffectImpl { Player controller = game.getPlayer(abilityToModify.getControllerId()); if (controller != null) { Mana mana = abilityToModify.getManaCostsToPay().getMana(); - int reduceMax = mana.getColorless(); - if (reduceMax > 0 && mana.count() == mana.getColorless()) { + int reduceMax = mana.getGeneric(); + if (reduceMax > 0 && mana.count() == mana.getGeneric()) { reduceMax--; } if (reduceMax > 2) { diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/WorldAtWar.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/WorldAtWar.java index a2f39bf1f69..0d7855c8d2a 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/WorldAtWar.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/WorldAtWar.java @@ -55,7 +55,6 @@ public class WorldAtWar extends CardImpl { super(ownerId, 172, "World at War", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{3}{R}{R}"); this.expansionSetCode = "ROE"; - // After the first postcombat main phase this turn, there's an additional combat phase followed by an additional main phase. At the beginning of that combat, untap all creatures that attacked this turn. this.getSpellAbility().addEffect(new WorldAtWarEffect()); @@ -95,10 +94,8 @@ class WorldAtWarEffect extends OneShotEffect { TurnMod combat = new TurnMod(source.getControllerId(), TurnPhase.COMBAT, TurnPhase.POSTCOMBAT_MAIN, false); game.getState().getTurnMods().add(combat); UntapDelayedTriggeredAbility delayedTriggeredAbility = new UntapDelayedTriggeredAbility(); - delayedTriggeredAbility.setSourceId(source.getSourceId()); - delayedTriggeredAbility.setControllerId(source.getControllerId()); delayedTriggeredAbility.setConnectedTurnMod(combat.getId()); - game.addDelayedTriggeredAbility(delayedTriggeredAbility); + game.addDelayedTriggeredAbility(delayedTriggeredAbility, source); return true; } @@ -108,7 +105,7 @@ class UntapDelayedTriggeredAbility extends DelayedTriggeredAbility { private UUID connectedTurnMod; private boolean enabled; - + public UntapDelayedTriggeredAbility() { super(new UntapAttackingThisTurnEffect()); } @@ -173,7 +170,7 @@ class UntapAttackingThisTurnEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Watcher watcher = game.getState().getWatchers().get("AttackedThisTurn"); if (watcher != null && watcher instanceof AttackedThisTurnWatcher) { - Set attackedThisTurn = ((AttackedThisTurnWatcher)watcher).getAttackedThisTurnCreatures(); + Set attackedThisTurn = ((AttackedThisTurnWatcher) watcher).getAttackedThisTurnCreatures(); for (UUID uuid : attackedThisTurn) { Permanent permanent = game.getPermanent(uuid); if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) { @@ -185,5 +182,3 @@ class UntapAttackingThisTurnEffect extends OneShotEffect { } } - - diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/CurtainOfLight.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/CurtainOfLight.java index 538519c8ef3..8dd36038122 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/CurtainOfLight.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/CurtainOfLight.java @@ -29,25 +29,21 @@ package mage.sets.saviorsofkamigawa; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.AfterBlockersAreDeclaredCondition; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.constants.CardType; -import mage.constants.Duration; import mage.constants.Outcome; -import mage.constants.PhaseStep; import mage.constants.Rarity; 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.BlockingPredicate; import mage.game.Game; import mage.game.combat.CombatGroup; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; @@ -59,25 +55,23 @@ import mage.target.common.TargetCreaturePermanent; public class CurtainOfLight extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("unblocked attacking creature"); - + static { filter.add(new AttackingPredicate()); filter.add(Predicates.not(new BlockingPredicate())); } - + public CurtainOfLight(UUID ownerId) { super(ownerId, 6, "Curtain of Light", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{W}"); this.expansionSetCode = "SOK"; // Cast Curtain of Light only during combat after blockers are declared. - Ability ability = new SimpleStaticAbility(Zone.ALL, new CurtainOfLightRuleModifyingEffect()); - ability.setRuleAtTheTop(true); - this.addAbility(ability); - + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(TurnPhase.COMBAT, AfterBlockersAreDeclaredCondition.getInstance())); + // Target unblocked attacking creature becomes blocked. - this.getSpellAbility().addEffect(new CurtainOfLightEffect()); + this.getSpellAbility().addEffect(new CurtainOfLightEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); - + // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); } @@ -92,59 +86,22 @@ public class CurtainOfLight extends CardImpl { } } -class CurtainOfLightRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl { - - CurtainOfLightRuleModifyingEffect() { - super(Duration.EndOfGame, Outcome.Detriment); - staticText = "Cast {this} only during combat after blockers are declared"; - } - - CurtainOfLightRuleModifyingEffect(final CurtainOfLightRuleModifyingEffect effect) { - super(effect); - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType().equals(GameEvent.EventType.CAST_SPELL); - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getSourceId().equals(source.getSourceId())) { - return !game.getPhase().getType().equals(TurnPhase.COMBAT) || - game.getStep().getType().equals(PhaseStep.BEGIN_COMBAT) || - game.getStep().getType().equals(PhaseStep.DECLARE_ATTACKERS); - } - return false; - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public CurtainOfLightRuleModifyingEffect copy() { - return new CurtainOfLightRuleModifyingEffect(this); - } -} - class CurtainOfLightEffect extends OneShotEffect { - + public CurtainOfLightEffect() { super(Outcome.Benefit); this.staticText = "Target unblocked attacking creature becomes blocked"; } - + public CurtainOfLightEffect(final CurtainOfLightEffect effect) { super(effect); } - + @Override public CurtainOfLightEffect copy() { return new CurtainOfLightEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/DeathDenied.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/DeathDenied.java index e73c75a492b..87f60a5cbe5 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/DeathDenied.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/DeathDenied.java @@ -28,13 +28,13 @@ package mage.sets.saviorsofkamigawa; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.target.Target; @@ -51,7 +51,6 @@ public class DeathDenied extends CardImpl { this.expansionSetCode = "SOK"; this.subtype.add("Arcane"); - // Return X target creature cards from your graveyard to your hand. Effect effect = new ReturnFromGraveyardToHandTargetEffect(); effect.setText("Return X target creature cards from your graveyard to your hand"); @@ -65,8 +64,8 @@ public class DeathDenied extends CardImpl { if (ability instanceof SpellAbility) { ability.getTargets().clear(); int xValue = ability.getManaCostsToPay().getX(); - Target target = new TargetCardInYourGraveyard(xValue, new FilterCreatureCard(new StringBuilder(xValue).append(xValue != 1?" creature cards":"creature card").append(" from your graveyard").toString())); - ability.addTarget(target); + Target target = new TargetCardInYourGraveyard(xValue, new FilterCreatureCard(new StringBuilder(xValue).append(xValue != 1 ? " creature cards" : "creature card").append(" from your graveyard").toString())); + ability.addTarget(target); } } diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/FootstepsOfTheGoryo.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/FootstepsOfTheGoryo.java index 1fe60da5cad..483c272327a 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/FootstepsOfTheGoryo.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/FootstepsOfTheGoryo.java @@ -102,10 +102,7 @@ class FootstepsOfTheGoryoEffect extends OneShotEffect { Effect sacrificeEffect = new SacrificeTargetEffect("Sacrifice that creature at the beginning of next end step", source.getControllerId()); sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } } } diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/SasayaOrochiAscendant.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/SasayaOrochiAscendant.java index 3804d61c11c..9376a2c477c 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/SasayaOrochiAscendant.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/SasayaOrochiAscendant.java @@ -77,7 +77,7 @@ public class SasayaOrochiAscendant extends CardImpl { this.flipCardName = "Sasaya's Essence"; // Reveal your hand: If you have seven or more land cards in your hand, flip Sasaya, Orochi Ascendant. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new SasayaOrochiAscendantFlipEffect(), new RevealHandSourceControllerCost() )); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new SasayaOrochiAscendantFlipEffect(), new RevealHandSourceControllerCost())); } public SasayaOrochiAscendant(final SasayaOrochiAscendant card) { @@ -91,21 +91,21 @@ public class SasayaOrochiAscendant extends CardImpl { } class SasayaOrochiAscendantFlipEffect extends OneShotEffect { - + public SasayaOrochiAscendantFlipEffect() { super(Outcome.Benefit); this.staticText = "If you have seven or more land cards in your hand, flip {this}"; } - + public SasayaOrochiAscendantFlipEffect(final SasayaOrochiAscendantFlipEffect effect) { super(effect); } - + @Override public SasayaOrochiAscendantFlipEffect copy() { return new SasayaOrochiAscendantFlipEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); @@ -121,7 +121,7 @@ class SasayaOrochiAscendantFlipEffect extends OneShotEffect { class SasayasEssence extends Token { - SasayasEssence () { + SasayasEssence() { super("Sasaya's Essence", ""); supertype.add("Legendary"); cardType.add(CardType.ENCHANTMENT); @@ -190,7 +190,7 @@ class SasayasEssenceManaEffectEffect extends ManaEffect { if (choice.getChoices().size() == 1) { choice.setChoice(choice.getChoices().iterator().next()); } else { - while(!choice.isChosen()) { + while (!choice.isChosen()) { controller.choose(outcome, choice, game); if (!controller.canRespond()) { return false; diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/TombOfUrami.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/TombOfUrami.java index e516c80f1fa..40f003719de 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/TombOfUrami.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/TombOfUrami.java @@ -35,6 +35,7 @@ import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -93,7 +94,7 @@ class SacrificeAllLandCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { for(Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledLandPermanent(), ability.getControllerId(), game)){ paid |= permanent.sacrifice(sourceId, game); } diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/ArgentSphinx.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/ArgentSphinx.java index aa0a0daaabd..d7d9075a2b2 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/ArgentSphinx.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/ArgentSphinx.java @@ -104,10 +104,7 @@ class ArgentSphinxEffect extends OneShotEffect { AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility( new ReturnFromExileEffect(source.getSourceId(), Zone.BATTLEFIELD)); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } } diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/BloodshotTrainee.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/BloodshotTrainee.java index 02296e641aa..b92df5d2757 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/BloodshotTrainee.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/BloodshotTrainee.java @@ -34,6 +34,7 @@ import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.common.DamageTargetEffect; @@ -100,7 +101,7 @@ class BloodshotTraineeCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { this.paid = true; return paid; } diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/Embersmith.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/Embersmith.java index 09d83f6f150..acf568e317b 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/Embersmith.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/Embersmith.java @@ -88,7 +88,7 @@ class EmbersmithEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Cost cost = new GenericManaCost(1); cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { Permanent permanent = game.getPermanent(source.getFirstTarget()); if (permanent != null) { permanent.damage(1, source.getSourceId(), game, false, true); diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/FleshAllergy.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/FleshAllergy.java index 6761d0c03c0..9b0098c23b1 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/FleshAllergy.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/FleshAllergy.java @@ -25,22 +25,20 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.scarsofmirrodin; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.WatcherScope; -import mage.constants.Zone; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.WatcherScope; +import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; @@ -57,10 +55,12 @@ import mage.watchers.Watcher; */ public class FleshAllergy extends CardImpl { - public FleshAllergy (UUID ownerId) { + public FleshAllergy(UUID ownerId) { super(ownerId, 62, "Flesh Allergy", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{2}{B}{B}"); this.expansionSetCode = "SOM"; + // As an additional cost to cast Flesh Allergy, sacrifice a creature. + // Destroy target creature. Its controller loses life equal to the number of creatures that died this turn. this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent())); this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); @@ -68,7 +68,7 @@ public class FleshAllergy extends CardImpl { this.getSpellAbility().addWatcher(new FleshAllergyWatcher()); } - public FleshAllergy (final FleshAllergy card) { + public FleshAllergy(final FleshAllergy card) { super(card); } @@ -97,7 +97,7 @@ class FleshAllergyWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { - if (event.getType() == EventType.ZONE_CHANGE && ((ZoneChangeEvent)event).isDiesEvent()) { + if (event.getType() == EventType.ZONE_CHANGE && ((ZoneChangeEvent) event).isDiesEvent()) { MageObject card = game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); if (card != null && card.getCardType().contains(CardType.CREATURE)) { creaturesDiedThisTurn++; @@ -132,9 +132,9 @@ class FleshAllergyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { FleshAllergyWatcher watcher = (FleshAllergyWatcher) game.getState().getWatchers().get("CreaturesDied"); - MageObject card = game.getLastKnownInformation(source.getFirstTarget(), Zone.BATTLEFIELD); - if (card != null && watcher != null) { - Player player = game.getPlayer(((Permanent)card).getControllerId()); + Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); + if (permanent != null && watcher != null) { + Player player = game.getPlayer(permanent.getControllerId()); if (player != null) { int amount = watcher.creaturesDiedThisTurn; if (amount > 0) { diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/GlimmerpointStag.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/GlimmerpointStag.java index 74e732372a0..3501a3df33e 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/GlimmerpointStag.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/GlimmerpointStag.java @@ -27,24 +27,27 @@ */ package mage.sets.scarsofmirrodin; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ReturnFromExileEffect; +import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.permanent.AnotherPredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.Target; +import mage.players.Player; import mage.target.TargetPermanent; - -import java.util.UUID; +import mage.target.targetpointer.FixedTarget; /** * @@ -52,6 +55,12 @@ import java.util.UUID; */ public class GlimmerpointStag extends CardImpl { + private final static FilterPermanent filter = new FilterPermanent("another target permanent"); + + static { + filter.add(new AnotherPredicate()); + } + public GlimmerpointStag(UUID ownerId) { super(ownerId, 9, "Glimmerpoint Stag", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); this.expansionSetCode = "SOM"; @@ -60,10 +69,12 @@ public class GlimmerpointStag extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(3); + // Vigilance this.addAbility(VigilanceAbility.getInstance()); - Target etbTarget = new TargetPermanent(); + + // When Glimmerpoint Stag enters the battlefield, exile another target permanent. Return that card to the battlefield under its owner's control at the beginning of the next end step. Ability etbAbility = new EntersBattlefieldTriggeredAbility(new GlimmerpointStagEffect()); - etbAbility.addTarget(etbTarget); + etbAbility.addTarget(new TargetPermanent(filter)); this.addAbility(etbAbility); } @@ -81,7 +92,7 @@ class GlimmerpointStagEffect extends OneShotEffect { private static final String effectText = "exile another target permanent. Return that card to the battlefield under its owner's control at the beginning of the next end step"; - GlimmerpointStagEffect ( ) { + GlimmerpointStagEffect() { super(Outcome.Detriment); staticText = effectText; } @@ -92,17 +103,19 @@ class GlimmerpointStagEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent != null) { - if (permanent.moveToExile(source.getSourceId(), "Glimmerpoint Stag Exile", source.getSourceId(), game)) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent != null) { + int zcc = permanent.getZoneChangeCounter(game); + controller.moveCards(permanent, Zone.EXILED, source, game); //create delayed triggered ability - AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnFromExileEffect(source.getSourceId(), Zone.BATTLEFIELD)); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); - return true; + Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(); + effect.setTargetPointer(new FixedTarget(permanent.getId(), zcc + 1)); + AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); + game.addDelayedTriggeredAbility(delayedAbility, source); } + return true; } return false; } diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/GrandArchitect.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/GrandArchitect.java index 267b4e2852a..c08b3ab2a85 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/GrandArchitect.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/GrandArchitect.java @@ -1,16 +1,16 @@ /* * Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,24 +20,15 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.scarsofmirrodin; import java.util.UUID; - import mage.ConditionalMana; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.SubLayer; -import mage.constants.Zone; import mage.MageInt; import mage.MageObject; import mage.Mana; @@ -53,6 +44,13 @@ import mage.abilities.effects.common.BasicManaEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.mana.ManaAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; @@ -146,17 +144,17 @@ class GrandArchitectManaAbility extends ManaAbility { filter.add(Predicates.not(new TappedPredicate())); } - GrandArchitectManaAbility ( ) { + GrandArchitectManaAbility() { super(Zone.BATTLEFIELD, new BasicManaEffect(new GrandArchitectConditionalMana()), new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, true))); - this.netMana.add(new Mana(0,0,0,0,0,2,0)); + this.netMana.add(new Mana(0, 0, 0, 0, 0, 0, 0, 2)); } - GrandArchitectManaAbility ( GrandArchitectManaAbility ability ) { + GrandArchitectManaAbility(GrandArchitectManaAbility ability) { super(ability); } @Override - public GrandArchitectManaAbility copy ( ) { + public GrandArchitectManaAbility copy() { return new GrandArchitectManaAbility(this); } } @@ -171,6 +169,7 @@ class GrandArchitectConditionalMana extends ConditionalMana { } class GrandArchitectManaCondition implements Condition { + @Override public boolean apply(Game game, Ability source) { MageObject object = game.getObject(source.getSourceId()); diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/Lifesmith.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/Lifesmith.java index ba2a2ca72e3..1dea4714e28 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/Lifesmith.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/Lifesmith.java @@ -85,7 +85,7 @@ class LifesmithEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Cost cost = new GenericManaCost(1); cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { player.gainLife(3, game); diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/MimicVat.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/MimicVat.java index 324ecd84756..e63bd8bbdbb 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/MimicVat.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/MimicVat.java @@ -209,10 +209,7 @@ class MimicVatCreateTokenEffect extends OneShotEffect { ExileTargetEffect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(new FixedTarget(addedToken, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } return true; diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/MyrReservoir.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/MyrReservoir.java index a29f82650aa..b9a1eb76f37 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/MyrReservoir.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/MyrReservoir.java @@ -27,9 +27,8 @@ */ package mage.sets.scarsofmirrodin; +import java.util.UUID; import mage.ConditionalMana; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageObject; import mage.Mana; import mage.abilities.Ability; @@ -41,14 +40,14 @@ import mage.abilities.effects.common.BasicManaEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.mana.BasicManaAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.target.common.TargetCardInYourGraveyard; -import java.util.UUID; - /** * @author nantuko */ @@ -88,7 +87,7 @@ class MyrReservoirManaAbility extends BasicManaAbility { MyrReservoirManaAbility() { super(new BasicManaEffect(new MyrConditionalMana())); - this.netMana.add(new Mana(0,0,0,0,0,2,0)); + this.netMana.add(new Mana(0, 0, 0, 0, 0, 0, 0, 2)); } MyrReservoirManaAbility(MyrReservoirManaAbility ability) { @@ -111,6 +110,7 @@ class MyrConditionalMana extends ConditionalMana { } class MyrManaCondition implements Condition { + @Override public boolean apply(Game game, Ability source) { MageObject object = game.getObject(source.getSourceId()); diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/Myrsmith.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/Myrsmith.java index 845fe559621..e0f688a9b1b 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/Myrsmith.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/Myrsmith.java @@ -84,7 +84,7 @@ class MyrsmithEffect extends CreateTokenEffect { public boolean apply(Game game, Ability source) { Cost cost = new GenericManaCost(1); cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { super.apply(game, source); } return true; diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/NimDeathmantle.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/NimDeathmantle.java index 0de1da15612..294fc85ba80 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/NimDeathmantle.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/NimDeathmantle.java @@ -154,7 +154,7 @@ class NimDeathmantleEffect extends OneShotEffect { if (controller != null && equipment != null) { if (controller.chooseUse(Outcome.Benefit, equipment.getName() + " - Pay " + cost.getText() + "?", source, game)) { cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { UUID target = targetPointer.getFirst(game, source); if (target != null) { Card card = game.getCard(target); diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/OgreGeargrabber.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/OgreGeargrabber.java index 13f7a9967b5..fb01ab47886 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/OgreGeargrabber.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/OgreGeargrabber.java @@ -1,16 +1,16 @@ /* * Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,7 +20,7 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. @@ -110,10 +110,7 @@ class OgreGeargrabberEffect1 extends OneShotEffect { UUID equipmentId = source.getFirstTarget(); if (equipmentId != null) { OgreGeargrabberDelayedTriggeredAbility delayedAbility = new OgreGeargrabberDelayedTriggeredAbility(equipmentId); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); Permanent equipment = game.getPermanent(equipmentId); if (equipment != null) { Permanent ogre = game.getPermanent(source.getSourceId()); @@ -132,7 +129,7 @@ class OgreGeargrabberDelayedTriggeredAbility extends DelayedTriggeredAbility { private UUID equipmentId; - OgreGeargrabberDelayedTriggeredAbility (UUID equipmentId) { + OgreGeargrabberDelayedTriggeredAbility(UUID equipmentId) { super(new OgreGeargrabberEffect2(equipmentId)); this.equipmentId = equipmentId; } @@ -151,6 +148,7 @@ class OgreGeargrabberDelayedTriggeredAbility extends DelayedTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { return event.getPlayerId().equals(controllerId) && event.getTargetId().equals(equipmentId); } + @Override public OgreGeargrabberDelayedTriggeredAbility copy() { return new OgreGeargrabberDelayedTriggeredAbility(this); diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/PainfulQuandary.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/PainfulQuandary.java index 8966440f999..f7f5bccc454 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/PainfulQuandary.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/PainfulQuandary.java @@ -93,7 +93,7 @@ class PainfulQuandryEffect extends OneShotEffect { Cost cost = new DiscardTargetCost(new TargetCardInHand()); if (cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(Outcome.Detriment, "Discard a card (otherwise you lose 5 life)?", source, game)) { - paid = cost.pay(source, game, source.getSourceId(), player.getId(), false); + paid = cost.pay(source, game, source.getSourceId(), player.getId(), false, null); } if (!paid) { player.loseLife(5, game); diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/PalladiumMyr.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/PalladiumMyr.java index 51117d52488..dccc2b8484f 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/PalladiumMyr.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/PalladiumMyr.java @@ -25,18 +25,16 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.scarsofmirrodin; -import mage.constants.CardType; -import mage.constants.Rarity; +import java.util.UUID; import mage.MageInt; import mage.Mana; import mage.abilities.effects.common.BasicManaEffect; import mage.abilities.mana.BasicManaAbility; import mage.cards.CardImpl; - -import java.util.UUID; +import mage.constants.CardType; +import mage.constants.Rarity; /** * @@ -44,7 +42,7 @@ import java.util.UUID; */ public class PalladiumMyr extends CardImpl { - public PalladiumMyr (UUID ownerId) { + public PalladiumMyr(UUID ownerId) { super(ownerId, 190, "Palladium Myr", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); this.expansionSetCode = "SOM"; this.subtype.add("Myr"); @@ -53,7 +51,7 @@ public class PalladiumMyr extends CardImpl { this.addAbility(new PalladiumMyrAbility()); } - public PalladiumMyr (final PalladiumMyr card) { + public PalladiumMyr(final PalladiumMyr card) { super(card); } @@ -67,7 +65,7 @@ class PalladiumMyrAbility extends BasicManaAbility { public PalladiumMyrAbility() { super(new BasicManaEffect(Mana.ColorlessMana(2))); - this.netMana.add(new Mana(0,0,0,0,0,2,0)); + this.netMana.add(new Mana(0, 0, 0, 0, 0, 0, 0, 2)); } public PalladiumMyrAbility(final PalladiumMyrAbility ability) { diff --git a/Mage.Sets/src/mage/sets/scourge/FormOfTheDragon.java b/Mage.Sets/src/mage/sets/scourge/FormOfTheDragon.java index ac3b132005f..6c016c1ee6c 100644 --- a/Mage.Sets/src/mage/sets/scourge/FormOfTheDragon.java +++ b/Mage.Sets/src/mage/sets/scourge/FormOfTheDragon.java @@ -56,7 +56,7 @@ import mage.target.common.TargetCreatureOrPlayer; */ public class FormOfTheDragon extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures without flying"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures without flying"); static { filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); diff --git a/Mage.Sets/src/mage/sets/seventhedition/RelentlessAssault.java b/Mage.Sets/src/mage/sets/seventhedition/RelentlessAssault.java index b55edf8374b..177f36f8376 100644 --- a/Mage.Sets/src/mage/sets/seventhedition/RelentlessAssault.java +++ b/Mage.Sets/src/mage/sets/seventhedition/RelentlessAssault.java @@ -56,7 +56,6 @@ public class RelentlessAssault extends CardImpl { super(ownerId, 214, "Relentless Assault", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{2}{R}{R}"); this.expansionSetCode = "7ED"; - // Untap all creatures that attacked this turn. After this main phase, there is an additional combat phase followed by an additional main phase. this.getSpellAbility().addWatcher(new AttackedThisTurnWatcher()); this.getSpellAbility().addEffect(new RelentlessAssaultUntapEffect()); @@ -130,10 +129,8 @@ class RelentlessAssaultAddPhasesEffect extends OneShotEffect { TurnMod combat = new TurnMod(source.getControllerId(), TurnPhase.COMBAT, TurnPhase.POSTCOMBAT_MAIN, false); game.getState().getTurnMods().add(combat); RelentlessAssaultDelayedAddMainPhaseAbility delayedTriggeredAbility = new RelentlessAssaultDelayedAddMainPhaseAbility(); - delayedTriggeredAbility.setSourceId(source.getSourceId()); - delayedTriggeredAbility.setControllerId(source.getControllerId()); delayedTriggeredAbility.setConnectedTurnMod(combat.getId()); - game.addDelayedTriggeredAbility(delayedTriggeredAbility); + game.addDelayedTriggeredAbility(delayedTriggeredAbility, source); return true; } return false; @@ -163,7 +160,7 @@ class RelentlessAssaultDelayedAddMainPhaseAbility extends DelayedTriggeredAbilit @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == EventType.PHASE_CHANGED + return event.getType() == EventType.PHASE_CHANGED || event.getType() == EventType.COMBAT_PHASE_PRE; } diff --git a/Mage.Sets/src/mage/sets/seventhedition/SisaysRing.java b/Mage.Sets/src/mage/sets/seventhedition/SisaysRing.java index 5f57cf73898..7cf6f59e99e 100644 --- a/Mage.Sets/src/mage/sets/seventhedition/SisaysRing.java +++ b/Mage.Sets/src/mage/sets/seventhedition/SisaysRing.java @@ -47,7 +47,7 @@ public class SisaysRing extends CardImpl { this.expansionSetCode = "7ED"; // {tap}: Add {C}{C} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0,0,0,0,0,2,0), new TapSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 0, 0, 0, 0, 2), new TapSourceCost())); } public SisaysRing(final SisaysRing card) { @@ -58,4 +58,4 @@ public class SisaysRing extends CardImpl { public SisaysRing copy() { return new SisaysRing(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/shadowmoor/CragganwickCremator.java b/Mage.Sets/src/mage/sets/shadowmoor/CragganwickCremator.java index 1a18f370549..7cadbaed388 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/CragganwickCremator.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/CragganwickCremator.java @@ -31,9 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; @@ -42,7 +40,6 @@ import mage.constants.Rarity; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; -import mage.target.targetpointer.FixedTarget; /** * @@ -94,14 +91,17 @@ class CragganwickCrematorEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player you = game.getPlayer(source.getControllerId()); - Player targetedPlayer = game.getPlayer(source.getFirstTarget()); - if (you != null && targetedPlayer != null) { - Card discardedCard = targetedPlayer.discardOne(true, source, game); + Player controller = game.getPlayer(source.getControllerId()); + + if (controller != null) { + Card discardedCard = controller.discardOne(true, source, game); if (discardedCard != null && discardedCard.getCardType().contains(CardType.CREATURE)) { - int damage = discardedCard.getPower().getValue(); - targetedPlayer.damage(damage, source.getSourceId(), game, false, true); + Player targetedPlayer = game.getPlayer(source.getFirstTarget()); + if (targetedPlayer != null) { + int damage = discardedCard.getPower().getValue(); + targetedPlayer.damage(damage, source.getSourceId(), game, false, true); + } } return true; } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/FateTransfer.java b/Mage.Sets/src/mage/sets/shadowmoor/FateTransfer.java index 811237a3b48..6cc21583286 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/FateTransfer.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/FateTransfer.java @@ -36,6 +36,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.counters.Counter; import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; @@ -47,7 +48,7 @@ import mage.target.common.TargetCreaturePermanent; public 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("target creature to move all counters to"); + private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another target creature to move all counters to"); public FateTransfer(UUID ownerId) { super(ownerId, 161, "Fate Transfer", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{U/B}"); @@ -55,8 +56,15 @@ public class FateTransfer extends CardImpl { // Move all counters from target creature onto another target creature. this.getSpellAbility().addEffect(new FateTransferEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter2)); + + 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); } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/FireLitThicket.java b/Mage.Sets/src/mage/sets/shadowmoor/FireLitThicket.java index 2f519202309..203c4a021f1 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/FireLitThicket.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/FireLitThicket.java @@ -55,7 +55,7 @@ public class FireLitThicket extends CardImpl { ability.addCost(new TapSourceCost()); this.addAbility(ability); - ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 0, 0, 0, 0, 0), new ManaCostsImpl("{R/G}")); + ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 0, 0, 0, 0, 0, 0), new ManaCostsImpl("{R/G}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/FossilFind.java b/Mage.Sets/src/mage/sets/shadowmoor/FossilFind.java index 25f6fc97393..41eebbc7ec4 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/FossilFind.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/FossilFind.java @@ -28,14 +28,14 @@ package mage.sets.shadowmoor; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.players.Player; @@ -49,7 +49,6 @@ public class FossilFind extends CardImpl { super(ownerId, 206, "Fossil Find", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{R/G}"); this.expansionSetCode = "SHM"; - // Return a card at random from your graveyard to your hand, then reorder your graveyard as you choose. this.getSpellAbility().addEffect(new FossilFindEffect()); } @@ -82,14 +81,14 @@ class FossilFindEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null && !player.getGraveyard().isEmpty()) { - Card card = player.getGraveyard().getRandom(game); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null && !controller.getGraveyard().isEmpty()) { + Card card = controller.getGraveyard().getRandom(game); if (card != null) { - card.moveToZone(Zone.HAND, source.getSourceId(), game, true); - game.informPlayers(card.getName() + "returned to the hand of" + player.getLogName()); + controller.moveCards(card, Zone.HAND, source, game); return true; } + controller.moveCards(controller.getGraveyard(), Zone.GRAVEYARD, source, game); } return false; } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/Gloomlance.java b/Mage.Sets/src/mage/sets/shadowmoor/Gloomlance.java index 84c70998249..994f8d21402 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/Gloomlance.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/Gloomlance.java @@ -28,7 +28,6 @@ package mage.sets.shadowmoor; import java.util.UUID; -import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -50,7 +49,6 @@ public class Gloomlance extends CardImpl { super(ownerId, 67, "Gloomlance", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{3}{B}{B}"); this.expansionSetCode = "SHM"; - // Destroy target creature. If that creature was green or white, its controller discards a card. this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addEffect(new GloomlanceEffect()); @@ -85,7 +83,7 @@ class GloomlanceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent targetCreature = game.getPermanent(source.getFirstTarget()); + Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); if (targetCreature != null) { Player targetController = game.getPlayer(targetCreature.getControllerId()); targetCreature.destroy(source.getSourceId(), game, false); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/GravenCairns.java b/Mage.Sets/src/mage/sets/shadowmoor/GravenCairns.java index 0ceeb37c22f..c47c2211f06 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/GravenCairns.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/GravenCairns.java @@ -56,7 +56,7 @@ public class GravenCairns extends CardImpl { ability.addCost(new TapSourceCost()); this.addAbility(ability); - ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 0, 1, 0, 0), new ManaCostsImpl("{B/R}")); + ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 0, 1, 0, 0, 0), new ManaCostsImpl("{B/R}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/ImpromptuRaid.java b/Mage.Sets/src/mage/sets/shadowmoor/ImpromptuRaid.java index de9ede0bc2d..9b4b6cdf931 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/ImpromptuRaid.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/ImpromptuRaid.java @@ -126,10 +126,7 @@ class ImpromptuRaidEffect extends OneShotEffect { SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("", source.getControllerId()); sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } return true; } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/IncrementalBlight.java b/Mage.Sets/src/mage/sets/shadowmoor/IncrementalBlight.java index 52e1c7100a8..b2641294305 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/IncrementalBlight.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/IncrementalBlight.java @@ -35,6 +35,8 @@ import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.Target; @@ -53,8 +55,23 @@ public class IncrementalBlight extends CardImpl { // 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()); - Target target = new TargetCreaturePermanent(3,3); - this.getSpellAbility().addTarget(target); + + 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); } public IncrementalBlight(final IncrementalBlight card) { @@ -85,9 +102,9 @@ class IncrementalBlightEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int i = 0; - for (UUID targetId : getTargetPointer().getTargets(game, source)) { + for (Target target : source.getTargets()) { i++; - Permanent creature = game.getPermanent(targetId); + Permanent creature = game.getPermanent(target.getFirstTarget()); if (creature != null) { creature.addCounters(CounterType.M1M1.createInstance(i), game); } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/ManaReflection.java b/Mage.Sets/src/mage/sets/shadowmoor/ManaReflection.java index 8acddd38c13..2d0ac179dac 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/ManaReflection.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/ManaReflection.java @@ -53,7 +53,6 @@ public class ManaReflection extends CardImpl { super(ownerId, 122, "Mana Reflection", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{G}{G}"); this.expansionSetCode = "SHM"; - // If you tap a permanent for mana, it produces twice as much of that mana instead. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ManaReflectionReplacementEffect())); @@ -89,7 +88,7 @@ class ManaReflectionReplacementEffect extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { Mana mana = ((ManaEvent) event).getMana(); if (mana.getBlack() > 0) { - mana.set(ManaType.BLACK, mana.getBlack()* 2); + mana.set(ManaType.BLACK, mana.getBlack() * 2); } if (mana.getBlue() > 0) { mana.set(ManaType.BLUE, mana.getBlue() * 2); @@ -115,7 +114,7 @@ class ManaReflectionReplacementEffect extends ReplacementEffectImpl { } @Override - public boolean applies(GameEvent event, Ability source, Game game) { + public boolean applies(GameEvent event, Ability source, Game game) { return event.getPlayerId().equals(source.getControllerId()) && game.getPermanentOrLKIBattlefield(event.getSourceId()) != null; } @@ -124,4 +123,4 @@ class ManaReflectionReplacementEffect extends ReplacementEffectImpl { public ManaReflectionReplacementEffect copy() { return new ManaReflectionReplacementEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/shadowmoor/Morselhoarder.java b/Mage.Sets/src/mage/sets/shadowmoor/Morselhoarder.java index ea39bc57e91..22bc0303910 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/Morselhoarder.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/Morselhoarder.java @@ -80,7 +80,7 @@ class MorselhoarderAbility extends ManaAbility { public MorselhoarderAbility(Cost cost) { super(Zone.BATTLEFIELD, new AddManaOfAnyColorEffect(), cost); - this.netMana.add(new Mana(0,0,0,0,0,0,1)); + this.netMana.add(new Mana(0,0,0,0,0,0,1, 0)); } public MorselhoarderAbility(final MorselhoarderAbility ability) { diff --git a/Mage.Sets/src/mage/sets/shadowmoor/MossbridgeTroll.java b/Mage.Sets/src/mage/sets/shadowmoor/MossbridgeTroll.java index bc44a0a95d4..50689961a2c 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/MossbridgeTroll.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/MossbridgeTroll.java @@ -32,6 +32,7 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.continuous.BoostSourceEffect; @@ -148,7 +149,7 @@ class MossbridgeTrollCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { int sumPower = 0; if (targets.choose(Outcome.Tap, controllerId, sourceId, game)) { for (UUID targetId : targets.get(0).getTargets()) { diff --git a/Mage.Sets/src/mage/sets/shadowmoor/MysticGate.java b/Mage.Sets/src/mage/sets/shadowmoor/MysticGate.java index 3c557dfcd5b..087f8367f93 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/MysticGate.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/MysticGate.java @@ -55,7 +55,7 @@ public class MysticGate extends CardImpl { ability.addCost(new TapSourceCost()); this.addAbility(ability); - ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 1, 0, 0, 0), new ManaCostsImpl("{W/U}")); + ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 1, 0, 0, 0, 0), new ManaCostsImpl("{W/U}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/PuppeteerClique.java b/Mage.Sets/src/mage/sets/shadowmoor/PuppeteerClique.java index c0568cfaf3a..2a241f97e04 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/PuppeteerClique.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/PuppeteerClique.java @@ -127,10 +127,7 @@ class PuppeteerCliqueEffect extends OneShotEffect { ExileTargetEffect exileEffect = new ExileTargetEffect("exile " + permanent.getLogName()); exileEffect.setTargetPointer(new FixedTarget(permanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect, TargetController.YOU); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); result = true; } } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/RosheenMeanderer.java b/Mage.Sets/src/mage/sets/shadowmoor/RosheenMeanderer.java index 05eb96aa6fd..8ae56680228 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/RosheenMeanderer.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/RosheenMeanderer.java @@ -76,7 +76,7 @@ class RosheenMeandererManaAbility extends BasicManaAbility { RosheenMeandererManaAbility() { super(new BasicManaEffect(new RosheenMeandererConditionalMana())); - this.netMana.add(new Mana(0, 0, 0, 0, 0, 4, 0)); + this.netMana.add(new Mana(0, 0, 0, 0, 0, 0, 0, 4)); } RosheenMeandererManaAbility(RosheenMeandererManaAbility ability) { diff --git a/Mage.Sets/src/mage/sets/shadowmoor/ScarscaleRitual.java b/Mage.Sets/src/mage/sets/shadowmoor/ScarscaleRitual.java index 8e955f022ff..3082728aafb 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/ScarscaleRitual.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/ScarscaleRitual.java @@ -29,6 +29,7 @@ package mage.sets.shadowmoor; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; @@ -90,7 +91,7 @@ class ScarscaleRitualCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(ability.getControllerId()); if (controller != null) { Target target = new TargetControlledCreaturePermanent(); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/SunkenRuins.java b/Mage.Sets/src/mage/sets/shadowmoor/SunkenRuins.java index ff6fe2bc7dd..8e2f6989821 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/SunkenRuins.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/SunkenRuins.java @@ -55,7 +55,7 @@ public class SunkenRuins extends CardImpl { ability.addCost(new TapSourceCost()); this.addAbility(ability); - ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 0, 1, 0, 0), new ManaCostsImpl("{U/B}")); + ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 1, 0, 1, 0, 0, 0), new ManaCostsImpl("{U/B}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/Tatterkite.java b/Mage.Sets/src/mage/sets/shadowmoor/Tatterkite.java index 27c846f33a5..72f220b3e1e 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/Tatterkite.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/Tatterkite.java @@ -60,7 +60,7 @@ public class Tatterkite extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Tatterkite can't have counters placed on it. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantHaveCountersSourceEffect(Duration.WhileOnBattlefield))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new CantHaveCountersSourceEffect(Duration.WhileOnBattlefield))); } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/Tyrannize.java b/Mage.Sets/src/mage/sets/shadowmoor/Tyrannize.java index 12451e7b893..4bac31203d0 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/Tyrannize.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/Tyrannize.java @@ -92,7 +92,7 @@ class TyrannizeEffect extends OneShotEffect { Cost cost = new PayLifeCost(7); if (!cost.canPay(source, source.getSourceId(), player.getId(), game) || !player.chooseUse(Outcome.LoseLife, "Pay 7 life?", source, game) - || !cost.pay(source, game, source.getSourceId(), player.getId(), false)) { + || !cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { for (Card card : player.getHand().getCards(game)) { player.discard(card, source, game); } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/Valleymaker.java b/Mage.Sets/src/mage/sets/shadowmoor/Valleymaker.java index 8cc7c134905..7577fd84c8d 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/Valleymaker.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/Valleymaker.java @@ -75,7 +75,7 @@ public class Valleymaker extends CardImpl { this.addAbility(ability); // {tap}, Sacrifice a Forest: Choose a player. That player adds {G}{G}{G} to his or her mana pool. - Ability ability2 = new SimpleManaAbility(Zone.BATTLEFIELD, new AddManaToManaPoolTargetControllerEffect(new Mana(0,3,0,0,0,0,0), "chosen player"), new TapSourceCost()); + Ability ability2 = new SimpleManaAbility(Zone.BATTLEFIELD, new AddManaToManaPoolTargetControllerEffect(new Mana(0,3,0,0,0,0,0, 0), "chosen player"), new TapSourceCost()); ability2.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter2))); ability2.addTarget(new TargetPlayer(1, 1, true)); this.addAbility(ability2); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/WoodedBastion.java b/Mage.Sets/src/mage/sets/shadowmoor/WoodedBastion.java index aaca1d70f12..0903c711521 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/WoodedBastion.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/WoodedBastion.java @@ -55,7 +55,7 @@ public class WoodedBastion extends CardImpl { ability.addCost(new TapSourceCost()); this.addAbility(ability); - ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 1, 0, 0, 0), new ManaCostsImpl("{G/W}")); + ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 0, 1, 0, 0, 0, 0), new ManaCostsImpl("{G/W}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/Worldpurge.java b/Mage.Sets/src/mage/sets/shadowmoor/Worldpurge.java index ae23a082507..40e2594c360 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/Worldpurge.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/Worldpurge.java @@ -27,21 +27,23 @@ */ package mage.sets.shadowmoor; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.FilterPermanent; -import mage.filter.predicate.other.OwnerIdPredicate; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInHand; @@ -55,7 +57,6 @@ public class Worldpurge extends CardImpl { super(ownerId, 156, "Worldpurge", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{W/U}{W/U}{W/U}{W/U}"); this.expansionSetCode = "SHM"; - // Return all permanents to their owners' hands. Each player chooses up to seven cards in his or her hand, then shuffles the rest into his or her library. Empty all mana pools. this.getSpellAbility().addEffect(new WorldpurgeEffect()); @@ -89,29 +90,37 @@ class WorldpurgeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterPermanent(), source.getControllerId(), source.getSourceId(), game)) { - permanent.moveToZone(Zone.HAND, source.getSourceId(), game, false); - } - game.informPlayers("Worldpurge: All permanents returned to owners' hands"); - for (Player player : game.getPlayers().values()) { - if (player != null) { - Cards hand = player.getHand(); - FilterCard filter = new FilterCard("card to keep in hand"); - filter.add(new OwnerIdPredicate(player.getId())); - int numberInHand = Math.min(7, hand.size()); - TargetCardInHand target = new TargetCardInHand(0, numberInHand, filter); - if (player.choose(Outcome.Benefit, target, source.getSourceId(), game)) { - for (Card card : hand.getCards(game)) { - if (!target.getTargets().contains(card.getId())) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller != null && sourceObject != null) { + Set allPermanents = new HashSet<>(); + allPermanents.addAll(game.getBattlefield().getActivePermanents(new FilterPermanent(), source.getControllerId(), source.getSourceId(), game)); + controller.moveCards(allPermanents, Zone.HAND, source, game, false, false, true, null); + game.informPlayers(sourceObject.getLogName() + " - All permanents returned to owners' hands"); + + for (UUID playerId : game.getState().getPlayerList(controller.getId())) { + Player player = game.getPlayer(playerId); + if (player != null) { + Cards hand = player.getHand(); + int numberInHand = Math.min(7, hand.size()); + TargetCardInHand target = new TargetCardInHand(0, numberInHand, new FilterCard("cards to keep in hand")); + Cards cardsToLibrary = new CardsImpl(); + if (player.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + for (Card card : hand.getCards(game)) { + if (!target.getTargets().contains(card.getId())) { + cardsToLibrary.add(card); + card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); + } } } + player.putCardsOnTopOfLibrary(cardsToLibrary, game, source, false); + player.shuffleLibrary(game); } - player.shuffleLibrary(game); } + game.emptyManaPools(); + game.informPlayers(sourceObject.getLogName() + " - All mana pools have been emptied"); + return true; } - game.emptyManaPools(); - game.informPlayers("Worldpurge: All mana pools have been emptied"); - return true; + return false; } } diff --git a/Mage.Sets/src/mage/sets/shardsofalara/CruelUltimatum.java b/Mage.Sets/src/mage/sets/shardsofalara/CruelUltimatum.java index 6e853e8797b..7fc2a6d7ec6 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/CruelUltimatum.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/CruelUltimatum.java @@ -108,7 +108,7 @@ class CruelUltimatumEffect extends OneShotEffect { if (card == null) { return false; } - controller.moveCards(card, null, Zone.HAND, source, game); + controller.moveCards(card, Zone.HAND, source, game); } return true; } diff --git a/Mage.Sets/src/mage/sets/shardsofalara/FlameblastDragon.java b/Mage.Sets/src/mage/sets/shardsofalara/FlameblastDragon.java index e2571f54389..5e0534f9932 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/FlameblastDragon.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/FlameblastDragon.java @@ -95,7 +95,7 @@ class FlameblastDragonEffect extends OneShotEffect { if (player.chooseUse(Outcome.Damage, "Pay " + cost.getText() + "? If you do, Flameblast Dragon deals X damage to target creature or player", source, game)) { int costX = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); cost.add(new GenericManaCost(costX)); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { Permanent permanent = game.getPermanent(source.getFirstTarget()); if (permanent != null) { permanent.damage(costX, source.getSourceId(), game, false, true); diff --git a/Mage.Sets/src/mage/sets/shardsofalara/PrinceOfThralls.java b/Mage.Sets/src/mage/sets/shardsofalara/PrinceOfThralls.java index f8643ddaf9e..a9f79f6b331 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/PrinceOfThralls.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/PrinceOfThralls.java @@ -146,7 +146,7 @@ class PrinceOfThrallsEffect extends OneShotEffect { PayLifeCost cost = new PayLifeCost(3); if (opponent.chooseUse(Outcome.Neutral, cost.getText() + " or " + card.getLogName() + " comes back into the battlefield under opponents control", source, game)) { cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), opponent.getId(), true)) { + if (cost.pay(source, game, source.getSourceId(), opponent.getId(), true, null)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/shardsofalara/RealmRazer.java b/Mage.Sets/src/mage/sets/shardsofalara/RealmRazer.java index 0f7291ab53e..7119873a085 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/RealmRazer.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/RealmRazer.java @@ -124,7 +124,7 @@ class RealmRazerEffect extends OneShotEffect { if (controller != null) { ExileZone exZone = game.getExile().getExileZone(source.getSourceId()); if (exZone != null) { - return controller.moveCards(exZone.getCards(game), Zone.BATTLEFIELD, source, game, true, false, false, null); + return controller.moveCards(exZone.getCards(game), Zone.BATTLEFIELD, source, game, true, false, true, null); } return true; } diff --git a/Mage.Sets/src/mage/sets/shardsofalara/Scourglass.java b/Mage.Sets/src/mage/sets/shardsofalara/Scourglass.java index 9efaefc29ce..aa6dcad487c 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/Scourglass.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/Scourglass.java @@ -29,16 +29,15 @@ package mage.sets.shardsofalara; import java.util.UUID; import mage.abilities.Ability; - -import mage.constants.CardType; -import mage.constants.Rarity; 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.effects.common.DestroyAllEffect; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.PhaseStep; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; @@ -51,19 +50,18 @@ import mage.filter.predicate.mageobject.CardTypePredicate; public class Scourglass extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("permanents except for artifacts and lands"); - - static{ + + static { filter.add(Predicates.not(Predicates.or(new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.LAND)))); } - + public Scourglass(UUID ownerId) { super(ownerId, 25, "Scourglass", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{3}{W}{W}"); this.expansionSetCode = "ALA"; - - // {tap}, Sacrifice Scourglass: Destroy all permanents except for artifacts and lands. Activate this ability only during your upkeep. + // {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), null); + new DestroyAllEffect(filter), new TapSourceCost(), new IsStepCondition(PhaseStep.UPKEEP), null); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/shardsofalara/Skeletonize.java b/Mage.Sets/src/mage/sets/shardsofalara/Skeletonize.java index 18cf0faca35..9f5b1ef120e 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/Skeletonize.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/Skeletonize.java @@ -62,7 +62,6 @@ public class Skeletonize extends CardImpl { super(ownerId, 114, "Skeletonize", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{4}{R}"); this.expansionSetCode = "ALA"; - // Skeletonize deals 3 damage to target creature. this.getSpellAbility().addEffect(new DamageTargetEffect(3)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); @@ -100,10 +99,7 @@ class SkeletonizeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { DelayedTriggeredAbility delayedAbility = new SkeletonizeDelayedTriggeredAbility(); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } } @@ -130,7 +126,7 @@ class SkeletonizeDelayedTriggeredAbility extends DelayedTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - ZoneChangeEvent zce = (ZoneChangeEvent) event; + ZoneChangeEvent zce = (ZoneChangeEvent) event; if (zce.isDiesEvent()) { DamagedByWatcher watcher = (DamagedByWatcher) game.getState().getWatchers().get("DamagedByWatcher", this.getSourceId()); if (watcher != null) { diff --git a/Mage.Sets/src/mage/sets/sorinvstibalt/CoalStoker.java b/Mage.Sets/src/mage/sets/sorinvstibalt/CoalStoker.java index 90aebf995f4..85b2aa32175 100644 --- a/Mage.Sets/src/mage/sets/sorinvstibalt/CoalStoker.java +++ b/Mage.Sets/src/mage/sets/sorinvstibalt/CoalStoker.java @@ -57,7 +57,7 @@ public class CoalStoker extends CardImpl { // When Coal Stoker enters the battlefield, if you cast it from your hand, add {R}{R}{R} to your mana pool. Ability ability = new EntersBattlefieldTriggeredAbility( - new ConditionalOneShotEffect(new BasicManaEffect(new Mana(3, 0, 0, 0, 0, 0, 0)), new CastFromHandCondition(), + new ConditionalOneShotEffect(new BasicManaEffect(new Mana(3, 0, 0, 0, 0, 0, 0, 0)), new CastFromHandCondition(), " if you cast it from your hand, add {R}{R}{R} to your mana pool.")); this.addAbility(ability, new CastFromHandWatcher()); } diff --git a/Mage.Sets/src/mage/sets/speedvscunning/AquamorphEntity.java b/Mage.Sets/src/mage/sets/speedvscunning/AquamorphEntity.java index c286fd7ffbe..6b6dd7eea35 100644 --- a/Mage.Sets/src/mage/sets/speedvscunning/AquamorphEntity.java +++ b/Mage.Sets/src/mage/sets/speedvscunning/AquamorphEntity.java @@ -29,11 +29,11 @@ package mage.sets.speedvscunning; import java.util.UUID; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; import mage.abilities.keyword.MorphAbility; import mage.cards.CardImpl; import mage.choices.Choice; @@ -42,14 +42,13 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; +import mage.constants.SubLayer; import mage.constants.Zone; import mage.game.Game; import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; -import mage.game.permanent.PermanentCard; -import mage.game.permanent.PermanentToken; import mage.players.Player; /** @@ -113,7 +112,7 @@ class AquamorphEntityReplacementEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == EventType.ENTERS_THE_BATTLEFIELD) { if (event.getTargetId().equals(source.getSourceId())) { - Permanent sourcePermanent = ((EntersTheBattlefieldEvent) event).getTarget();; + Permanent sourcePermanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (sourcePermanent != null && !sourcePermanent.isFaceDown(game)) { return true; } @@ -127,14 +126,14 @@ class AquamorphEntityReplacementEffect extends ReplacementEffectImpl { return false; } - @Override - public boolean apply(Game game, Ability source) { - return false; - } - @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); + Permanent permanent; + if (event instanceof EntersTheBattlefieldEvent) { + permanent = ((EntersTheBattlefieldEvent) event).getTarget(); + } else { + permanent = game.getPermanent(event.getTargetId()); + } if (permanent != null) { Choice choice = new ChoiceImpl(true); choice.setMessage("Choose what the creature becomes to"); @@ -149,22 +148,19 @@ class AquamorphEntityReplacementEffect extends ReplacementEffectImpl { } } } - MageObject mageObject; - if (permanent instanceof PermanentCard) { - mageObject = ((PermanentCard) permanent).getCard(); - } else { - mageObject = ((PermanentToken) permanent).getToken(); - } + int power = 0; + int toughness = 0; switch (choice.getChoice()) { case choice51: - mageObject.getPower().setValue(5); - mageObject.getToughness().setValue(1); + power = 5; + toughness = 1; break; case choice15: - mageObject.getPower().setValue(1); - mageObject.getToughness().setValue(5); + power = 1; + toughness = 5; break; } + game.addEffect(new SetPowerToughnessSourceEffect(power, toughness, Duration.Custom, SubLayer.SetPT_7b), source); } return false; diff --git a/Mage.Sets/src/mage/sets/stronghold/Heartstone.java b/Mage.Sets/src/mage/sets/stronghold/Heartstone.java index 0d530dfacd3..f2c466c3c94 100644 --- a/Mage.Sets/src/mage/sets/stronghold/Heartstone.java +++ b/Mage.Sets/src/mage/sets/stronghold/Heartstone.java @@ -90,7 +90,7 @@ class HeartstoneEffect extends CostModificationEffectImpl { Player controller = game.getPlayer(abilityToModify.getControllerId()); if (controller != null) { Mana mana = abilityToModify.getManaCostsToPay().getMana(); - if (mana.count() > 1 && mana.getColorless() > 0) { + if (mana.count() > 1 && mana.getGeneric() > 0) { CardUtil.reduceCost(abilityToModify, 1); } return true; diff --git a/Mage.Sets/src/mage/sets/stronghold/Overgrowth.java b/Mage.Sets/src/mage/sets/stronghold/Overgrowth.java index 2d4aec7bcc8..6a06deddebb 100644 --- a/Mage.Sets/src/mage/sets/stronghold/Overgrowth.java +++ b/Mage.Sets/src/mage/sets/stronghold/Overgrowth.java @@ -83,7 +83,7 @@ class OvergrowthTriggeredAbility extends TriggeredManaAbility { public OvergrowthTriggeredAbility() { - super(Zone.BATTLEFIELD, new AddManaToManaPoolTargetControllerEffect(new Mana(0,2,0,0,0,0,0), "his or her")); + super(Zone.BATTLEFIELD, new AddManaToManaPoolTargetControllerEffect(new Mana(0,2,0,0,0,0,0, 0), "his or her")); } public OvergrowthTriggeredAbility(final OvergrowthTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/sets/tempest/CorpseDance.java b/Mage.Sets/src/mage/sets/tempest/CorpseDance.java index 0087bb59d0c..5a157c94c96 100644 --- a/Mage.Sets/src/mage/sets/tempest/CorpseDance.java +++ b/Mage.Sets/src/mage/sets/tempest/CorpseDance.java @@ -115,10 +115,7 @@ class CorpseDanceEffect extends OneShotEffect { ExileTargetEffect exileEffect = new ExileTargetEffect(null, "", Zone.BATTLEFIELD); exileEffect.setTargetPointer(fixedTarget); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } } } diff --git a/Mage.Sets/src/mage/sets/tempest/EssenceBottle.java b/Mage.Sets/src/mage/sets/tempest/EssenceBottle.java index faa799dd012..e1b65510d10 100644 --- a/Mage.Sets/src/mage/sets/tempest/EssenceBottle.java +++ b/Mage.Sets/src/mage/sets/tempest/EssenceBottle.java @@ -98,7 +98,7 @@ class EssenceBottleCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(ability.getSourceId()); if (permanent != null) { this.removedCounters = permanent.getCounters().getCount(CounterType.ELIXIR); diff --git a/Mage.Sets/src/mage/sets/tempest/ReflectingPool.java b/Mage.Sets/src/mage/sets/tempest/ReflectingPool.java index 005b0e53f88..1abb636666c 100644 --- a/Mage.Sets/src/mage/sets/tempest/ReflectingPool.java +++ b/Mage.Sets/src/mage/sets/tempest/ReflectingPool.java @@ -76,7 +76,7 @@ public class ReflectingPool extends CardImpl { class ReflectingPoolManaAbility extends ManaAbility { public ReflectingPoolManaAbility() { - super(Zone.BATTLEFIELD, new ReflectingPoolEffect(),new TapSourceCost()); + super(Zone.BATTLEFIELD, new ReflectingPoolEffect(), new TapSourceCost()); } public ReflectingPoolManaAbility(final ReflectingPoolManaAbility ability) { @@ -90,7 +90,7 @@ class ReflectingPoolManaAbility extends ManaAbility { @Override public List getNetMana(Game game) { - return ((ReflectingPoolEffect)getEffects().get(0)).getNetMana(game, this); + return ((ReflectingPoolEffect) getEffects().get(0)).getNetMana(game, this); } } @@ -176,11 +176,11 @@ class ReflectingPoolEffect extends ManaEffect { return true; } - public List getNetMana(Game game, Ability source) { + public List getNetMana(Game game, Ability source) { List netManas = new ArrayList<>(); Mana types = getManaTypes(game, source); - if (types.getAny()> 0) { - netManas.add(new Mana(0,0,0,0,0,0,1)); + if (types.getAny() > 0) { + netManas.add(new Mana(0, 0, 0, 0, 0, 0, 1, 0)); return netManas; } if (types.getBlack() > 0) { @@ -199,7 +199,7 @@ class ReflectingPoolEffect extends ManaEffect { netManas.add(new Mana(ColoredManaSymbol.W)); } if (types.getColorless() > 0) { - netManas.add(new Mana(0,0,0,0,0,1,0)); + netManas.add(new Mana(0, 0, 0, 0, 0, 0, 0, 1)); } return netManas; } @@ -211,7 +211,7 @@ class ReflectingPoolEffect extends ManaEffect { Abilities manaAbilities = land.getAbilities().getManaAbilities(Zone.BATTLEFIELD); for (ManaAbility ability : manaAbilities) { if (!ability.equals(source) && ability.definesMana()) { - for (Mana netMana: ability.getNetMana(game)) { + for (Mana netMana : ability.getNetMana(game)) { types.add(netMana); if (netMana.getAny() > 0) { return types; diff --git a/Mage.Sets/src/mage/sets/tempest/TortureChamber.java b/Mage.Sets/src/mage/sets/tempest/TortureChamber.java index 8768d304fa5..627b584672d 100644 --- a/Mage.Sets/src/mage/sets/tempest/TortureChamber.java +++ b/Mage.Sets/src/mage/sets/tempest/TortureChamber.java @@ -103,7 +103,7 @@ class TortureChamberCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(ability.getSourceId()); if (permanent != null) { this.removedCounters = permanent.getCounters().getCount(CounterType.PAIN); diff --git a/Mage.Sets/src/mage/sets/tempestremastered/Necrologia.java b/Mage.Sets/src/mage/sets/tempestremastered/Necrologia.java index dd32de85bc5..09eb11c5f86 100644 --- a/Mage.Sets/src/mage/sets/tempestremastered/Necrologia.java +++ b/Mage.Sets/src/mage/sets/tempestremastered/Necrologia.java @@ -28,26 +28,15 @@ package mage.sets.tempestremastered; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.costs.common.PayVariableLifeCost; -import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.GetXValue; -import mage.abilities.dynamicvalue.common.ManacostVariableValue; -import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.cards.CardImpl; import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; import mage.constants.PhaseStep; import mage.constants.Rarity; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; /** * @@ -60,13 +49,12 @@ public class Necrologia extends CardImpl { this.expansionSetCode = "TPR"; // Cast Necrologia only during your end step. - Ability ability = new SimpleStaticAbility(Zone.ALL, new NecrologiaTimingEffect()); - ability.setRuleAtTheTop(true); - this.addAbility(ability); - + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, PhaseStep.END_TURN, MyTurnCondition.getInstance(), + "Cast {this} only during your end step")); + // As an additional cost to cast to Necrologia, pay X life. this.getSpellAbility().addCost(new PayVariableLifeCost(true)); - + // Draw X cards. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(new GetXValue())); } @@ -80,35 +68,3 @@ public class Necrologia extends CardImpl { return new Necrologia(this); } } - -class NecrologiaTimingEffect extends ContinuousRuleModifyingEffectImpl { - NecrologiaTimingEffect() { - super(Duration.EndOfGame, Outcome.Detriment); - staticText = "Cast {this} only during your end step"; - } - - NecrologiaTimingEffect(final NecrologiaTimingEffect effect) { - super(effect); - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType().equals(GameEvent.EventType.CAST_SPELL); - } - - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getSourceId().equals(source.getSourceId())) { - if (!game.getActivePlayerId().equals(source.getControllerId()) || !PhaseStep.END_TURN.equals(game.getTurn().getStepType())) { - return true; - } - } - return false; - } - - @Override - public NecrologiaTimingEffect copy() { - return new NecrologiaTimingEffect(this); - } -} diff --git a/Mage.Sets/src/mage/sets/tenthedition/CompositeGolem.java b/Mage.Sets/src/mage/sets/tenthedition/CompositeGolem.java index bea103f47a7..958d06f8b4c 100644 --- a/Mage.Sets/src/mage/sets/tenthedition/CompositeGolem.java +++ b/Mage.Sets/src/mage/sets/tenthedition/CompositeGolem.java @@ -52,7 +52,7 @@ public class CompositeGolem extends CardImpl { this.toughness = new MageInt(4); // Sacrifice Composite Golem: Add {W}{U}{B}{R}{G} to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 1, 1, 1, 0, 0), new SacrificeSourceCost())); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(1, 1, 1, 1, 1, 0, 0, 0), new SacrificeSourceCost())); } public CompositeGolem(final CompositeGolem card) { diff --git a/Mage.Sets/src/mage/sets/tenthedition/DoublingCube.java b/Mage.Sets/src/mage/sets/tenthedition/DoublingCube.java index 99ea557b4ee..cd8e15c2f81 100644 --- a/Mage.Sets/src/mage/sets/tenthedition/DoublingCube.java +++ b/Mage.Sets/src/mage/sets/tenthedition/DoublingCube.java @@ -93,7 +93,7 @@ class DoublingCubeEffect extends ManaEffect { int greenMana = pool.getGreen(); int redMana = pool.getRed(); int colorlessMana = pool.getColorless(); - Mana mana = new Mana(redMana, greenMana, blueMana, whiteMana, blackMana, colorlessMana, 0); + Mana mana = new Mana(redMana, greenMana, blueMana, whiteMana, blackMana, colorlessMana, 0, 0); checkToFirePossibleEvents(mana, game, source); pool.addMana(mana, game, source); return true; diff --git a/Mage.Sets/src/mage/sets/tenthedition/MidnightRitual.java b/Mage.Sets/src/mage/sets/tenthedition/MidnightRitual.java new file mode 100644 index 00000000000..5853ace91bb --- /dev/null +++ b/Mage.Sets/src/mage/sets/tenthedition/MidnightRitual.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.tenthedition; + +import java.util.UUID; + +/** + * + * @author Skyler Sell + */ +public class MidnightRitual extends mage.sets.mercadianmasques.MidnightRitual { + + public MidnightRitual(UUID ownerId) { + super(ownerId); + this.cardNumber = 158; + this.expansionSetCode = "10E"; + } + + public MidnightRitual(final MidnightRitual card) { + super(card); + } + + @Override + public MidnightRitual copy() { + return new MidnightRitual(this); + } +} diff --git a/Mage.Sets/src/mage/sets/tenthedition/Plagiarize.java b/Mage.Sets/src/mage/sets/tenthedition/Plagiarize.java new file mode 100644 index 00000000000..071fdc37f59 --- /dev/null +++ b/Mage.Sets/src/mage/sets/tenthedition/Plagiarize.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.tenthedition; + +import java.util.UUID; + +/** + * + * @author Skyler Sell + */ +public class Plagiarize extends mage.sets.ninthedition.Plagiarize { + + public Plagiarize(UUID ownerId) { + super(ownerId); + this.cardNumber = 97; + this.expansionSetCode = "10E"; + } + + public Plagiarize(final Plagiarize card) { + super(card); + } + + @Override + public Plagiarize copy() { + return new Plagiarize(this); + } +} diff --git a/Mage.Sets/src/mage/sets/theros/BoonOfErebos.java b/Mage.Sets/src/mage/sets/theros/BoonOfErebos.java index 74afa663602..cc3db8d3855 100644 --- a/Mage.Sets/src/mage/sets/theros/BoonOfErebos.java +++ b/Mage.Sets/src/mage/sets/theros/BoonOfErebos.java @@ -28,6 +28,7 @@ package mage.sets.theros; import java.util.UUID; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.RegenerateTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; @@ -47,11 +48,12 @@ public class BoonOfErebos extends CardImpl { super(ownerId, 80, "Boon of Erebos", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{B}"); this.expansionSetCode = "THS"; - // Target creature gets +2/+0 until end of turn. Regenerate it. You lose 2 life. - this.getSpellAbility().addEffect(new BoostTargetEffect(2,0, Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new BoostTargetEffect(2, 0, Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(new RegenerateTargetEffect()); + Effect effect = new RegenerateTargetEffect(); + effect.setText("Regenerate it"); + this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(new LoseLifeSourceControllerEffect(2)); } diff --git a/Mage.Sets/src/mage/sets/theros/RescueFromTheUnderworld.java b/Mage.Sets/src/mage/sets/theros/RescueFromTheUnderworld.java index d5e83a36b87..8d7aff9b561 100644 --- a/Mage.Sets/src/mage/sets/theros/RescueFromTheUnderworld.java +++ b/Mage.Sets/src/mage/sets/theros/RescueFromTheUnderworld.java @@ -150,9 +150,6 @@ class RescueFromTheUnderworldCreateDelayedTriggeredAbilityEffect extends OneShot @Override public boolean apply(Game game, Ability source) { DelayedTriggeredAbility delayedAbility = (DelayedTriggeredAbility) ability.copy(); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); delayedAbility.getTargets().addAll(source.getTargets()); for (Effect effect : delayedAbility.getEffects()) { effect.getTargetPointer().init(game, source); @@ -169,7 +166,7 @@ class RescueFromTheUnderworldCreateDelayedTriggeredAbilityEffect extends OneShot } } - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } diff --git a/Mage.Sets/src/mage/sets/theros/WhipOfErebos.java b/Mage.Sets/src/mage/sets/theros/WhipOfErebos.java index 8d9dd84c469..0ff234badb8 100644 --- a/Mage.Sets/src/mage/sets/theros/WhipOfErebos.java +++ b/Mage.Sets/src/mage/sets/theros/WhipOfErebos.java @@ -126,10 +126,7 @@ class WhipOfErebosEffect extends OneShotEffect { ExileTargetEffect exileEffect = new ExileTargetEffect(null, null, Zone.BATTLEFIELD); exileEffect.setTargetPointer(new FixedTarget(creature, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } } return true; diff --git a/Mage.Sets/src/mage/sets/timeshifted/MysticEnforcer.java b/Mage.Sets/src/mage/sets/timeshifted/MysticEnforcer.java index 2c9a23cb576..9e09d1d7d4b 100644 --- a/Mage.Sets/src/mage/sets/timeshifted/MysticEnforcer.java +++ b/Mage.Sets/src/mage/sets/timeshifted/MysticEnforcer.java @@ -40,6 +40,7 @@ import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.ProtectionAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -72,16 +73,12 @@ public class MysticEnforcer extends CardImpl { // Protection from black this.addAbility(new ProtectionAbility(filter)); // Threshold - As long as seven or more cards are in your graveyard, Mystic Enforcer gets +3/+3 and has flying. - Ability thresholdAbility = new SimpleStaticAbility( - Zone.BATTLEFIELD, - new ConditionalContinuousEffect( - new BoostSourceEffect(3, 3, Duration.WhileOnBattlefield), - new CardsInControllerGraveCondition(7), - "Threshold - {this} gets +3/+3 as long as seven or more cards are in your graveyard" - )); - Effect effect = new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield); - effect.setText("and has flying"); - thresholdAbility.addEffect(effect); + Ability thresholdAbility = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostSourceEffect(3, 3, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), + " as long as seven or more cards are in your graveyard, {this} gets +3/+3")); + thresholdAbility.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance()), + new CardsInControllerGraveCondition(7), "and has flying")); + thresholdAbility.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(thresholdAbility); } diff --git a/Mage.Sets/src/mage/sets/timeshifted/WallOfRoots.java b/Mage.Sets/src/mage/sets/timeshifted/WallOfRoots.java index eb85758d6e5..e7b6a50e645 100644 --- a/Mage.Sets/src/mage/sets/timeshifted/WallOfRoots.java +++ b/Mage.Sets/src/mage/sets/timeshifted/WallOfRoots.java @@ -34,6 +34,7 @@ import mage.constants.Zone; import mage.MageInt; import mage.Mana; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.effects.common.BasicManaEffect; import mage.abilities.keyword.DefenderAbility; @@ -90,7 +91,7 @@ class WallOfRootsCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { permanent.addCounters(new BoostCounter(0, -1), game); diff --git a/Mage.Sets/src/mage/sets/timespiral/ForiysianTotem.java b/Mage.Sets/src/mage/sets/timespiral/ForiysianTotem.java index f5c35e200ed..20f34eb9468 100644 --- a/Mage.Sets/src/mage/sets/timespiral/ForiysianTotem.java +++ b/Mage.Sets/src/mage/sets/timespiral/ForiysianTotem.java @@ -83,7 +83,7 @@ public class ForiysianTotem extends CardImpl { class ForiysianTotemToken extends Token { public ForiysianTotemToken() { - super("", "4/4 red Giant artifact creature"); + super("", "4/4 red Giant artifact creature with trample"); cardType.add(CardType.CREATURE); cardType.add(CardType.ARTIFACT); subtype.add("Giant"); @@ -92,4 +92,4 @@ class ForiysianTotemToken extends Token { toughness = new MageInt(4); this.addAbility(TrampleAbility.getInstance()); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/timespiral/NorinTheWary.java b/Mage.Sets/src/mage/sets/timespiral/NorinTheWary.java index 1b0a67fb131..a71e1722ebe 100644 --- a/Mage.Sets/src/mage/sets/timespiral/NorinTheWary.java +++ b/Mage.Sets/src/mage/sets/timespiral/NorinTheWary.java @@ -30,7 +30,7 @@ package mage.sets.timespiral; import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.common.ExileReturnToBattlefieldOwnerNextEndStepEffect; +import mage.abilities.effects.common.ExileReturnBattlefieldOwnerNextEndStepSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; @@ -73,7 +73,7 @@ public class NorinTheWary extends CardImpl { class NorinTheWaryTriggeredAbility extends TriggeredAbilityImpl { public NorinTheWaryTriggeredAbility() { - super(Zone.BATTLEFIELD, new ExileReturnToBattlefieldOwnerNextEndStepEffect(true), false); + super(Zone.BATTLEFIELD, new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(true), false); } public NorinTheWaryTriggeredAbility(final NorinTheWaryTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/sets/timespiral/SaffiEriksdotter.java b/Mage.Sets/src/mage/sets/timespiral/SaffiEriksdotter.java index ef34134f210..edb69129dd4 100644 --- a/Mage.Sets/src/mage/sets/timespiral/SaffiEriksdotter.java +++ b/Mage.Sets/src/mage/sets/timespiral/SaffiEriksdotter.java @@ -102,15 +102,11 @@ class SaffiEriksdotterEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { DelayedTriggeredAbility delayedAbility = new SaffiEriksdotterDelayedTriggeredAbility(new FixedTarget(this.getTargetPointer().getFirst(game, source))); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return false; } } - class SaffiEriksdotterDelayedTriggeredAbility extends DelayedTriggeredAbility { protected FixedTarget fixedTarget; @@ -140,7 +136,7 @@ class SaffiEriksdotterDelayedTriggeredAbility extends DelayedTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { if (((ZoneChangeEvent) event).isDiesEvent()) { if (fixedTarget.getFirst(game, this).equals(event.getTargetId())) { - if (this.getControllerId().equals(event.getPlayerId())){ + if (this.getControllerId().equals(event.getPlayerId())) { return true; } } @@ -153,5 +149,3 @@ class SaffiEriksdotterDelayedTriggeredAbility extends DelayedTriggeredAbility { return "When target creature is put into your graveyard from the battlefield this turn, " + super.getRule(); } } - - diff --git a/Mage.Sets/src/mage/sets/torment/AvenTrooper.java b/Mage.Sets/src/mage/sets/torment/AvenTrooper.java new file mode 100644 index 00000000000..28b41e8953f --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/AvenTrooper.java @@ -0,0 +1,74 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class AvenTrooper extends CardImpl { + + public AvenTrooper(UUID ownerId) { + super(ownerId, 2, "Aven Trooper", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{W}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Bird"); + this.subtype.add("Soldier"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // {2}{W}, Discard a card: Aven Trooper gets +1/+2 until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 2, Duration.EndOfTurn), new ManaCostsImpl("{2}{W}")); + ability.addCost(new DiscardCardCost()); + this.addAbility(ability); + } + + public AvenTrooper(final AvenTrooper card) { + super(card); + } + + @Override + public AvenTrooper copy() { + return new AvenTrooper(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/BoneshardSlasher.java b/Mage.Sets/src/mage/sets/torment/BoneshardSlasher.java new file mode 100644 index 00000000000..cff6595ec72 --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/BoneshardSlasher.java @@ -0,0 +1,83 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BecomesTargetTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class BoneshardSlasher extends CardImpl { + + public BoneshardSlasher(UUID ownerId) { + super(ownerId, 50, "Boneshard Slasher", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{B}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Horror"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // Threshold - As long as seven or more cards are in your graveyard, Boneshard Slasher gets +2/+2 and has "When Boneshard Slasher becomes the target of a spell or ability, sacrifice it." + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), + "As long as seven or more cards are in your graveyard, {this} gets +2/+2")); + Effect effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect())), + new CardsInControllerGraveCondition(7), "and has \"When {this} becomes the target of a spell or ability, sacrifice it.\""); + ability.addEffect(effect); + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); + } + + public BoneshardSlasher(final BoneshardSlasher card) { + super(card); + } + + @Override + public BoneshardSlasher copy() { + return new BoneshardSlasher(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/CabalRitual.java b/Mage.Sets/src/mage/sets/torment/CabalRitual.java index 203914aba3f..129f3234fba 100644 --- a/Mage.Sets/src/mage/sets/torment/CabalRitual.java +++ b/Mage.Sets/src/mage/sets/torment/CabalRitual.java @@ -50,8 +50,8 @@ public class CabalRitual extends CardImpl { // Add {B}{B}{B} to your mana pool. // Threshold — Add {B}{B}{B}{B}{B} to your mana pool instead if seven or more cards are in your graveyard. this.getSpellAbility().addEffect(new ConditionalManaEffect( - new BasicManaEffect(new Mana(0, 0, 0, 0, 5, 0, 0)), - new BasicManaEffect(new Mana(0, 0, 0, 0, 3, 0, 0)), + new BasicManaEffect(new Mana(0, 0, 0, 0, 5, 0, 0, 0)), + new BasicManaEffect(new Mana(0, 0, 0, 0, 3, 0, 0, 0)), new CardsInControllerGraveCondition(7), "Add {B}{B}{B} to your mana pool.

Threshold - Add {B}{B}{B}{B}{B} to your mana pool instead if seven or more cards are in your graveyard")); } diff --git a/Mage.Sets/src/mage/sets/torment/CentaurVeteran.java b/Mage.Sets/src/mage/sets/torment/CentaurVeteran.java new file mode 100644 index 00000000000..b1f60bb6a16 --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/CentaurVeteran.java @@ -0,0 +1,72 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class CentaurVeteran extends CardImpl { + + public CentaurVeteran(UUID ownerId) { + super(ownerId, 123, "Centaur Veteran", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{5}{G}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Centaur"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + // {G}, Discard a card: Regenerate Centaur Veteran. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{G}")); + ability.addCost(new DiscardCardCost()); + this.addAbility(ability); + } + + public CentaurVeteran(final CentaurVeteran card) { + super(card); + } + + @Override + public CentaurVeteran copy() { + return new CentaurVeteran(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/CephalidSage.java b/Mage.Sets/src/mage/sets/torment/CephalidSage.java new file mode 100644 index 00000000000..3af20f45406 --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/CephalidSage.java @@ -0,0 +1,75 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class CephalidSage extends CardImpl { + + public CephalidSage(UUID ownerId) { + super(ownerId, 29, "Cephalid Sage", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{U}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Cephalid"); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Threshold - As long as seven or more cards are in your graveyard, Cephalid Sage has "When Cephalid Sage enters the battlefield, draw three cards, then discard two cards." + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new GainAbilitySourceEffect(new EntersBattlefieldTriggeredAbility(new DrawDiscardControllerEffect(3, 2))), + new CardsInControllerGraveCondition(7), + "As long as seven or more cards are in your graveyard, {this} has \"When {this} enters the battlefield, draw three cards, then discard two cards.\"")); + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); + } + + public CephalidSage(final CephalidSage card) { + super(card); + } + + @Override + public CephalidSage copy() { + return new CephalidSage(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/ChurningEddy.java b/Mage.Sets/src/mage/sets/torment/ChurningEddy.java new file mode 100644 index 00000000000..23f5a207c6a --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/ChurningEddy.java @@ -0,0 +1,65 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author LoneFox + */ +public class ChurningEddy extends CardImpl { + + public ChurningEddy(UUID ownerId) { + super(ownerId, 32, "Churning Eddy", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{3}{U}"); + this.expansionSetCode = "TOR"; + + // Return target creature and target land to their owners' hands. + Effect effect = new ReturnToHandTargetEffect(true, true); + effect.setText("Return target creature and target land to their owners' hands"); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetLandPermanent()); + } + + public ChurningEddy(final ChurningEddy card) { + super(card); + } + + @Override + public ChurningEddy copy() { + return new ChurningEddy(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/CracklingClub.java b/Mage.Sets/src/mage/sets/torment/CracklingClub.java new file mode 100644 index 00000000000..23bf0d0bda6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/CracklingClub.java @@ -0,0 +1,81 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class CracklingClub extends CardImpl { + + public CracklingClub(UUID ownerId) { + super(ownerId, 93, "Crackling Club", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{R}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature gets +1/+0. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 0, Duration.WhileOnBattlefield))); + // Sacrifice Crackling Club: Crackling Club deals 1 damage to target creature. + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new SacrificeSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public CracklingClub(final CracklingClub card) { + super(card); + } + + @Override + public CracklingClub copy() { + return new CracklingClub(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/Gloomdrifter.java b/Mage.Sets/src/mage/sets/torment/Gloomdrifter.java new file mode 100644 index 00000000000..1cc426ada7b --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/Gloomdrifter.java @@ -0,0 +1,91 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorPredicate; + +/** + * + * @author LoneFox + */ +public class Gloomdrifter extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonblack creatures"); + + static { + filter.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK))); + } + + public Gloomdrifter(UUID ownerId) { + super(ownerId, 61, "Gloomdrifter", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Zombie"); + this.subtype.add("Minion"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // Threshold - As long as seven or more cards are in your graveyard, Gloomdrifter has "When Gloomdrifter enters the battlefield, nonblack creatures get -2/-2 until end of turn." + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new GainAbilitySourceEffect(new EntersBattlefieldTriggeredAbility( + new BoostAllEffect(-2, -2, Duration.EndOfTurn, filter, false))), + new CardsInControllerGraveCondition(7), + "As long as seven or more cards are in your graveyard, {this} has \"When {this} enters the battlefield, nonblack creatures get -2/-2 until end of turn.\"")); + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); + } + + public Gloomdrifter(final Gloomdrifter card) { + super(card); + } + + @Override + public Gloomdrifter copy() { + return new Gloomdrifter(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/Gravegouger.java b/Mage.Sets/src/mage/sets/torment/Gravegouger.java new file mode 100644 index 00000000000..4b34556d5b5 --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/Gravegouger.java @@ -0,0 +1,77 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.ExileTargetForSourceEffect; +import mage.abilities.effects.common.ReturnFromExileForSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.target.common.TargetCardInASingleGraveyard; + +/** + * + * @author LoneFox + */ +public class Gravegouger extends CardImpl { + + public Gravegouger(UUID ownerId) { + super(ownerId, 62, "Gravegouger", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Nightmare"); + this.subtype.add("Horror"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // 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)); + } + + public Gravegouger(final Gravegouger card) { + super(card); + } + + @Override + public Gravegouger copy() { + return new Gravegouger(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/Hypochondria.java b/Mage.Sets/src/mage/sets/torment/Hypochondria.java new file mode 100644 index 00000000000..f758eac737c --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/Hypochondria.java @@ -0,0 +1,74 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.PreventDamageToTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author LoneFox + */ +public class Hypochondria extends CardImpl { + + public Hypochondria(UUID ownerId) { + super(ownerId, 7, "Hypochondria", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + this.expansionSetCode = "TOR"; + + // {W}, Discard a card: Prevent the next 3 damage that would be dealt to target creature or player this turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventDamageToTargetEffect(Duration.EndOfTurn, 3), new ManaCostsImpl("{W}")); + ability.addCost(new DiscardCardCost()); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(ability); + // {W}, Sacrifice Hypochondria: Prevent the next 3 damage that would be dealt to target creature or player this turn. + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventDamageToTargetEffect(Duration.EndOfTurn, 3), new ManaCostsImpl("{W}")); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(ability); + } + + public Hypochondria(final Hypochondria card) { + super(card); + } + + @Override + public Hypochondria copy() { + return new Hypochondria(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/InvigoratingFalls.java b/Mage.Sets/src/mage/sets/torment/InvigoratingFalls.java new file mode 100644 index 00000000000..28c32d7eea6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/InvigoratingFalls.java @@ -0,0 +1,63 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterCreatureCard; + +/** + * + * @author LoneFox + */ +public class InvigoratingFalls extends CardImpl { + + public InvigoratingFalls(UUID ownerId) { + super(ownerId, 128, "Invigorating Falls", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{2}{G}{G}"); + this.expansionSetCode = "TOR"; + + // You gain life equal to the number of creature cards in all graveyards. + Effect effect = new GainLifeEffect(new CardsInAllGraveyardsCount(new FilterCreatureCard())); + effect.setText("You gain life equal to the number of creature cards in all graveyards."); + this.getSpellAbility().addEffect(effect); + } + + public InvigoratingFalls(final InvigoratingFalls card) { + super(card); + } + + @Override + public InvigoratingFalls copy() { + return new InvigoratingFalls(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/KamahlsSledge.java b/Mage.Sets/src/mage/sets/torment/KamahlsSledge.java new file mode 100644 index 00000000000..e0590a85324 --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/KamahlsSledge.java @@ -0,0 +1,67 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DamageTargetControllerEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class KamahlsSledge extends CardImpl { + + public KamahlsSledge(UUID ownerId) { + super(ownerId, 102, "Kamahl's Sledge", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{5}{R}{R}"); + this.expansionSetCode = "TOR"; + + // Kamahl's Sledge deals 4 damage to target creature. + this.getSpellAbility().addEffect(new DamageTargetEffect(4)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + // Threshold - If seven or more cards are in your graveyard, instead Kamahl's Sledge deals 4 damage to that creature and 4 damage to that creature's controller. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new DamageTargetControllerEffect(4), + new CardsInControllerGraveCondition(7), + "

Threshold — If seven or more cards are in your graveyard, instead {this} deals 4 damage to that creature and 4 damage to that creature's controller.")); + } + + public KamahlsSledge(final KamahlsSledge card) { + super(card); + } + + @Override + public KamahlsSledge copy() { + return new KamahlsSledge(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/KrosanRestorer.java b/Mage.Sets/src/mage/sets/torment/KrosanRestorer.java index 83b0dcc2f8a..c1541162a9f 100644 --- a/Mage.Sets/src/mage/sets/torment/KrosanRestorer.java +++ b/Mage.Sets/src/mage/sets/torment/KrosanRestorer.java @@ -36,6 +36,7 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.UntapTargetEffect; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; @@ -60,14 +61,14 @@ public class KrosanRestorer extends CardImpl { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new UntapTargetEffect(), new TapSourceCost()); ability.addTarget(new TargetLandPermanent()); 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(Zone.BATTLEFIELD, - new UntapTargetEffect(), - new TapSourceCost(), - new CardsInControllerGraveCondition(7), - "Threshold - {T}: Untap up to three target lands. Activate this ability only if seven or more cards are in your graveyard."); + ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, + new UntapTargetEffect(), + new TapSourceCost(), + new CardsInControllerGraveCondition(7)); ability.addTarget(new TargetLandPermanent(0, 3, new FilterLandPermanent(), false)); + ability.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/torment/Mortiphobia.java b/Mage.Sets/src/mage/sets/torment/Mortiphobia.java new file mode 100644 index 00000000000..d79091e62e5 --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/Mortiphobia.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.common.TargetCardInGraveyard; + +/** + * + * @author LoneFox + */ +public class Mortiphobia extends CardImpl { + + public Mortiphobia(UUID ownerId) { + super(ownerId, 72, "Mortiphobia", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{B}"); + this.expansionSetCode = "TOR"; + + // {1}{B}, Discard a card: Exile target card from a graveyard. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(), new ManaCostsImpl("{1}{B}")); + ability.addCost(new DiscardCardCost()); + ability.addTarget(new TargetCardInGraveyard()); + this.addAbility(ability); + // {1}{B}, Sacrifice Mortiphobia: Exile target card from a graveyard. + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(), new ManaCostsImpl("{1}{B}")); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetCardInGraveyard()); + this.addAbility(ability); + } + + public Mortiphobia(final Mortiphobia card) { + super(card); + } + + @Override + public Mortiphobia copy() { + return new Mortiphobia(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/NantukoCalmer.java b/Mage.Sets/src/mage/sets/torment/NantukoCalmer.java new file mode 100644 index 00000000000..c8364477f1b --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/NantukoCalmer.java @@ -0,0 +1,86 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.common.TargetEnchantmentPermanent; + +/** + * + * @author LoneFox + */ +public class NantukoCalmer extends CardImpl { + + public NantukoCalmer(UUID ownerId) { + super(ownerId, 132, "Nantuko Calmer", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{G}{G}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Insect"); + this.subtype.add("Druid"); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // {G}, {tap}, Sacrifice Nantuko Calmer: Destroy target enchantment. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl("{G}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetEnchantmentPermanent()); + this.addAbility(ability); + // Threshold - Nantuko Calmer gets +1/+1 as long as seven or more cards are in your graveyard. + ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), + "{this} gets +1/+1 as long as seven or more cards are in your graveyard")); + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); + } + + public NantukoCalmer(final NantukoCalmer card) { + super(card); + } + + @Override + public NantukoCalmer copy() { + return new NantukoCalmer(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/Petradon.java b/Mage.Sets/src/mage/sets/torment/Petradon.java new file mode 100644 index 00000000000..69ac50e9f2d --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/Petradon.java @@ -0,0 +1,82 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +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.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author LoneFox + */ +public class Petradon extends CardImpl { + + public Petradon(UUID ownerId) { + super(ownerId, 108, "Petradon", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{6}{R}{R}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Nightmare"); + this.subtype.add("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)); + 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)); + // {R}: Petradon gets +1/+0 until end of turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl("{R}"))); + } + + public Petradon(final Petradon card) { + super(card); + } + + @Override + public Petradon copy() { + return new Petradon(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/Petravark.java b/Mage.Sets/src/mage/sets/torment/Petravark.java new file mode 100644 index 00000000000..5dd3052ab5f --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/Petravark.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.effects.common.ExileTargetForSourceEffect; +import mage.abilities.effects.common.ReturnFromExileForSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author LoneFox + */ +public class Petravark extends CardImpl { + + public Petravark(UUID ownerId) { + super(ownerId, 109, "Petravark", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{R}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Nightmare"); + this.subtype.add("Beast"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Petravark enters the battlefield, exile target land. + 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)); + } + + public Petravark(final Petravark card) { + super(card); + } + + @Override + public Petravark copy() { + return new Petravark(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/Plagiarize.java b/Mage.Sets/src/mage/sets/torment/Plagiarize.java new file mode 100644 index 00000000000..5f2203f69b5 --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/Plagiarize.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; + +/** + * + * @author Skyler Sell + */ +public class Plagiarize extends mage.sets.ninthedition.Plagiarize { + + public Plagiarize(UUID ownerId) { + super(ownerId); + this.cardNumber = 44; + this.expansionSetCode = "TOR"; + } + + public Plagiarize(final Plagiarize card) { + super(card); + } + + @Override + public Plagiarize copy() { + return new Plagiarize(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/PutridImp.java b/Mage.Sets/src/mage/sets/torment/PutridImp.java index 1f560a0d8ef..2d6fadf3c77 100644 --- a/Mage.Sets/src/mage/sets/torment/PutridImp.java +++ b/Mage.Sets/src/mage/sets/torment/PutridImp.java @@ -42,6 +42,7 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -68,12 +69,12 @@ public class PutridImp extends CardImpl { Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), - "Threshold - As long as seven or more cards are in your graveyard, {this} gets +1/+1")); + "As long as seven or more cards are in your graveyard, {this} gets +1/+1")); Effect effect = new ConditionalRestrictionEffect(new CantBlockSourceEffect(Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7)); effect.setText("and can't block"); ability.addEffect(effect); + ability.setAbilityWord(AbilityWord.THRESHOLD); this.addAbility(ability); - } public PutridImp(final PutridImp card) { diff --git a/Mage.Sets/src/mage/sets/torment/SonicSeizure.java b/Mage.Sets/src/mage/sets/torment/SonicSeizure.java new file mode 100644 index 00000000000..818d802f9a1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/SonicSeizure.java @@ -0,0 +1,63 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author LoneFox + */ +public class SonicSeizure extends CardImpl { + + public SonicSeizure(UUID ownerId) { + super(ownerId, 115, "Sonic Seizure", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{R}"); + this.expansionSetCode = "TOR"; + + // As an additional cost to cast Sonic Seizure, discard a card at random. + this.getSpellAbility().addCost(new DiscardCardCost(true)); + // Sonic Seizure deals 3 damage to target creature or player. + this.getSpellAbility().addEffect(new DamageTargetEffect(3)); + this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); + } + + public SonicSeizure(final SonicSeizure card) { + super(card); + } + + @Override + public SonicSeizure copy() { + return new SonicSeizure(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/StrengthOfIsolation.java b/Mage.Sets/src/mage/sets/torment/StrengthOfIsolation.java new file mode 100644 index 00000000000..f65ec40ec3f --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/StrengthOfIsolation.java @@ -0,0 +1,94 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.MadnessAbility; +import mage.abilities.keyword.ProtectionAbility; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; +/** + * + * @author LoneFox + */ +public class StrengthOfIsolation extends CardImpl { + + private static final FilterCard filter = new FilterCard("black"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + } + + public StrengthOfIsolation(UUID ownerId) { + super(ownerId, 17, "Strength of Isolation", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature gets +1/+2 and has protection from black. + ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 2, Duration.WhileOnBattlefield)); + Effect effect = new GainAbilityAttachedEffect(new ProtectionAbility(filter), AttachmentType.AURA); + effect.setText("and has protection from black"); + ability.addEffect(effect); + this.addAbility(ability); + // Madness {W} + this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{W}"))); + } + + public StrengthOfIsolation(final StrengthOfIsolation card) { + super(card); + } + + @Override + public StrengthOfIsolation copy() { + return new StrengthOfIsolation(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/StrengthOfLunacy.java b/Mage.Sets/src/mage/sets/torment/StrengthOfLunacy.java new file mode 100644 index 00000000000..96090b168d3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/StrengthOfLunacy.java @@ -0,0 +1,95 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.MadnessAbility; +import mage.abilities.keyword.ProtectionAbility; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class StrengthOfLunacy extends CardImpl { + + private static final FilterCard filter = new FilterCard("white"); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + } + + public StrengthOfLunacy(UUID ownerId) { + super(ownerId, 86, "Strength of Lunacy", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature gets +2/+1 and has protection from white. + ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, 1, Duration.WhileOnBattlefield)); + Effect effect = new GainAbilityAttachedEffect(new ProtectionAbility(filter), AttachmentType.AURA); + effect.setText("and has protection from white"); + ability.addEffect(effect); + this.addAbility(ability); + // Madness {B} + this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{B}"))); + } + + public StrengthOfLunacy(final StrengthOfLunacy card) { + super(card); + } + + @Override + public StrengthOfLunacy copy() { + return new StrengthOfLunacy(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/TerohsVanguard.java b/Mage.Sets/src/mage/sets/torment/TerohsVanguard.java new file mode 100644 index 00000000000..401c09283cf --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/TerohsVanguard.java @@ -0,0 +1,93 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.ProtectionAbility; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; + +/** + * + * @author LoneFox + */ +public class TerohsVanguard extends CardImpl { + + private static final FilterCard filter = new FilterCard("black"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + } + + public TerohsVanguard(UUID ownerId) { + super(ownerId, 19, "Teroh's Vanguard", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{W}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Human"); + this.subtype.add("Nomad"); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flash + this.addAbility(FlashAbility.getInstance()); + // Threshold - As long as seven or more cards are in your graveyard, Teroh's Vanguard has "When Teroh's Vanguard enters the battlefield, creatures you control gain protection from black until end of turn." + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new GainAbilitySourceEffect(new EntersBattlefieldTriggeredAbility( + new GainAbilityControlledEffect(new ProtectionAbility(filter), Duration.EndOfTurn, new FilterCreaturePermanent()))), + new CardsInControllerGraveCondition(7), + "As long as seven or more cards are in your graveyard, {this} has \"When {this} enters the battlefield, creatures you control gain protection from black until end of turn.\"")); + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); + + } + + public TerohsVanguard(final TerohsVanguard card) { + super(card); + } + + @Override + public TerohsVanguard copy() { + return new TerohsVanguard(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/WasteAway.java b/Mage.Sets/src/mage/sets/torment/WasteAway.java new file mode 100644 index 00000000000..3d71a70299e --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/WasteAway.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class WasteAway extends CardImpl { + + public WasteAway(UUID ownerId) { + super(ownerId, 88, "Waste Away", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{4}{B}"); + this.expansionSetCode = "TOR"; + + // As an additional cost to cast Waste Away, discard a card. + this.getSpellAbility().addCost(new DiscardCardCost()); + // Target creature gets -5/-5 until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(-5, -5, Duration.EndOfTurn)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public WasteAway(final WasteAway card) { + super(card); + } + + @Override + public WasteAway copy() { + return new WasteAway(this); + } +} diff --git a/Mage.Sets/src/mage/sets/unlimitededition/LibraryOfLeng.java b/Mage.Sets/src/mage/sets/unlimitededition/LibraryOfLeng.java new file mode 100644 index 00000000000..0db34db7436 --- /dev/null +++ b/Mage.Sets/src/mage/sets/unlimitededition/LibraryOfLeng.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.unlimitededition; + +import java.util.UUID; + +/** + * + * @author LevelX2 + */ +public class LibraryOfLeng extends mage.sets.limitedbeta.LibraryOfLeng { + + public LibraryOfLeng(UUID ownerId) { + super(ownerId); + this.cardNumber = 258; + this.expansionSetCode = "2ED"; + } + + public LibraryOfLeng(final LibraryOfLeng card) { + super(card); + } + + @Override + public LibraryOfLeng copy() { + return new LibraryOfLeng(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzaslegacy/MoltenHydra.java b/Mage.Sets/src/mage/sets/urzaslegacy/MoltenHydra.java index c98e7d98caa..3e0f9f8cc73 100644 --- a/Mage.Sets/src/mage/sets/urzaslegacy/MoltenHydra.java +++ b/Mage.Sets/src/mage/sets/urzaslegacy/MoltenHydra.java @@ -111,7 +111,7 @@ class RemoveAllCountersSourceCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { this.amount = permanent.getCounters().getCount(name); diff --git a/Mage.Sets/src/mage/sets/urzaslegacy/SlowMotion.java b/Mage.Sets/src/mage/sets/urzaslegacy/SlowMotion.java index ffe52f22517..20f81031958 100644 --- a/Mage.Sets/src/mage/sets/urzaslegacy/SlowMotion.java +++ b/Mage.Sets/src/mage/sets/urzaslegacy/SlowMotion.java @@ -108,7 +108,7 @@ class SacrificeEquipedUnlessPaysEffect extends OneShotEffect { if (player != null && equipped != null) { if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "? (Or " + equipped.getName() + " will be sacrificed.)", source, game)) { cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), equipped.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), equipped.getControllerId(), false, null)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/urzassaga/ArgothianWurm.java b/Mage.Sets/src/mage/sets/urzassaga/ArgothianWurm.java index 159db3e05a6..a98359478a6 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/ArgothianWurm.java +++ b/Mage.Sets/src/mage/sets/urzassaga/ArgothianWurm.java @@ -101,7 +101,7 @@ class ArgothianWurmEffect extends PutOnLibrarySourceEffect { if (player != null && cost.canPay(source, source.getSourceId(), playerId, game) && player.chooseUse(Outcome.Sacrifice, "Sacrifice a land?", source, game) - && cost.pay(source, game, source.getSourceId(), playerId, true)) { + && cost.pay(source, game, source.getSourceId(), playerId, true, null)) { costPaid = true; } } diff --git a/Mage.Sets/src/mage/sets/urzassaga/CarpetOfFlowers.java b/Mage.Sets/src/mage/sets/urzassaga/CarpetOfFlowers.java index 8f6e677c103..dcc9eeaf127 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/CarpetOfFlowers.java +++ b/Mage.Sets/src/mage/sets/urzassaga/CarpetOfFlowers.java @@ -202,7 +202,7 @@ class CarpetOfFlowersEffect extends ManaEffect { mana.setWhite(count); break; case "Colorless": - mana.setColorless(count); + mana.setGeneric(count); break; } checkToFirePossibleEvents(mana, game, source); diff --git a/Mage.Sets/src/mage/sets/urzassaga/Fluctuator.java b/Mage.Sets/src/mage/sets/urzassaga/Fluctuator.java index 11c4d3241d6..ce605ee1fe1 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/Fluctuator.java +++ b/Mage.Sets/src/mage/sets/urzassaga/Fluctuator.java @@ -97,7 +97,7 @@ class FluctuatorEffect extends CostModificationEffectImpl { Player controller = game.getPlayer(abilityToModify.getControllerId()); if (controller != null) { Mana mana = abilityToModify.getManaCostsToPay().getMana(); - int reduceMax = mana.getColorless(); + int reduceMax = mana.getGeneric(); if (reduceMax > 2) { reduceMax = 2; } diff --git a/Mage.Sets/src/mage/sets/urzassaga/LurkingEvil.java b/Mage.Sets/src/mage/sets/urzassaga/LurkingEvil.java index ce966c161d2..a8b38dc6b45 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/LurkingEvil.java +++ b/Mage.Sets/src/mage/sets/urzassaga/LurkingEvil.java @@ -31,6 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; @@ -87,7 +88,7 @@ class LurkingEvilCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { int currentLife = controller.getLife(); diff --git a/Mage.Sets/src/mage/sets/urzassaga/SneakAttack.java b/Mage.Sets/src/mage/sets/urzassaga/SneakAttack.java index 4cb45d7a1fc..ac062bc46ce 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/SneakAttack.java +++ b/Mage.Sets/src/mage/sets/urzassaga/SneakAttack.java @@ -113,10 +113,7 @@ class SneakAttackEffect extends OneShotEffect { SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice " + card.getName(), source.getControllerId()); sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } return true; } diff --git a/Mage.Sets/src/mage/sets/urzassaga/WitchEngine.java b/Mage.Sets/src/mage/sets/urzassaga/WitchEngine.java index 71092fd879f..8abe0533630 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/WitchEngine.java +++ b/Mage.Sets/src/mage/sets/urzassaga/WitchEngine.java @@ -65,7 +65,7 @@ public class WitchEngine extends CardImpl { this.addAbility(new SwampwalkAbility()); // {tap}: Add {B}{B}{B}{B} to your mana pool. Target opponent gains control of Witch Engine. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BasicManaEffect(new Mana(0, 0, 0, 0, 4, 0, 0)), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BasicManaEffect(new Mana(0, 0, 0, 0, 4, 0, 0, 0)), new TapSourceCost()); ability.addEffect(new WitchEngineEffect()); ability.addTarget(new TargetOpponent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/urzassaga/WornPowerstone.java b/Mage.Sets/src/mage/sets/urzassaga/WornPowerstone.java index 61f70e0a12f..bec1cb10146 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/WornPowerstone.java +++ b/Mage.Sets/src/mage/sets/urzassaga/WornPowerstone.java @@ -25,17 +25,16 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.urzassaga; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.Mana; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.effects.common.BasicManaEffect; import mage.abilities.mana.BasicManaAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; /** * @@ -43,14 +42,14 @@ import mage.cards.CardImpl; */ public class WornPowerstone extends CardImpl { - public WornPowerstone (UUID ownerId) { + public WornPowerstone(UUID ownerId) { super(ownerId, 318, "Worn Powerstone", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT}, "{3}"); this.expansionSetCode = "USG"; this.addAbility(new EntersBattlefieldTappedAbility()); this.addAbility(new WornPowerstoneAbility()); } - public WornPowerstone (final WornPowerstone card) { + public WornPowerstone(final WornPowerstone card) { super(card); } @@ -64,7 +63,7 @@ class WornPowerstoneAbility extends BasicManaAbility { public WornPowerstoneAbility() { super(new BasicManaEffect(Mana.ColorlessMana(2))); - this.netMana.add(new Mana(0,0,0,0,0,2,0)); + this.netMana.add(new Mana(0, 0, 0, 0, 0, 0, 0, 2)); } public WornPowerstoneAbility(final WornPowerstoneAbility ability) { @@ -75,4 +74,4 @@ class WornPowerstoneAbility extends BasicManaAbility { public WornPowerstoneAbility copy() { return new WornPowerstoneAbility(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/venservskoth/GalepowderMage.java b/Mage.Sets/src/mage/sets/venservskoth/GalepowderMage.java index 7305b139aa9..4609cd103aa 100644 --- a/Mage.Sets/src/mage/sets/venservskoth/GalepowderMage.java +++ b/Mage.Sets/src/mage/sets/venservskoth/GalepowderMage.java @@ -33,8 +33,9 @@ import mage.MageObject; import mage.abilities.Ability; 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.ReturnFromExileEffect; +import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.Card; import mage.cards.CardImpl; @@ -48,6 +49,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; /** * @@ -56,11 +58,11 @@ import mage.target.common.TargetCreaturePermanent; public class GalepowderMage extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); - + static { filter.add(new AnotherPredicate()); } - + public GalepowderMage(UUID ownerId) { super(ownerId, 12, "Galepowder Mage", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.expansionSetCode = "DDI"; @@ -74,7 +76,7 @@ public 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 GalepowderMageEffect(), false); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); } @@ -116,17 +118,16 @@ class GalepowderMageEffect extends OneShotEffect { UUID exileId = UUID.randomUUID(); if (controller.moveCardToExileWithInfo(permanent, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true)) { if (card != null) { - AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnFromExileEffect(exileId, Zone.BATTLEFIELD)); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(card.getOwnerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(); + effect.setTargetPointer(new FixedTarget(card.getId(), game.getState().getZoneChangeCounter(card.getId()))); + AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); + game.addDelayedTriggeredAbility(delayedAbility, source); } } } - } + } return true; - } + } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/vintagemasters/DecreeOfJustice.java b/Mage.Sets/src/mage/sets/vintagemasters/DecreeOfJustice.java index 241c2d5b492..911d21180c9 100644 --- a/Mage.Sets/src/mage/sets/vintagemasters/DecreeOfJustice.java +++ b/Mage.Sets/src/mage/sets/vintagemasters/DecreeOfJustice.java @@ -103,7 +103,7 @@ class DecreeOfJusticeCycleEffect extends OneShotEffect { if (player != null) { int costX = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); cost.add(new GenericManaCost(costX)); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { Token token = new SoldierToken(); token.putOntoBattlefield(costX, game, source.getSourceId(), source.getControllerId()); } diff --git a/Mage.Sets/src/mage/sets/vintagemasters/LakeOfTheDead.java b/Mage.Sets/src/mage/sets/vintagemasters/LakeOfTheDead.java index e82d34e10a0..948485ae038 100644 --- a/Mage.Sets/src/mage/sets/vintagemasters/LakeOfTheDead.java +++ b/Mage.Sets/src/mage/sets/vintagemasters/LakeOfTheDead.java @@ -67,7 +67,7 @@ public class LakeOfTheDead extends CardImpl { this.addAbility(new BlackManaAbility()); // {tap}, Sacrifice a Swamp: Add {B}{B}{B}{B} to your mana pool. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 0, 4, 0, 0), new TapSourceCost()); + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 0, 4, 0, 0, 0), new TapSourceCost()); ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/vintagemasters/ManaDrain.java b/Mage.Sets/src/mage/sets/vintagemasters/ManaDrain.java index ccf352688be..65ebc145d5d 100644 --- a/Mage.Sets/src/mage/sets/vintagemasters/ManaDrain.java +++ b/Mage.Sets/src/mage/sets/vintagemasters/ManaDrain.java @@ -55,10 +55,9 @@ public class ManaDrain extends CardImpl { super(ownerId, 78, "Mana Drain", Rarity.MYTHIC, new CardType[]{CardType.INSTANT}, "{U}{U}"); this.expansionSetCode = "VMA"; - // Counter target spell. At the beginning of your next main phase, add X mana of {C} to your mana pool, where X is that spell's converted mana cost. this.getSpellAbility().addTarget(new TargetSpell()); - this.getSpellAbility().addEffect(new ManaDrainCounterEffect()); + this.getSpellAbility().addEffect(new ManaDrainCounterEffect()); } public ManaDrain(final ManaDrain card) { @@ -94,14 +93,11 @@ class ManaDrainCounterEffect extends OneShotEffect { game.getStack().counter(getTargetPointer().getFirst(game, source), source.getSourceId(), game); // mana gets added also if counter is not successful int cmc = spell.getConvertedManaCost(); - Effect effect = new AddManaToManaPoolTargetControllerEffect(new Mana(0,0,0,0,0,cmc,0), "your"); + Effect effect = new AddManaToManaPoolTargetControllerEffect(new Mana(0, 0, 0, 0, 0, 0, 0, cmc), "your"); effect.setTargetPointer(new FixedTarget(source.getControllerId())); - AtTheBeginOfMainPhaseDelayedTriggeredAbility delayedAbility = - new AtTheBeginOfMainPhaseDelayedTriggeredAbility(effect, false, TargetController.YOU, PhaseSelection.NEXT_MAIN); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + AtTheBeginOfMainPhaseDelayedTriggeredAbility delayedAbility + = new AtTheBeginOfMainPhaseDelayedTriggeredAbility(effect, false, TargetController.YOU, PhaseSelection.NEXT_MAIN); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/vintagemasters/MarchesaTheBlackRose.java b/Mage.Sets/src/mage/sets/vintagemasters/MarchesaTheBlackRose.java index d8b586092a9..22437add325 100644 --- a/Mage.Sets/src/mage/sets/vintagemasters/MarchesaTheBlackRose.java +++ b/Mage.Sets/src/mage/sets/vintagemasters/MarchesaTheBlackRose.java @@ -160,11 +160,8 @@ class MarchesaTheBlackRoseEffect extends OneShotEffect { Effect effect = new ReturnToBattlefieldUnderYourControlTargetEffect(); effect.setText("return that card to the battlefield under your control at the beginning of the next end step"); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); delayedAbility.getEffects().get(0).setTargetPointer(getTargetPointer()); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/vintagemasters/SelvalaExplorerReturned.java b/Mage.Sets/src/mage/sets/vintagemasters/SelvalaExplorerReturned.java index 3a88cb54f45..462eaa3cd81 100644 --- a/Mage.Sets/src/mage/sets/vintagemasters/SelvalaExplorerReturned.java +++ b/Mage.Sets/src/mage/sets/vintagemasters/SelvalaExplorerReturned.java @@ -102,7 +102,7 @@ class SelvalaExplorerReturnedEffect extends OneShotEffect { if (controller != null) { int parley = ParleyCount.getInstance().calculate(game, source, this); if (parley > 0) { - controller.getManaPool().addMana(new Mana(0, parley, 0, 0, 0, 0, 0), game, source); + controller.getManaPool().addMana(new Mana(0, parley, 0, 0, 0, 0, 0, 0), game, source); controller.gainLife(parley, game); } return true; diff --git a/Mage.Sets/src/mage/sets/vintagemasters/SuChi.java b/Mage.Sets/src/mage/sets/vintagemasters/SuChi.java index c3e1d638995..655667845bd 100644 --- a/Mage.Sets/src/mage/sets/vintagemasters/SuChi.java +++ b/Mage.Sets/src/mage/sets/vintagemasters/SuChi.java @@ -39,7 +39,7 @@ import mage.constants.Rarity; /** * * @author LoneFox - + * */ public class SuChi extends CardImpl { @@ -51,7 +51,7 @@ public class SuChi extends CardImpl { this.toughness = new MageInt(4); // When Su-Chi dies, add {C}{C}{C}{C} to your mana pool. - this.addAbility(new DiesTriggeredAbility(new BasicManaEffect(new Mana(0, 0, 0, 0, 0, 4, 0)), false)); + this.addAbility(new DiesTriggeredAbility(new BasicManaEffect(new Mana(0, 0, 0, 0, 0, 0, 0, 4)), false)); } public SuChi(final SuChi card) { diff --git a/Mage.Sets/src/mage/sets/vintagemasters/ThopterSquadron.java b/Mage.Sets/src/mage/sets/vintagemasters/ThopterSquadron.java index 24ec01d3920..edb41cb1cc4 100644 --- a/Mage.Sets/src/mage/sets/vintagemasters/ThopterSquadron.java +++ b/Mage.Sets/src/mage/sets/vintagemasters/ThopterSquadron.java @@ -32,7 +32,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.RemoveCountersSourceCost; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.GenericManaCost; @@ -77,7 +76,7 @@ public class ThopterSquadron extends CardImpl { this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(3)), "with three +1/+1 counters on it")); // {1}, Remove a +1/+1 counter from Thopter Squadron: Put a 1/1 colorless Thopter artifact creature token with flying onto the battlefield. Activate this ability only any time you could cast a sorcery. - Ability firstAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new ThopterColorlessToken(), 1), new GenericManaCost(1)); + Ability firstAbility = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new ThopterColorlessToken(), 1), new GenericManaCost(1)); firstAbility.addCost(new RemoveCountersSourceCost(CounterType.P1P1.createInstance(1))); this.addAbility(firstAbility); diff --git a/Mage.Sets/src/mage/sets/weatherlight/LlanowarSentinel.java b/Mage.Sets/src/mage/sets/weatherlight/LlanowarSentinel.java index bf5a00bb21f..f297f59dab6 100644 --- a/Mage.Sets/src/mage/sets/weatherlight/LlanowarSentinel.java +++ b/Mage.Sets/src/mage/sets/weatherlight/LlanowarSentinel.java @@ -94,7 +94,7 @@ class LlanowarSentinelEffect extends OneShotEffect { if(player != null) { if(player.chooseUse(Outcome.BoostCreature, "Do you want to to pay {1}{G}?", source, game)) { Cost cost = new ManaCostsImpl("{1}{G}"); - if(cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if(cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { FilterCard filter = new FilterCard("card named Llanowar Sentinel"); filter.add(new NamePredicate("Llanowar Sentinel")); new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(0, 1, filter), false, true).apply(game, source); diff --git a/Mage.Sets/src/mage/sets/weatherlight/PsychicVortex.java b/Mage.Sets/src/mage/sets/weatherlight/PsychicVortex.java index b829bd3c80d..642d090f0b0 100644 --- a/Mage.Sets/src/mage/sets/weatherlight/PsychicVortex.java +++ b/Mage.Sets/src/mage/sets/weatherlight/PsychicVortex.java @@ -30,6 +30,7 @@ package mage.sets.weatherlight; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.common.SacrificeTargetEffect; @@ -85,7 +86,7 @@ class PsychicVortexCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { controller.drawCards(1, game); diff --git a/Mage.Sets/src/mage/sets/weatherlight/SpinningDarkness.java b/Mage.Sets/src/mage/sets/weatherlight/SpinningDarkness.java index 97623904f4a..3adbb45eb8b 100644 --- a/Mage.Sets/src/mage/sets/weatherlight/SpinningDarkness.java +++ b/Mage.Sets/src/mage/sets/weatherlight/SpinningDarkness.java @@ -33,6 +33,7 @@ import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.costs.AlternativeCostSourceAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.GainLifeEffect; @@ -101,7 +102,7 @@ class SpinningDarknessCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { Set blackCardsInGraveyard = controller.getGraveyard().getCards(filter, game); diff --git a/Mage.Sets/src/mage/sets/weatherlight/Tariff.java b/Mage.Sets/src/mage/sets/weatherlight/Tariff.java index f3ec4cd4178..12aa0150277 100644 --- a/Mage.Sets/src/mage/sets/weatherlight/Tariff.java +++ b/Mage.Sets/src/mage/sets/weatherlight/Tariff.java @@ -118,7 +118,7 @@ class TariffEffect extends OneShotEffect { String message = new StringBuilder("Pay ").append(manaCost.getText()).append(" (otherwise sacrifice ") .append(creatureToPayFor.getName()).append(")?").toString(); if (player.chooseUse(Outcome.Benefit, message, source, game)) { - if (manaCost.pay(source, game, source.getSourceId(), player.getId(), false)) { + if (manaCost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { game.informPlayers(new StringBuilder(sourceObject != null ? sourceObject.getName() : "") .append(": ").append(player.getLogName()).append(" has paid").toString()); return; diff --git a/Mage.Sets/src/mage/sets/worldwake/FeralContest.java b/Mage.Sets/src/mage/sets/worldwake/FeralContest.java index b519cab6c9c..2ff3ec2b193 100644 --- a/Mage.Sets/src/mage/sets/worldwake/FeralContest.java +++ b/Mage.Sets/src/mage/sets/worldwake/FeralContest.java @@ -37,6 +37,8 @@ import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.CardImpl; import mage.constants.Duration; import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; @@ -54,10 +56,18 @@ public class FeralContest extends CardImpl { // Put a +1/+1 counter on target creature you control. this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); - this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + + TargetControlledCreaturePermanent target1 = new TargetControlledCreaturePermanent(); + target1.setTargetTag(1); + this.getSpellAbility().addTarget(target1); + // Another target creature blocks it this turn if able. this.getSpellAbility().addEffect(new FeralContestEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + 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); } public FeralContest(final FeralContest card) { diff --git a/Mage.Sets/src/mage/sets/worldwake/Groundswell.java b/Mage.Sets/src/mage/sets/worldwake/Groundswell.java index fdcb5411d82..d6c14a8ff68 100644 --- a/Mage.Sets/src/mage/sets/worldwake/Groundswell.java +++ b/Mage.Sets/src/mage/sets/worldwake/Groundswell.java @@ -50,13 +50,13 @@ public class Groundswell extends CardImpl { this.expansionSetCode = "WWK"; // Target creature gets +2/+2 until end of turn. - //Landfall - If you had a land enter the battlefield under your control this turn, that creature gets +4/+4 until end of turn instead. + // Landfall - If you had a land enter the battlefield under your control this turn, that creature gets +4/+4 until end of turn instead. this.getSpellAbility().addWatcher(new LandfallWatcher()); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new AddContinuousEffectToGame(new BoostTargetEffect(4, 4, Duration.EndOfTurn)), new AddContinuousEffectToGame(new BoostTargetEffect(2, 2, Duration.EndOfTurn)), LandfallCondition.getInstance(), - "Target creature gets +2/+2 until end of turn.
Landfall — If you had a land enter the battlefield under your control this turn, that creature gets +4/44 until end of turn instead")); + "Target creature gets +2/+2 until end of turn.
Landfall — If you had a land enter the battlefield under your control this turn, that creature gets +4/+4 until end of turn instead")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/sets/worldwake/HarabazDruid.java b/Mage.Sets/src/mage/sets/worldwake/HarabazDruid.java index b6eaca60c4d..106f713fac5 100644 --- a/Mage.Sets/src/mage/sets/worldwake/HarabazDruid.java +++ b/Mage.Sets/src/mage/sets/worldwake/HarabazDruid.java @@ -61,7 +61,7 @@ public class HarabazDruid extends CardImpl { this.toughness = new MageInt(1); // {T}: Add X mana of any one color to your mana pool, where X is the number of Allies you control. - this.addAbility(new DynamicManaAbility(new Mana(0,0,0,0,0,0,1), new PermanentsOnBattlefieldCount(filter), new TapSourceCost(), + this.addAbility(new DynamicManaAbility(new Mana(0,0,0,0,0,0,1, 0), new PermanentsOnBattlefieldCount(filter), new TapSourceCost(), "Add X mana of any one color to your mana pool, where X is the number of Allies you control", true)); } diff --git a/Mage.Sets/src/mage/sets/worldwake/KazuulTyrantOfTheCliffs.java b/Mage.Sets/src/mage/sets/worldwake/KazuulTyrantOfTheCliffs.java index 347d2cc3cda..f3c5515c266 100644 --- a/Mage.Sets/src/mage/sets/worldwake/KazuulTyrantOfTheCliffs.java +++ b/Mage.Sets/src/mage/sets/worldwake/KazuulTyrantOfTheCliffs.java @@ -135,7 +135,7 @@ class KazuulTyrantOfTheCliffsEffect extends OneShotEffect { Player payee = game.getPlayer(targetPointer.getFirst(game, source)); if (payee != null) { cost.clearPaid(); - if (!cost.pay(source, game, source.getSourceId(), payee.getId(), false)) { + if (!cost.pay(source, game, source.getSourceId(), payee.getId(), false, null)) { return token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId()); } } diff --git a/Mage.Sets/src/mage/sets/worldwake/NaturesClaim.java b/Mage.Sets/src/mage/sets/worldwake/NaturesClaim.java index 8bfc053fdf2..557127a10d3 100644 --- a/Mage.Sets/src/mage/sets/worldwake/NaturesClaim.java +++ b/Mage.Sets/src/mage/sets/worldwake/NaturesClaim.java @@ -28,14 +28,13 @@ package mage.sets.worldwake; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.Rarity; import mage.filter.common.FilterArtifactOrEnchantmentPermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -48,7 +47,7 @@ import mage.target.TargetPermanent; */ public class NaturesClaim extends CardImpl { - public NaturesClaim (UUID ownerId) { + public NaturesClaim(UUID ownerId) { super(ownerId, 108, "Nature's Claim", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{G}"); this.expansionSetCode = "WWK"; @@ -58,7 +57,7 @@ public class NaturesClaim extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent(new FilterArtifactOrEnchantmentPermanent())); } - public NaturesClaim (final NaturesClaim card) { + public NaturesClaim(final NaturesClaim card) { super(card); } @@ -69,6 +68,7 @@ public class NaturesClaim extends CardImpl { } class NaturesClaimEffect extends OneShotEffect { + NaturesClaimEffect() { super(Outcome.GainLife); staticText = "Its controller gains 4 life"; @@ -80,7 +80,7 @@ class NaturesClaimEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent target = (Permanent) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.BATTLEFIELD); + Permanent target = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); if (target != null) { Player player = game.getPlayer(target.getControllerId()); if (player != null) { @@ -95,4 +95,4 @@ class NaturesClaimEffect extends OneShotEffect { public NaturesClaimEffect copy() { return new NaturesClaimEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/worldwake/NemesisTrap.java b/Mage.Sets/src/mage/sets/worldwake/NemesisTrap.java index 95b7dead30f..ef568466434 100644 --- a/Mage.Sets/src/mage/sets/worldwake/NemesisTrap.java +++ b/Mage.Sets/src/mage/sets/worldwake/NemesisTrap.java @@ -120,10 +120,7 @@ class NemesisTrapEffect extends OneShotEffect { Effect exileEffect = new ExileTargetEffect("Exile " + addedToken.getName() + " at the beginning of the next end step"); exileEffect.setTargetPointer(new FixedTarget(addedToken, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } return true; } diff --git a/Mage.Sets/src/mage/sets/worldwake/RazorBoomerang.java b/Mage.Sets/src/mage/sets/worldwake/RazorBoomerang.java index e91f89c492d..3d40df4d009 100644 --- a/Mage.Sets/src/mage/sets/worldwake/RazorBoomerang.java +++ b/Mage.Sets/src/mage/sets/worldwake/RazorBoomerang.java @@ -33,6 +33,7 @@ import mage.constants.*; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; @@ -91,7 +92,7 @@ class UnattachCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { Permanent attachment = game.getPermanent(attachmentid); diff --git a/Mage.Sets/src/mage/sets/worldwake/StoneIdolTrap.java b/Mage.Sets/src/mage/sets/worldwake/StoneIdolTrap.java index d6f1d3c7394..2c0d532f81e 100644 --- a/Mage.Sets/src/mage/sets/worldwake/StoneIdolTrap.java +++ b/Mage.Sets/src/mage/sets/worldwake/StoneIdolTrap.java @@ -27,27 +27,32 @@ */ package mage.sets.worldwake; -import mage.constants.*; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.CostModificationType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AttackingPredicate; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.game.permanent.token.Token; import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; -import java.util.UUID; -import mage.game.permanent.Permanent; - /** * * @author jeffwadsworth @@ -141,7 +146,7 @@ class StoneIdolTrapEffect extends OneShotEffect { if (tokenPermanent != null) { ExileTargetEffect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); - game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect), source); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone.ALL, exileEffect, TargetController.YOU), source); } } return true; diff --git a/Mage.Sets/src/mage/sets/worldwake/TectonicEdge.java b/Mage.Sets/src/mage/sets/worldwake/TectonicEdge.java index a25944f4cb8..f2f015fbfc4 100644 --- a/Mage.Sets/src/mage/sets/worldwake/TectonicEdge.java +++ b/Mage.Sets/src/mage/sets/worldwake/TectonicEdge.java @@ -32,6 +32,7 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.common.OpponentControlsPermanentCondition; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; @@ -112,7 +113,7 @@ class TectonicEdgeCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { this.paid = true; return paid; } diff --git a/Mage.Sets/src/mage/sets/worldwake/VastwoodAnimist.java b/Mage.Sets/src/mage/sets/worldwake/VastwoodAnimist.java index 02a22a0f7e8..f8c4eaf5941 100644 --- a/Mage.Sets/src/mage/sets/worldwake/VastwoodAnimist.java +++ b/Mage.Sets/src/mage/sets/worldwake/VastwoodAnimist.java @@ -49,16 +49,12 @@ import mage.game.Game; import mage.game.permanent.token.Token; import mage.target.common.TargetControlledPermanent; - - /** * * @author jeffwadsworth */ public class VastwoodAnimist extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledLandPermanent(); - public VastwoodAnimist(UUID ownerId) { super(ownerId, 116, "Vastwood Animist", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.expansionSetCode = "WWK"; @@ -71,7 +67,7 @@ public class VastwoodAnimist extends CardImpl { // {tap}: Target land you control becomes an X/X Elemental creature until end of turn, where X is the number of Allies you control. It's still a land. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new VastwoodAnimistEffect(), new TapSourceCost()); - ability.addTarget(new TargetControlledPermanent(filter)); + ability.addTarget(new TargetControlledPermanent(new FilterControlledLandPermanent())); this.addAbility(ability); } @@ -88,6 +84,7 @@ public class VastwoodAnimist extends CardImpl { class VastwoodAnimistEffect extends OneShotEffect { final static FilterControlledPermanent filterAllies = new FilterControlledPermanent("allies you control"); + static { filterAllies.add(new SubtypePredicate("Ally")); } @@ -118,7 +115,6 @@ class VastwoodAnimistEffect extends OneShotEffect { class VastwoodAnimistElementalToken extends Token { - VastwoodAnimistElementalToken(int amount) { super("", "X/X Elemental creature, where X is the number of Allies you control"); cardType.add(CardType.CREATURE); diff --git a/Mage.Sets/src/mage/sets/zendikar/BlazingTorch.java b/Mage.Sets/src/mage/sets/zendikar/BlazingTorch.java index b385513addd..261236404a4 100644 --- a/Mage.Sets/src/mage/sets/zendikar/BlazingTorch.java +++ b/Mage.Sets/src/mage/sets/zendikar/BlazingTorch.java @@ -38,6 +38,7 @@ import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; @@ -128,7 +129,7 @@ class BlazingTorchCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(ability.getSourceId()); List attachments = permanent.getAttachments(); for (UUID attachmentId : attachments) { diff --git a/Mage.Sets/src/mage/sets/zendikar/BraveTheElements.java b/Mage.Sets/src/mage/sets/zendikar/BraveTheElements.java index caf72def1f8..4c8f74c770a 100644 --- a/Mage.Sets/src/mage/sets/zendikar/BraveTheElements.java +++ b/Mage.Sets/src/mage/sets/zendikar/BraveTheElements.java @@ -31,23 +31,13 @@ package mage.sets.zendikar; import java.util.UUID; import mage.MageObject; import mage.ObjectColor; -import mage.abilities.Ability; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.continuous.GainAbilityAllEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.keyword.ProtectionAbility; +import mage.abilities.effects.common.continuous.GainProtectionFromColorAllEffect; import mage.cards.CardImpl; -import mage.choices.ChoiceColor; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Outcome; import mage.constants.Rarity; -import mage.filter.FilterCard; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; -import mage.game.Game; -import mage.players.Player; /** * @@ -55,13 +45,19 @@ import mage.players.Player; */ public class BraveTheElements extends CardImpl { + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("White creatures you control"); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + } + public BraveTheElements(UUID ownerId) { super(ownerId, 4, "Brave the Elements", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{W}"); this.expansionSetCode = "ZEN"; // Choose a color. White creatures you control gain protection from the chosen color until end of turn. - this.getSpellAbility().addEffect(new BraveTheElementsChooseColorEffect()); + this.getSpellAbility().addEffect(new GainProtectionFromColorAllEffect(Duration.EndOfTurn, filter)); } public BraveTheElements(final BraveTheElements card) { @@ -74,53 +70,3 @@ public class BraveTheElements extends CardImpl { } } - - -class BraveTheElementsChooseColorEffect extends OneShotEffect { - - private static final FilterControlledCreaturePermanent filter1 = new FilterControlledCreaturePermanent(); - - static { - filter1.add(new ColorPredicate(ObjectColor.WHITE)); - } - - public BraveTheElementsChooseColorEffect() { - super(Outcome.Benefit); - this.staticText = "Choose a color. White creatures you control gain protection from the chosen color until end of turn"; - } - - public BraveTheElementsChooseColorEffect(final BraveTheElementsChooseColorEffect effect) { - super(effect); - } - - @Override - public BraveTheElementsChooseColorEffect copy() { - return new BraveTheElementsChooseColorEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (sourceObject != null && controller != null) { - ChoiceColor choice = new ChoiceColor(); - while (!choice.isChosen()) { - controller.choose(outcome, choice, game); - if (!controller.canRespond()) { - return false; - } - } - if (choice.getColor() == null) { - return false; - } - game.informPlayers(sourceObject.getName() + ": " + controller.getLogName() + " has chosen " + choice.getChoice()); - FilterCard filterColor = new FilterCard(); - filterColor.add(new ColorPredicate(choice.getColor())); - filterColor.setMessage(choice.getChoice()); - ContinuousEffect effect = new GainAbilityAllEffect(new ProtectionAbility(new FilterCard(filterColor)), Duration.EndOfTurn, filter1); - game.addEffect(effect, source); - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/sets/zendikar/DesecratedEarth.java b/Mage.Sets/src/mage/sets/zendikar/DesecratedEarth.java index c54ec7de6b3..2ca94151695 100644 --- a/Mage.Sets/src/mage/sets/zendikar/DesecratedEarth.java +++ b/Mage.Sets/src/mage/sets/zendikar/DesecratedEarth.java @@ -28,14 +28,13 @@ package mage.sets.zendikar; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -51,7 +50,6 @@ public class DesecratedEarth extends CardImpl { super(ownerId, 86, "Desecrated Earth", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{4}{B}"); this.expansionSetCode = "ZEN"; - // Destroy target land. Its controller discards a card. this.getSpellAbility().addTarget(new TargetLandPermanent()); this.getSpellAbility().addEffect(new DestroyTargetEffect()); @@ -87,11 +85,11 @@ class DesecratedEarthEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) game.getLastKnownInformation(source.getFirstTarget(), Zone.BATTLEFIELD); + Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); if (permanent != null) { Player player = game.getPlayer(permanent.getControllerId()); if (player != null) { - player.discard(1, source, game); + player.discard(1, false, source, game); return true; } } diff --git a/Mage.Sets/src/mage/sets/zendikar/Electropotence.java b/Mage.Sets/src/mage/sets/zendikar/Electropotence.java index ce2b9795af4..59e0d09ee16 100644 --- a/Mage.Sets/src/mage/sets/zendikar/Electropotence.java +++ b/Mage.Sets/src/mage/sets/zendikar/Electropotence.java @@ -133,7 +133,7 @@ class ElectropotenceEffect extends OneShotEffect { if (controller.chooseUse(Outcome.Damage, "Pay {2}{R} to do the damage?", source, game)) { // if (controller.chooseUse(Outcome.Damage, "Pay {2}{R}? If you do, " + creature.getName() + " deals damage equal to its power to target creature or player.", game)) { ManaCosts manaCosts = new ManaCostsImpl("{2}{R}"); - if (manaCosts.pay(source, game, source.getSourceId(), controller.getId(), false)) { + if (manaCosts.pay(source, game, source.getSourceId(), controller.getId(), false, null)) { int amount = creature.getPower().getValue(); UUID target = source.getTargets().getFirstTarget(); Permanent targetCreature = game.getPermanent(target); diff --git a/Mage.Sets/src/mage/sets/zendikar/FeastOfBlood.java b/Mage.Sets/src/mage/sets/zendikar/FeastOfBlood.java index 24dabbcc7ec..6bbfbecfd47 100644 --- a/Mage.Sets/src/mage/sets/zendikar/FeastOfBlood.java +++ b/Mage.Sets/src/mage/sets/zendikar/FeastOfBlood.java @@ -31,6 +31,7 @@ import java.util.UUID; import mage.constants.CardType; import mage.constants.Rarity; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.GainLifeEffect; @@ -91,7 +92,7 @@ class FeastOfBloodCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { this.paid = true; return paid; } diff --git a/Mage.Sets/src/mage/sets/zendikar/HellkiteCharger.java b/Mage.Sets/src/mage/sets/zendikar/HellkiteCharger.java index 9586ec1a36c..da0d62db16a 100644 --- a/Mage.Sets/src/mage/sets/zendikar/HellkiteCharger.java +++ b/Mage.Sets/src/mage/sets/zendikar/HellkiteCharger.java @@ -99,7 +99,7 @@ class HellkiteChargerEffect extends OneShotEffect { ManaCosts cost = new ManaCostsImpl("{5}{R}{R}"); if (player.chooseUse(Outcome.Damage, "Pay " + cost.getText() + "?", source, game)) { cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { new UntapAllControllerEffect(new FilterAttackingCreature(),"").apply(game, source); game.getState().getTurnMods().add(new TurnMod(source.getControllerId(), TurnPhase.COMBAT, null, false)); return true; diff --git a/Mage.Sets/src/mage/sets/zendikar/KabiraEvangel.java b/Mage.Sets/src/mage/sets/zendikar/KabiraEvangel.java index b2d00f04395..d686cc470de 100644 --- a/Mage.Sets/src/mage/sets/zendikar/KabiraEvangel.java +++ b/Mage.Sets/src/mage/sets/zendikar/KabiraEvangel.java @@ -29,31 +29,19 @@ package mage.sets.zendikar; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.continuous.GainAbilityAllEffect; -import mage.abilities.keyword.ProtectionAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.GainProtectionFromColorAllEffect; import mage.cards.CardImpl; -import mage.choices.ChoiceColor; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.TargetController; import mage.constants.Zone; -import mage.filter.FilterCard; import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardIdPredicate; -import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.mageobject.SubtypePredicate; -import mage.filter.predicate.permanent.ControllerPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; /** * @@ -61,6 +49,12 @@ import mage.players.Player; */ public class KabiraEvangel extends CardImpl { + private static final FilterControlledCreaturePermanent filter1 = new FilterControlledCreaturePermanent(); + + static { + filter1.add(new SubtypePredicate("Ally")); + } + public KabiraEvangel(UUID ownerId) { super(ownerId, 15, "Kabira Evangel", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.expansionSetCode = "ZEN"; @@ -71,13 +65,13 @@ public class KabiraEvangel extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(3); - FilterPermanent filter = new FilterPermanent(getName() + " or another Ally"); - filter.add(Predicates.or( - new CardIdPredicate(this.getId()), - new SubtypePredicate("Ally"))); + FilterPermanent filter2 = new FilterPermanent(getName() + " or another Ally"); + filter2.add(Predicates.or(new CardIdPredicate(this.getId()), new SubtypePredicate("Ally"))); // Whenever Kabira Evangel or another Ally enters the battlefield under your control, you may choose a color. If you do, Allies you control gain protection from the chosen color until end of turn. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, new KabiraEvangelChooseColorEffect(), filter, true)); + Effect effect = new GainProtectionFromColorAllEffect(Duration.EndOfTurn, filter1); + effect.setText("choose a color. If you do, Allies you control gain protection from the chosen color until end of turn."); + this.addAbility(new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, effect, filter2, true)); } public KabiraEvangel(final KabiraEvangel card) { @@ -89,55 +83,3 @@ public class KabiraEvangel extends CardImpl { return new KabiraEvangel(this); } } - - - -class KabiraEvangelChooseColorEffect extends OneShotEffect { - - private static final FilterCreaturePermanent filter1 = new FilterCreaturePermanent(); - - static { - filter1.add(new ControllerPredicate(TargetController.YOU)); - filter1.add(new SubtypePredicate("Ally")); - } - - public KabiraEvangelChooseColorEffect() { - super(Outcome.Benefit); - staticText = "choose a color. All Allies you control gain protection from the chosen color until end of turn"; - } - - public KabiraEvangelChooseColorEffect(final KabiraEvangelChooseColorEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Permanent sourceObject = game.getPermanent(source.getSourceId()); - if (sourceObject != null && controller != null) { - ChoiceColor choice = new ChoiceColor(); - while (!choice.isChosen()) { - controller.choose(outcome, choice, game); - if (!controller.canRespond()) { - return false; - } - } - if (choice.getColor() == null) { - return false; - } - game.informPlayers(sourceObject.getName() + ": " + controller.getLogName() + " has chosen " + choice.getChoice()); - FilterCard filterColor = new FilterCard(); - filterColor.add(new ColorPredicate(choice.getColor())); - filterColor.setMessage(choice.getChoice()); - ContinuousEffect effect = new GainAbilityAllEffect(new ProtectionAbility(new FilterCard(filterColor)), Duration.EndOfTurn, filter1); - game.addEffect(effect, source); - return true; - } - return false; - } - - @Override - public KabiraEvangelChooseColorEffect copy() { - return new KabiraEvangelChooseColorEffect(this); - } -} diff --git a/Mage.Sets/src/mage/sets/zendikar/LorthosTheTidemaker.java b/Mage.Sets/src/mage/sets/zendikar/LorthosTheTidemaker.java index d6f4e02af71..098a382196b 100644 --- a/Mage.Sets/src/mage/sets/zendikar/LorthosTheTidemaker.java +++ b/Mage.Sets/src/mage/sets/zendikar/LorthosTheTidemaker.java @@ -104,7 +104,7 @@ class LorthosTheTideMakerEffect extends OneShotEffect { Cost cost = new ManaCostsImpl("{8}"); if (player.chooseUse(Outcome.Tap, "Pay " + cost.getText() + " and " + staticText, source, game)) { cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { for (UUID target : this.targetPointer.getTargets(game, source)) { Permanent permanent = game.getPermanent(target); if (permanent != null) { diff --git a/Mage.Sets/src/mage/sets/zendikar/LuminarchAscension.java b/Mage.Sets/src/mage/sets/zendikar/LuminarchAscension.java index 466a68220af..58989f44685 100644 --- a/Mage.Sets/src/mage/sets/zendikar/LuminarchAscension.java +++ b/Mage.Sets/src/mage/sets/zendikar/LuminarchAscension.java @@ -32,6 +32,7 @@ import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalTriggeredAbility; @@ -128,7 +129,7 @@ class SourceHasCountersCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { this.paid = true; return paid; } diff --git a/Mage.Sets/src/mage/sets/zendikar/SeaGateLoremaster.java b/Mage.Sets/src/mage/sets/zendikar/SeaGateLoremaster.java index 26b0f2830e7..25f6969fac2 100644 --- a/Mage.Sets/src/mage/sets/zendikar/SeaGateLoremaster.java +++ b/Mage.Sets/src/mage/sets/zendikar/SeaGateLoremaster.java @@ -28,15 +28,15 @@ package mage.sets.zendikar; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.SubtypePredicate; @@ -62,6 +62,7 @@ public class SeaGateLoremaster extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(3); + // {T}: Draw a card for each Ally you control. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(new PermanentsOnBattlefieldCount(filter)), new TapSourceCost())); diff --git a/Mage.Stats/pom.xml b/Mage.Stats/pom.xml index 148254290ac..8393d25c828 100644 --- a/Mage.Stats/pom.xml +++ b/Mage.Stats/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.6 + 1.4.8 org.mage diff --git a/Mage.Tests/CommanderDuel_Karador_BGW.dck b/Mage.Tests/CommanderDuel_Karador_BGW.dck new file mode 100644 index 00000000000..e0ea3d96a1d --- /dev/null +++ b/Mage.Tests/CommanderDuel_Karador_BGW.dck @@ -0,0 +1,100 @@ +1 [M15:108] Necromancer's Stockpile +1 [FRF:76] Merciless Executioner +1 [9ED:283] Wood Elves +1 [M11:172] Fauna Shaman +1 [CMD:140] Acidic Slime +1 [PLS:42] Diabolic Intent +1 [AVR:226] Cavern of Souls +1 [TOR:77] Putrid Imp +1 [M15:194] Reclamation Sage +1 [RAV:230] Shambling Shell +1 [ISD:105] Liliana of the Veil +1 [M15:198] Satyr Wayfinder +1 [UDS:115] Pattern of Rebirth +1 [JOU:163] Mana Confluence +1 [ARB:75] Qasali Pridemage +1 [BFZ:250] Plains +1 [ZEN:172] Oracle of Mul Daya +1 [M13:229] Sunpetal Grove +1 [WWK:20] Stoneforge Mystic +1 [8ED:322] City of Brass +1 [ZEN:83] Bloodghast +1 [TSP:104] Dread Return +1 [ICE:278] Swords to Plowshares +1 [USG:230] Acridian +1 [RAV:107] Stinkweed Imp +1 [CON:113] Knight of the Reliquary +1 [AVR:106] Griselbrand +1 [10E:137] Doomed Necromancer +1 [M12:39] Sun Titan +1 [NPH:104] Birthing Pod +1 [M12:165] Birds of Paradise +1 [ORI:245] Caves of Koilos +1 [ZEN:211] Arid Mesa +1 [SOM:72] Necrotic Ooze +1 [M13:83] Bloodthrone Vampire +1 [ZEN:219] Marsh Flats +1 [TMP:340] Wasteland +1 [RAV:81] Dark Confidant +1 [TOR:69] Mesmeric Fiend +1 [RAV:87] Golgari Thug +1 [ISD:15] Fiend Hunter +1 [M15:248] Urborg, Tomb of Yawgmoth +1 [ORI:248] Llanowar Wastes +1 [KTK:248] Windswept Heath +1 [KTK:249] Wooded Foothills +1 [WWK:132] Bojuka Bog +1 [ALL:167] Phyrexian Devourer +1 [EVE:180] Twilight Mire +1 [5DN:86] Eternal Witness +1 [ZEN:220] Misty Rainforest +1 [MOR:22] Reveillark +1 [RAV:167] Golgari Grave-Troll +1 [ZEN:229] Verdant Catacombs +1 [KTK:239] Polluted Delta +1 [10E:349] Brushland +1 [RTR:243] Overgrown Tomb +1 [WWK:144] Stirring Wildwood +1 [C15:281] Command Tower +1 [SCG:59] Carrion Feeder +1 [ISD:249] Woodland Cemetery +1 [RTR:248] Temple Garden +1 [KTK:233] Flooded Strand +1 [ROE:33] Linvala, Keeper of Silence +1 [NPH:9] Elesh Norn, Grand Cenobite +1 [ISD:242] Isolated Chapel +1 [FUT:169] Dakmor Salvage +1 [M15:5] Boonweaver Giant +1 [LRW:248] Gaddock Teeg +1 [KTK:230] Bloodstained Mire +1 [RAV:172] Life from the Loam +1 [M12:188] Primeval Titan +1 [CHK:239] Sakura-Tribe Elder +1 [USG:321] Gaea's Cradle +1 [RTR:213] Deathrite Shaman +1 [USG:322] Phyrexian Tower +1 [BFZ:270] Forest +1 [FUT:174] Dryad Arbor +1 [3ED:297] Savannah +1 [ULG:11] Karmic Guide +1 [3ED:298] Scrubland +1 [UDS:1] Academy Rector +1 [5ED:191] Sylvan Library +1 [M11:218] Triskelion +1 [9ED:54] Weathered Wayfarer +1 [5ED:2] Animate Dead +1 [3ED:13] Demonic Tutor +1 [ARN:84] Bazaar of Baghdad +1 [ISD:122] Unburial Rites +1 [GTC:242] Godless Shrine +1 [ME3:69] Grim Tutor +1 [SHM:110] Devoted Druid +1 [EXO:129] Survival of the Fittest +1 [BFZ:260] Swamp +1 [DST:140] Skullclamp +1 [ALA:202] Tidehollow Sculler +1 [3ED:283] Bayou +1 [10E:361] Treetop Village +1 [TSP:245] Saffi Eriksdotter +1 [M11:120] Viscera Seer +SB: 1 [CMD:207] Karador, Ghost Chieftain diff --git a/Mage.Tests/pom.xml b/Mage.Tests/pom.xml index 5388d7caa1f..279c225f293 100644 --- a/Mage.Tests/pom.xml +++ b/Mage.Tests/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.6 + 1.4.8 mage-tests diff --git a/Mage.Tests/src/test/java/org/mage/test/AI/basic/CastCreaturesTest.java b/Mage.Tests/src/test/java/org/mage/test/AI/basic/CastCreaturesTest.java index 7ec428ccede..ac6ce7fb593 100644 --- a/Mage.Tests/src/test/java/org/mage/test/AI/basic/CastCreaturesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/AI/basic/CastCreaturesTest.java @@ -29,6 +29,7 @@ package org.mage.test.AI.basic; import mage.constants.PhaseStep; import mage.constants.Zone; +import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBaseAI; @@ -57,6 +58,7 @@ public class CastCreaturesTest extends CardTestPlayerBaseAI { * first creature */ @Test + @Ignore // Produces sometime error probably because of wrong mana usage of the AI - Not solved yet public void testSimpleCast2() { addCard(Zone.HAND, playerA, "Silvercoat Lion"); addCard(Zone.HAND, playerA, "Silvercoat Lion"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/AwakenTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/AwakenTest.java index 7f7f21db988..be0b77c7b97 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/AwakenTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/AwakenTest.java @@ -29,6 +29,7 @@ package org.mage.test.cards.abilities.keywords; import mage.constants.PhaseStep; import mage.constants.Zone; +import mage.filter.Filter; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -120,4 +121,31 @@ public class AwakenTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Silvercoat Lion", 1); } + + /** + * Awakened Clutch of Currents returned the targeted land (for awaken) to my + * hand in addition to the targeted creature. + */ + @Test + public void testClutchOfCurrents() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + // Return target creature to its owner's hand. + // Awaken 3—{4}{U} + addCard(Zone.HAND, playerA, "Clutch of Currents", 1); // {U} + + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Clutch of Currents with awaken", "Silvercoat Lion"); + addTarget(playerA, "Island"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Clutch of Currents", 1); + assertHandCount(playerB, "Silvercoat Lion", 1); + assertPermanentCount(playerA, "Island", 5); + assertPowerToughness(playerA, "Island", 3, 3, Filter.ComparisonScope.Any); + + } + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SurgeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SurgeTest.java index 053f5f8492d..171781717c0 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SurgeTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SurgeTest.java @@ -110,4 +110,30 @@ public class SurgeTest extends CardTestPlayerBase { assertLife(playerB, 14); } + @Test + public void testContainmentMembrane() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + // Enchant creature + // Enchanted creature doesn't untap during its controller's untap step. + // Surge {U} (You may cast a spell for its surge cost if you or a teammate have cast another spell in the same turn.) + addCard(Zone.HAND, playerA, "Containment Membrane"); // {2}{U} + addCard(Zone.HAND, playerA, "Lightning Bolt"); + + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1, true); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Containment Membrane", "Silvercoat Lion"); + + setStopAt(2, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertLife(playerB, 17); + assertGraveyardCount(playerA, "Lightning Bolt", 1); + assertPermanentCount(playerA, "Containment Membrane", 1); + + assertTapped("Silvercoat Lion", true); + + } + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/UndyingTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/UndyingTest.java index 058b5e5bed1..61333082f40 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/UndyingTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/UndyingTest.java @@ -228,6 +228,8 @@ public class UndyingTest extends CardTestPlayerBase { // Other non-Human creatures you control get +1/+1 and have undying. addCard(Zone.BATTLEFIELD, playerA, "Mikaeus, the Unhallowed", 1); + // Flying + // Tatterkite can't have counters placed on it. addCard(Zone.BATTLEFIELD, playerA, "Tatterkite", 1); // Artifact Creature - Scarecrow 2/1 castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Tatterkite"); @@ -239,8 +241,33 @@ public class UndyingTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Tatterkite", 1); assertPermanentCount(playerA, "Mikaeus, the Unhallowed", 1); - assertCounterCount("Tatterkite", CounterType.P1P1, 1); - assertPowerToughness(playerA, "Tatterkite", 4, 3); + assertCounterCount("Tatterkite", CounterType.P1P1, 0); + assertPowerToughness(playerA, "Tatterkite", 3, 2); + + } + + @Test + public void testUndyingMikaeusAndTatterkiteSacrifice() { + // Sacrifice a creature: Add {C}{C} to your mana pool. + addCard(Zone.BATTLEFIELD, playerA, "Ashnod's Altar", 1); + // Whenever a Human deals damage to you, destroy it. + // Other non-Human creatures you control get +1/+1 and have undying. + addCard(Zone.BATTLEFIELD, playerA, "Mikaeus, the Unhallowed", 1); + + // Flying + // Tatterkite can't have counters placed on it. + addCard(Zone.BATTLEFIELD, playerA, "Tatterkite", 1); // Artifact Creature - Scarecrow 2/1 + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice a creature"); + setChoice(playerA, "Tatterkite"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Tatterkite", 1); + assertPermanentCount(playerA, "Mikaeus, the Unhallowed", 1); + assertCounterCount("Tatterkite", CounterType.P1P1, 0); + assertPowerToughness(playerA, "Tatterkite", 3, 2); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/destroy/NaturesClaimTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/destroy/NaturesClaimTest.java new file mode 100644 index 00000000000..da4ed60d2a1 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/destroy/NaturesClaimTest.java @@ -0,0 +1,83 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.abilities.oneshot.destroy; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class NaturesClaimTest extends CardTestPlayerBase { + + @Test + public void testTargetDestroyable() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + // Destroy target artifact or enchantment. Its controller gains 4 life. + addCard(Zone.HAND, playerA, "Nature's Claim"); + + // Flying + addCard(Zone.BATTLEFIELD, playerA, "Gold-Forged Sentinel"); // 4/4 + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nature's Claim", "Gold-Forged Sentinel"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Nature's Claim", 1); + + assertGraveyardCount(playerA, "Gold-Forged Sentinel", 1); + assertLife(playerA, 24); + assertLife(playerB, 20); + } + + @Test + public void testTargetUndestroyable() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + // Destroy target artifact or enchantment. Its controller gains 4 life. + addCard(Zone.HAND, playerA, "Nature's Claim"); + + // Flying + // Darksteel Gargoyle is indestructible. ("Destroy" effects and lethal damage don't destroy it.) + addCard(Zone.BATTLEFIELD, playerA, "Darksteel Gargoyle"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nature's Claim", "Darksteel Gargoyle"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Nature's Claim", 1); + + assertPermanentCount(playerA, "Darksteel Gargoyle", 1); + assertLife(playerA, 24); + assertLife(playerB, 20); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/WardenOfTheFirstTreeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/WardenOfTheFirstTreeTest.java new file mode 100644 index 00000000000..5e2058b2c65 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/WardenOfTheFirstTreeTest.java @@ -0,0 +1,123 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.continuous; + +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.filter.Filter; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class WardenOfTheFirstTreeTest extends CardTestPlayerBase { + + @Test + public void testFirstAbility() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 7); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + // {1}{W/B}: Warden of the First Tree becomes a Human Warrior with base power and toughness 3/3. + // {2}{W/B}{W/B}: If Warden of the First Tree is a Warrior, it becomes a Human Spirit Warrior with trample and lifelink. + // {3}{W/B}{W/B}{W/B}: If Warden of the First Tree is a Spirit, put five +1/+1 counters on it. + addCard(Zone.HAND, playerA, "Warden of the First Tree", 2); // {G} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Warden of the First Tree"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{W/B}:"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPowerToughness(playerA, "Warden of the First Tree", 3, 3, Filter.ComparisonScope.Any); + assertType("Warden of the First Tree", CardType.CREATURE, "Human"); + assertType("Warden of the First Tree", CardType.CREATURE, "Warrior"); + assertAbility(playerA, "Warden of the First Tree", TrampleAbility.getInstance(), false); + assertAbility(playerA, "Warden of the First Tree", LifelinkAbility.getInstance(), false); + } + + @Test + public void testSecondAbility() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 7); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + // {1}{W/B}: Warden of the First Tree becomes a Human Warrior with base power and toughness 3/3. + // {2}{W/B}{W/B}: If Warden of the First Tree is a Warrior, it becomes a Human Spirit Warrior with trample and lifelink. + // {3}{W/B}{W/B}{W/B}: If Warden of the First Tree is a Spirit, put five +1/+1 counters on it. + addCard(Zone.HAND, playerA, "Warden of the First Tree", 2); // {G} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Warden of the First Tree"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{W/B}:"); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{2}{W/B}{W/B}:"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPowerToughness(playerA, "Warden of the First Tree", 3, 3, Filter.ComparisonScope.Any); + assertType("Warden of the First Tree", CardType.CREATURE, "Human"); + assertType("Warden of the First Tree", CardType.CREATURE, "Spirit"); + assertType("Warden of the First Tree", CardType.CREATURE, "Warrior"); + assertAbility(playerA, "Warden of the First Tree", TrampleAbility.getInstance(), true); + assertAbility(playerA, "Warden of the First Tree", LifelinkAbility.getInstance(), true); + } + + @Test + public void testThirdAbility() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 7); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + // {1}{W/B}: Warden of the First Tree becomes a Human Warrior with base power and toughness 3/3. + // {2}{W/B}{W/B}: If Warden of the First Tree is a Warrior, it becomes a Human Spirit Warrior with trample and lifelink. + // {3}{W/B}{W/B}{W/B}: If Warden of the First Tree is a Spirit, put five +1/+1 counters on it. + addCard(Zone.HAND, playerA, "Warden of the First Tree", 2); // {G} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Warden of the First Tree"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{W/B}:"); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{2}{W/B}{W/B}:"); + + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}{W/B}{W/B}{W/B}:"); + + setStopAt(3, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPowerToughness(playerA, "Warden of the First Tree", 8, 8, Filter.ComparisonScope.Any); + assertType("Warden of the First Tree", CardType.CREATURE, "Human"); + assertType("Warden of the First Tree", CardType.CREATURE, "Spirit"); + assertType("Warden of the First Tree", CardType.CREATURE, "Warrior"); + assertAbility(playerA, "Warden of the First Tree", TrampleAbility.getInstance(), true); + assertAbility(playerA, "Warden of the First Tree", LifelinkAbility.getInstance(), true); + } + + /** + * When a Warden of the First Tree enters the battlefield, if it is not the + * first warden played during the game, it enters with a random + * power/toughness instead of 1/1. I have had it enter with both 2/2 and + * 4/4, neither of which are actual values the card can hold. + */ +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java b/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java index 13f434621e6..ae2ab5f4d82 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java @@ -148,4 +148,49 @@ public class ExileAndReturnUnderYourControl extends CardTestPlayerBase { } + /** + * I cast a Villainous Wealth in Vintage Cube, and when it came time to cast + * my opponent's cards (Mox Sapphire, Mox Emerald, Brainstorm, Snapcaster + * Mage, Fact or Fiction and a Quicken), it rolled back to before I had cast + * my spell after Quicken resolved. I have the error, but the forums won't + * let me post them. I did find it was replicatable whenever you try to cast + * Quicken off a Villainous Wealth. + */ + @Test + public void testVillainousWealthAndQuicken() { + // Villainous Wealth {X}{B}{G}{U} + // Target opponent exiles the top X cards of his or her library. You may cast any number + // of nonland cards with converted mana cost X or less from among them without paying + // their mana costs. + addCard(Zone.HAND, playerA, "Villainous Wealth"); // {X}{B}{G}{U} + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + + // At the beginning of your draw step, you may draw two additional cards. + // If you do, choose two cards in your hand drawn this turn. + // For each of those cards, pay 4 life or put the card on top of your library. + addCard(Zone.LIBRARY, playerB, "Mox Emerald"); + // The next sorcery card you cast this turn can be cast as though it had flash. + // Draw a card. + addCard(Zone.LIBRARY, playerB, "Quicken"); // Instant - {U} + addCard(Zone.LIBRARY, playerB, "Mox Sapphire"); + skipInitShuffling(); // to keep this card on top of library + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Villainous Wealth", playerB); + setChoice(playerA, "X=3"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mox Emerald"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Quicken"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mox Sapphire"); + + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerA, "Villainous Wealth", 1); + assertExileCount(playerB, 0); + assertPermanentCount(playerA, "Mox Emerald", 1); + assertPermanentCount(playerA, "Mox Sapphire", 1); + assertGraveyardCount(playerB, "Quicken", 1); + + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhyrexianMetamorphTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhyrexianMetamorphTest.java index 1f3ac8a3242..07f84407316 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhyrexianMetamorphTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhyrexianMetamorphTest.java @@ -152,7 +152,7 @@ public class PhyrexianMetamorphTest extends CardTestPlayerBase { /** * If a Harmonic Sliver enters the battlefield the controller has to destroy - * one artifacts or enchantments + * one artifact or enchantment */ @Test public void testHarmonicSliverNative1() { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/SplinterTwinTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/SplinterTwinTest.java new file mode 100644 index 00000000000..c8c45bbd385 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/SplinterTwinTest.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.copy; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class SplinterTwinTest extends CardTestPlayerBase { + + @Test + public void testCopyCreature() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + // Enchant creature + // Enchanted creature has "{T}: Put a token that's a copy of this creature onto the battlefield. That token has haste. Exile it at the beginning of the next end step." + addCard(Zone.HAND, playerA, "Splinter Twin"); // {2}{R}{R} + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); + + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); + addCard(Zone.HAND, playerB, "Lightning Bolt"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Splinter Twin", "Silvercoat Lion"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Put a token"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", "Silvercoat Lion", "{T}: Put a token"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertHandCount(playerB, "Lightning Bolt", 0); + assertGraveyardCount(playerB, "Lightning Bolt", 1); + + assertGraveyardCount(playerA, "Silvercoat Lion", 1); + assertGraveyardCount(playerA, "Splinter Twin", 1); + + assertPermanentCount(playerA, "Silvercoat Lion", 1); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/KaradorGhostChieftainTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/KaradorGhostChieftainTest.java new file mode 100644 index 00000000000..9149006006d --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/KaradorGhostChieftainTest.java @@ -0,0 +1,86 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.cost.modification; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class KaradorGhostChieftainTest extends CardTestPlayerBase { + + @Test + public void castReducedTwo() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 2); + // Karador, Ghost Chieftain costs {1} less to cast for each creature card in your graveyard. + // During each of your turns, you may cast one creature card from your graveyard. + addCard(Zone.HAND, playerA, "Karador, Ghost Chieftain");// {5}{B}{G}{W} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertTappedCount("Island", false, 2); + assertPermanentCount(playerA, "Karador, Ghost Chieftain", 1); + } + + /** + * I had a couple problems in a commander game last night. Using Karador, + * Ghost Chieftain as my commander. Most of the match, his casting cost was + * correctly calculated, reducing the extra commander tax and generic mana + * costs by the number of creature cards in my graveyard. On the 4th cast + * though, the cost was 12 mana total. I tried casting a few times over a + * couple turns, but it was still an incorrect cost (I had probably 15 + * creatures in my graveyard). + */ + @Test + public void castReducedSeven() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 7); + // Karador, Ghost Chieftain costs {1} less to cast for each creature card in your graveyard. + // During each of your turns, you may cast one creature card from your graveyard. + addCard(Zone.HAND, playerA, "Karador, Ghost Chieftain");// {5}{B}{G}{W} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertTappedCount("Island", false, 5); + assertPermanentCount(playerA, "Karador, Ghost Chieftain", 1); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/mana/ConditionalManaTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/mana/ConditionalManaTest.java index 304ed2fdf67..c4f3ad3739d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/mana/ConditionalManaTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/mana/ConditionalManaTest.java @@ -27,6 +27,7 @@ */ package org.mage.test.cards.mana; +import mage.abilities.keyword.FlyingAbility; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; @@ -141,4 +142,91 @@ public class ConditionalManaTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Snapping Drake", 2); } + + /** + * I've found a bit of a problem with colorless costs. I've been unable to + * pay colorless costs with lands conditionally tapping for 2 colorless i.e + * shrine of forsaken gods and eldrazi temple ,including if I float the + * mana. Seperately but on a related note, if you float at least one + * colorless mana you can pay all colorless costs with floated generic mana. + */ + @Test + public void testPayColorlessWithConditionalMana() { + // {T}: Add {C} to your mana pool. + // {T}: Add {C}{C} to your mana pool. Spend this mana only to cast colorless spells. Activate this ability only if you control seven or more lands. + addCard(Zone.BATTLEFIELD, playerA, "Shrine of the Forsaken Gods", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 8); + // When you cast Kozilek, the Great Distortion, if you have fewer than seven cards in hand, draw cards equal to the difference. + // Menace + // Discard a card with converted mana cost X: Counter target spell with converted mana cost X. + addCard(Zone.HAND, playerA, "Kozilek, the Great Distortion", 1); // {8}{C}{C} + + activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {C}{C}"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Kozilek, the Great Distortion"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Kozilek, the Great Distortion", 1); + } + + @Test + public void CultivatorDroneColorlessSpell() { + // Devoid + // {T}: Add {C} to your mana pool. Spend this mana only to cast a colorless spell, activate an ability of a colorless permanent, or pay a cost that contains {C}. + addCard(Zone.BATTLEFIELD, playerA, "Cultivator Drone", 1); + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + // Target creature gets +3/-3 until end of turn. + addCard(Zone.HAND, playerA, "Spatial Contortion", 1); // {1}{C} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Spatial Contortion", "Silvercoat Lion"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Spatial Contortion", 1); + assertGraveyardCount(playerA, "Silvercoat Lion", 1); + } + + @Test + public void CultivatorDroneColorlessAbility() { + // Devoid + // {T}: Add {C} to your mana pool. Spend this mana only to cast a colorless spell, activate an ability of a colorless permanent, or pay a cost that contains {C}. + addCard(Zone.BATTLEFIELD, playerA, "Cultivator Drone", 1); + addCard(Zone.BATTLEFIELD, playerA, "Wastes", 1); + // Untap Endbringer during each other player's untap step. + // {T}: Endbringer deals 1 damage to target creature or player. + // {C}, {T}: Target creature can't attack or block this turn. + // {C}{C}, {T}: Draw a card. + addCard(Zone.BATTLEFIELD, playerA, "Endbringer", 1); // {1}{C} + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{C}{C},"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertHandCount(playerA, 1); + } + + @Test + public void CultivatorDroneColorlessCost() { + // Devoid + // {T}: Add {C} to your mana pool. Spend this mana only to cast a colorless spell, activate an ability of a colorless permanent, or pay a cost that contains {C}. + addCard(Zone.BATTLEFIELD, playerA, "Cultivator Drone", 1); + // Devoid (This card has no color.) + // Flying + // When Gravity Negator attacks, you may pay {C}. If you do, another target creature gains flying until end of turn. ({C} represents colorless mana) + addCard(Zone.BATTLEFIELD, playerA, "Gravity Negator", 1); // 2/3 + + attack(1, playerA, "Gravity Negator"); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertTapped("Gravity Negator", true); + assertAbility(playerA, "Cultivator Drone", FlyingAbility.getInstance(), true); + + assertLife(playerB, 18); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/AjaniTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/AjaniTest.java new file mode 100644 index 00000000000..fa25073a1ad --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/AjaniTest.java @@ -0,0 +1,90 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.planeswalker; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class AjaniTest extends CardTestPlayerBase { + + @Test + public void CastAjani() { + // +1: You gain 2 life. + // -1: Put a +1/+1 counter on each creature you control. Those creatures gain vigilance until end of turn. + // -6: Put a white Avatar creature token onto the battlefield. It has "This creature's power and toughness are each equal to your life total." + addCard(Zone.HAND, playerA, "Ajani Goldmane"); // {2}{W}{W} starts with 4 Loyality counters + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ajani Goldmane"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: You gain 2 life"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Ajani Goldmane", 1); + assertCounterCount("Ajani Goldmane", CounterType.LOYALTY, 5); // 4 + 1 = 5 + + assertLife(playerA, 22); + assertLife(playerB, 20); + } + + @Test + public void CastAjaniWithOathOfGideon() { + // +1: You gain 2 life. + // -1: Put a +1/+1 counter on each creature you control. Those creatures gain vigilance until end of turn. + // -6: Put a white Avatar creature token onto the battlefield. It has "This creature's power and toughness are each equal to your life total." + addCard(Zone.HAND, playerA, "Ajani Goldmane"); // {2}{W}{W} starts with 4 Loyality counters + // When Oath of Gideon enters the battlefield, put two 1/1 Kor Ally creature tokens onto the battlefield. + // Each planeswalker you control enters the battlefield with an additional loyalty counter on it. + addCard(Zone.HAND, playerA, "Oath of Gideon"); // {2}{W} + addCard(Zone.BATTLEFIELD, playerA, "Plains", 7); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Oath of Gideon"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ajani Goldmane"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: You gain 2 life"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Kor Ally", 2); + assertPermanentCount(playerA, "Oath of Gideon", 1); + assertPermanentCount(playerA, "Ajani Goldmane", 1); + assertCounterCount("Ajani Goldmane", CounterType.LOYALTY, 6); // 5 + 1 = 5 + + assertLife(playerA, 22); + assertLife(playerB, 20); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/requirement/BlockRequirementTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/requirement/BlockRequirementTest.java index 6797cdc95a5..3fca8549681 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/requirement/BlockRequirementTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/requirement/BlockRequirementTest.java @@ -112,4 +112,48 @@ public class BlockRequirementTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Bog Wraith", 1); } + /** + * Elemental Uprising - "it must be blocked this turn if able", not working + * + * The bug just happened for me today as well - the problem is "must be + * blocked" is not being enforced correctly. During opponent's main phase he + * casted Elemental Uprising targeting an untapped land. He attacked with + * two creatures, I had one creature to block with, and did not block the + * land-creature targeted by Elemental Uprising. Instead I blocked a 2/2 of + * his with my 2/3. I should have been forced to block the land targeted by + * Elemental Uprising. + */ + @Test + public void testElementalUprising() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); // 2/2 + // Target land you control becomes a 4/4 Elemental creature with haste until end of turn. It's still a land. It must be blocked this turn if able. + addCard(Zone.HAND, playerA, "Elemental Uprising"); + + addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox"); // 2/4 + + activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {G}"); + activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {G}"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Elemental Uprising", "Mountain"); + + // Silvercoat Lion has not to block because it has to pay {3} to block + attack(1, playerA, "Mountain"); + attack(1, playerA, "Silvercoat Lion"); + block(1, playerB, "Pillarfield Ox", "Silvercoat Lion"); // Not allowed, the Mountain has to be blocked + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerA, "Elemental Uprising", 1); + assertPowerToughness(playerA, "Mountain", 4, 4); + + assertPermanentCount(playerA, "Silvercoat Lion", 1); + assertGraveyardCount(playerB, "Pillarfield Ox", 1); + + assertLife(playerB, 18); + + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/FracturingGustTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/FracturingGustTest.java index 3c91554cf73..b38e6c72ac4 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/FracturingGustTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/FracturingGustTest.java @@ -36,12 +36,12 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * * @author LevelX2 */ - public class FracturingGustTest extends CardTestPlayerBase { @Test - public void testCard() { + public void testWithStaticAbility() { addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); + // Destroy all artifacts and enchantments. You gain 2 life for each permanent destroyed this way. addCard(Zone.HAND, playerA, "Fracturing Gust", 1); // Players can't gain life. @@ -49,13 +49,11 @@ public class FracturingGustTest extends CardTestPlayerBase { // At the beginning of your end step, target opponent chosen at random gains control of Witch Hunt. addCard(Zone.BATTLEFIELD, playerB, "Witch Hunt", 1); - // Destroy all artifacts and enchantments. You gain 2 life for each permanent destroyed this way. castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fracturing Gust"); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertGraveyardCount(playerA, "Fracturing Gust", 1); assertGraveyardCount(playerB, "Witch Hunt", 1); @@ -65,4 +63,26 @@ public class FracturingGustTest extends CardTestPlayerBase { } -} \ No newline at end of file + @Test + public void testWithTriggerdAbility() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); + // Destroy all artifacts and enchantments. You gain 2 life for each permanent destroyed this way. + addCard(Zone.HAND, playerA, "Fracturing Gust", 1); + + // When Guardian Automaton dies, you gain 3 life. + addCard(Zone.BATTLEFIELD, playerA, "Guardian Automaton", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fracturing Gust"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Fracturing Gust", 1); + assertGraveyardCount(playerA, "Guardian Automaton", 1); + + // + 2 from destroyed Guardian Automaton + assertLife(playerA, 25); + assertLife(playerB, 20); + + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/bfz/BrutalExpulsionTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/bfz/BrutalExpulsionTest.java new file mode 100644 index 00000000000..195666c6097 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/bfz/BrutalExpulsionTest.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.single.bfz; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author Quercitron + */ +public class BrutalExpulsionTest extends CardTestPlayerBase { + + /** + * Brutal Expulsion targeting Gideon, Ally of Zendikar. Gideon has 3 loyalty. Brutal Expulsion resolves, + * leaves 1 loyalty. I attack Gideon for 1 with a Scion token, Gideon dies. Instead of going to graveyard, + * Expulsion sends Gideon to exile. However, in game Gideon went to graveyard. + */ + @Test + public void testPlaneswalkerExile() { + // Choose one or both + // - Return target spell or creature to its owner's hand; + // or Brutal Expulsion deals 2 damage to target creature or planeswalker. If that permanent would be put into a graveyard this turn, exile it instead. + addCard(Zone.HAND, playerA, "Brutal Expulsion"); + // Shock deals 2 damage to target creature or player. + addCard(Zone.HAND, playerA, "Shock"); + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + + // Planeswalker with 4 loyalty. + addCard(Zone.BATTLEFIELD, playerB, "Gideon, Ally of Zendikar"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Brutal Expulsion", playerB); + setModeChoice(playerA, "2"); + setModeChoice(playerA, null); + setChoice(playerA, "Yes"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shock", playerB); + setChoice(playerA, "Yes"); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertPermanentCount(playerB, "Gideon, Ally of Zendikar", 0); + assertGraveyardCount(playerB, "Gideon, Ally of Zendikar", 0); + assertExileCount("Gideon, Ally of Zendikar", 1); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/EntersTheBattlefieldTriggerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/EntersTheBattlefieldTriggerTest.java index fbeebe9d6eb..d6950d92b97 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/EntersTheBattlefieldTriggerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/EntersTheBattlefieldTriggerTest.java @@ -64,4 +64,35 @@ public class EntersTheBattlefieldTriggerTest extends CardTestPlayerBase { assertLife(playerB, 20); } + /** + * Diluvian Primordial is bugged and doesn't trigger upon entering the + * battlefield + */ + @Test + public void testDiluvianPrimordial() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 7); + // Flying + // When Diluvian Primordial enters the battlefield, for each opponent, you may cast up to one target instant or sorcery card from that player's graveyard without paying its mana cost. If a card cast this way would be put into a graveyard this turn, exile it instead. + addCard(Zone.HAND, playerA, "Diluvian Primordial", 1); // {5}{U}{U} + + addCard(Zone.GRAVEYARD, playerB, "Lightning Bolt"); + + // You may have Clever Impersonator enter the battlefield as a copy of any nonland permanent on the battlefield. + addCard(Zone.HAND, playerB, "Clever Impersonator", 1); + addCard(Zone.BATTLEFIELD, playerB, "Island", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Diluvian Primordial"); + addTarget(playerA, "Lightning Bolt"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Diluvian Primordial", 1); + + assertExileCount("Lightning Bolt", 1); + + assertLife(playerA, 20); + assertLife(playerB, 17); + } + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java index 5c2a7cdd982..0fe0e93c2eb 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java @@ -225,4 +225,29 @@ public class SpellskiteTest extends CardTestPlayerBase { assertLife(playerB, 20); } + + /** + * When an AI opponent casts a spell targeting one of my creatures, Wild + * Defiance does not trigger. (Tested with Flame Slash, which was able to + * kill my Spellskite) + */ + @Test + public void testWildDefiance() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + // Flame Slash deals 4 damage to target creature. + addCard(Zone.HAND, playerA, "Flame Slash"); // {R} + + // Whenever a creature you control becomes the target of an instant or sorcery spell, that creature gets +3/+3 until end of turn. + addCard(Zone.BATTLEFIELD, playerB, "Wild Defiance", 1); + addCard(Zone.BATTLEFIELD, playerB, "Spellskite", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Flame Slash", "Spellskite"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Flame Slash", 1); + assertPowerToughness(playerB, "Spellskite", 3, 7); + } + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/BloodArtistTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/BloodArtistTest.java index ae5d9ab002c..996cba1c974 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/BloodArtistTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/BloodArtistTest.java @@ -2,6 +2,7 @@ package org.mage.test.cards.triggers.dies; import mage.constants.PhaseStep; import mage.constants.Zone; +import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -9,18 +10,21 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * * @author noxx * - * Whenever Blood Artist or another creature dies, target player loses 1 life and you gain 1 life. + * Whenever Blood Artist or another creature dies, target player loses 1 life + * and you gain 1 life. */ public class BloodArtistTest extends CardTestPlayerBase { /** - * Tests that whenever Blood Artist goes to graveyard, it would trigger its ability. - * Tests that after Blood Artist went to graveyard, his ability doesn't work anymore. + * Tests that whenever Blood Artist goes to graveyard, it would trigger its + * ability. Tests that after Blood Artist went to graveyard, his ability + * doesn't work anymore. */ @Test public void testDisabledEffectOnChangeZone() { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); addCard(Zone.HAND, playerA, "Lightning Bolt", 2); + // Whenever Blood Artist or another creature dies, target player loses 1 life and you gain 1 life. addCard(Zone.BATTLEFIELD, playerA, "Blood Artist", 2); addCard(Zone.GRAVEYARD, playerA, "Blood Artist", 1); @@ -36,4 +40,93 @@ public class BloodArtistTest extends CardTestPlayerBase { assertLife(playerB, 17); } + /** + * There is realy something wrong with sacrifice effects triggers. Had + * Zulaport Cutthroat on battlefield and tried Altar's Reap and Bone + * Splinters on it. Neither triggered ZC's abbility. Tried the same with + * Blood Artist on battlefield, same result - no trigger. + */ + @Test + public void testWithBoneSplinters() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + // As an additional cost to cast Bone Splinters, sacrifice a creature. + // Destroy target creature. + addCard(Zone.HAND, playerA, "Bone Splinters", 1); // Sorcery - {B} + // Whenever Blood Artist or another creature dies, target player loses 1 life and you gain 1 life. + addCard(Zone.BATTLEFIELD, playerA, "Blood Artist", 1); + + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bone Splinters", "Pillarfield Ox"); + setChoice(playerA, "Silvercoat Lion"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Bone Splinters", 1); + assertGraveyardCount(playerA, "Silvercoat Lion", 1); + assertGraveyardCount(playerB, "Pillarfield Ox", 1); + assertLife(playerA, 22); + assertLife(playerB, 18); + } + + @Test + @Ignore // not Fixed yet + public void testWithBoneSplinters2() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + // As an additional cost to cast Bone Splinters, sacrifice a creature. + // Destroy target creature. + addCard(Zone.HAND, playerA, "Bone Splinters", 1); // Sorcery - {B} + // Whenever Blood Artist or another creature dies, target player loses 1 life and you gain 1 life. + addCard(Zone.BATTLEFIELD, playerA, "Blood Artist", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bone Splinters", "Pillarfield Ox"); + setChoice(playerA, "Blood Artist"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Bone Splinters", 1); + assertGraveyardCount(playerA, "Blood Artist", 1); + assertGraveyardCount(playerB, "Pillarfield Ox", 1); + assertLife(playerA, 21); // For sacrifice both Blood Artist trigger, for destoy effect only one ist left + assertLife(playerB, 19); + } + + @Test + @Ignore // not Fixed yet + public void testWithBoneSplinters3() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + // As an additional cost to cast Bone Splinters, sacrifice a creature. + // Destroy target creature. + addCard(Zone.HAND, playerA, "Bone Splinters", 1); // Sorcery - {B} + // Destroy target nonartifact, nonblack creature. It can't be regenerated. + addCard(Zone.HAND, playerA, "Terror", 1); // Instant - {1}{B} + // Whenever Blood Artist or another creature dies, target player loses 1 life and you gain 1 life. + addCard(Zone.BATTLEFIELD, playerA, "Blood Artist", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 1); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bone Splinters", "Pillarfield Ox"); + setChoice(playerA, "Blood Artist"); + // Blood Artist may no longer trigger from destroyed creature because already in the graveyard + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Terror", "Silvercoat Lion", "Bone Splinters"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Bone Splinters", 1); + assertGraveyardCount(playerA, "Terror", 1); + assertGraveyardCount(playerA, "Blood Artist", 1); + assertGraveyardCount(playerB, "Pillarfield Ox", 1); + assertGraveyardCount(playerB, "Silvercoat Lion", 1); + assertLife(playerA, 21); // For sacrifice both Blood Artist trigger, for destoy effect only one ist left + assertLife(playerB, 19); + } + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/StoneHavenOutfitterTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/StoneHavenOutfitterTest.java new file mode 100644 index 00000000000..03043451e8a --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/StoneHavenOutfitterTest.java @@ -0,0 +1,87 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.triggers.dies; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class StoneHavenOutfitterTest extends CardTestPlayerBase { + + @Test + public void testEquipped() { + // Equipped creatures you control get +1/+1. + // Whenever an equipped creature you control dies, draw a card. + addCard(Zone.BATTLEFIELD, playerA, "Stone Haven Outfitter", 1); // Creature 2/2 + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + // Equipped creature has hexproof and haste. + // Equip {1} + addCard(Zone.BATTLEFIELD, playerA, "Swiftfoot Boots", 1); + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip", "Silvercoat Lion"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPowerToughness(playerA, "Silvercoat Lion", 3, 3); + + } + + @Test + public void testEquippedDied() { + // Equipped creatures you control get +1/+1. + // Whenever an equipped creature you control dies, draw a card. + addCard(Zone.BATTLEFIELD, playerA, "Stone Haven Outfitter", 1); // Creature 2/2 + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); + // Equipped creature has hexproof and haste. + // Equip {1} + addCard(Zone.BATTLEFIELD, playerA, "Swiftfoot Boots", 1); + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); + + addCard(Zone.HAND, playerA, "Lightning Bolt", 1); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip", "Silvercoat Lion"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Silvercoat Lion"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerA, "Lightning Bolt", 1); + assertGraveyardCount(playerA, "Silvercoat Lion", 1); + + assertHandCount(playerA, 1); + + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ZulaportCutthroatTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ZulaportCutthroatTest.java new file mode 100644 index 00000000000..32514bec91b --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ZulaportCutthroatTest.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.triggers.dies; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class ZulaportCutthroatTest extends CardTestPlayerBase { + + /** + * Zulaport's ability doesn't trigger when it dies. I'm not sure if that's + * always the case, but I've encountered that bug at least several times + * today. + * + */ + @Test + public void testDiesAndControllerDamage() { + // Whenever Zulaport Cutthroat or another creature you control dies, each opponent loses 1 life and you gain 1 life. + addCard(Zone.BATTLEFIELD, playerA, "Zulaport Cutthroat", 1); // 1/1 + + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); + // Target creature you control gets +1/+0 and gains deathtouch until end of turn. + // Whenever a creature dealt damage by that creature this turn dies, its controller loses 2 life. + addCard(Zone.HAND, playerB, "Lightning Bolt"); // {B} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", "Zulaport Cutthroat"); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerB, "Lightning Bolt", 1); + assertGraveyardCount(playerA, "Zulaport Cutthroat", 1); + + assertLife(playerA, 21); + assertLife(playerB, 19); + + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/watchers/HallOfTheBanditLordTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/watchers/HallOfTheBanditLordTest.java index b0a7b2b45d3..d3422a9ed31 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/watchers/HallOfTheBanditLordTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/watchers/HallOfTheBanditLordTest.java @@ -15,25 +15,25 @@ public class HallOfTheBanditLordTest extends CardTestPlayerBase { * Hall of the Bandit Lord * Legendary Land * Hall of the Bandit Lord enters the battlefield tapped. - * {T}, Pay 3 life: Add {C} to your mana pool. If that mana is spent on a + * {T}, Pay 3 life: Add {C} to your mana pool. If that mana is spent on a * creature spell, it gains haste. * - */ - + */ + // test that a creature cast using Hall of the Bandit Lord mana gains haste @Test public void testGainsHaste() { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); addCard(Zone.BATTLEFIELD, playerA, "Hall of the Bandit Lord"); - addCard(Zone.HAND, playerA, "Goblin Roughrider"); - + addCard(Zone.HAND, playerA, "Goblin Roughrider"); // Creature 3/3 - {2}{R} + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Goblin Roughrider"); - + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - + this.assertAbility(playerA, "Goblin Roughrider", HasteAbility.getInstance(), true); - + } // test that a creature cast not using Hall of the Bandit Lord mana does not gain haste @@ -42,14 +42,14 @@ public class HallOfTheBanditLordTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); addCard(Zone.BATTLEFIELD, playerA, "Hall of the Bandit Lord"); addCard(Zone.HAND, playerA, "Ember Hauler"); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ember Hauler"); - + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - + this.assertAbility(playerA, "Ember Hauler", HasteAbility.getInstance(), false); - + } - + } diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/duel/KaradorGhostChieftainTest.java b/Mage.Tests/src/test/java/org/mage/test/commander/duel/KaradorGhostChieftainTest.java new file mode 100644 index 00000000000..b2901ee77d4 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/commander/duel/KaradorGhostChieftainTest.java @@ -0,0 +1,155 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.commander.duel; + +import java.io.FileNotFoundException; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.GameException; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestCommanderDuelBase; + +/** + * + * @author LevelX2 + */ +public class KaradorGhostChieftainTest extends CardTestCommanderDuelBase { + + @Override + protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { + // Karador, Ghost Chieftain costs {1} less to cast for each creature card in your graveyard. + // During each of your turns, you may cast one creature card from your graveyard. + setDecknamePlayerA("CommanderDuel_Karador_BGW.dck"); // Commander = Karador, Ghost Chieftain {5}{B}{G}{W} + setDecknamePlayerB("CMDNorinTheWary.dck"); // Need red + + return super.createNewGameAndPlayers(); + } + + @Test + public void castKarador() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertTappedCount("Island", false, 2); + assertPermanentCount(playerA, "Karador, Ghost Chieftain", 1); + } + + @Test + public void castKaradorTwice() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 7); + addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 2); + + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 4); + // Lightning Blast deals 4 damage to target creature or player. + addCard(Zone.HAND, playerB, "Lightning Blast", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Blast", "Karador, Ghost Chieftain"); + + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + + setStopAt(3, PhaseStep.BEGIN_COMBAT); + execute(); + assertGraveyardCount(playerB, "Lightning Blast", 1); + assertPermanentCount(playerA, "Karador, Ghost Chieftain", 1); + + assertTappedCount("Island", true, 5); + } + + @Test + public void castKaradorFourTimes() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 11); + addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 2); + + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 4); + // Lightning Blast deals 4 damage to target creature or player. + addCard(Zone.HAND, playerB, "Lightning Blast", 3); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Blast", "Karador, Ghost Chieftain"); + + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + castSpell(4, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Blast", "Karador, Ghost Chieftain"); + + castSpell(5, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + castSpell(6, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Blast", "Karador, Ghost Chieftain"); + + castSpell(7, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + + setStopAt(7, PhaseStep.BEGIN_COMBAT); + execute(); + assertGraveyardCount(playerB, "Lightning Blast", 3); + assertPermanentCount(playerA, "Karador, Ghost Chieftain", 1); + + assertTappedCount("Island", true, 9); + } + + @Test + public void castKaradorFourTimes15Reduction() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 11); + addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 15); + + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 4); + // Lightning Blast deals 4 damage to target creature or player. + addCard(Zone.HAND, playerB, "Lightning Blast", 3); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Blast", "Karador, Ghost Chieftain"); + + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + castSpell(4, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Blast", "Karador, Ghost Chieftain"); + + castSpell(5, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + castSpell(6, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Blast", "Karador, Ghost Chieftain"); + + castSpell(7, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + + setStopAt(7, PhaseStep.BEGIN_COMBAT); + execute(); + assertGraveyardCount(playerB, "Lightning Blast", 3); + assertPermanentCount(playerA, "Karador, Ghost Chieftain", 1); + + assertTappedCount("Island", true, 0); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/duel/OpalPalaceTest.java b/Mage.Tests/src/test/java/org/mage/test/commander/duel/OpalPalaceTest.java index aa2284c768d..273b8dbd12f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/commander/duel/OpalPalaceTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/commander/duel/OpalPalaceTest.java @@ -37,24 +37,25 @@ import org.mage.test.serverside.base.CardTestCommanderDuelBase; * * @author LevelX2 */ - public class OpalPalaceTest extends CardTestCommanderDuelBase { + /** - * I cast my commander with Opal Palace's second ability and it did not receive a +1/+1 counter - * the first time it was cast (rulings say it should on the first time cast). + * I cast my commander with Opal Palace's second ability and it did not + * receive a +1/+1 counter the first time it was cast (rulings say it should + * on the first time cast). */ @Test public void testFirstAbility() { addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); - + // {T}: Add {C} to your mana pool. - // {1}, {T}: Add to your mana pool one mana of any color in your commander's color identity. + // {1}, {T}: Add to your mana pool one mana of any color in your commander's color identity. // If you spend this mana to cast your commander, it enters the battlefield with a number of +1/+1 counters on it - // equal to the number of times it's been cast from the command zone this game. + // equal to the number of times it's been cast from the command zone this game. addCard(Zone.BATTLEFIELD, playerA, "Opal Palace", 1); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ob Nixilis of the Black Oath"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ob Nixilis of the Black Oath"); // {3}{B}{B} setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); 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 280c227ac81..87d245772d3 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 @@ -521,6 +521,11 @@ public class TestPlayer implements Player { @Override public Mode chooseMode(Modes modes, Ability source, Game game) { if (!modesSet.isEmpty() && modes.getMaxModes() > modes.getSelectedModes().size()) { + // set mode to null to select less than maximum modes if multiple modes are allowed + if (modesSet.get(0) == null) { + modesSet.remove(0); + return null; + } int selectedMode = Integer.parseInt(modesSet.get(0)); int i = 1; for (Mode mode : modes.getAvailableModes(source, game)) { @@ -2077,4 +2082,8 @@ public class TestPlayer implements Player { return AIPlayer; } + public String getHistory() { + return computerPlayer.getHistory(); + } + } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java index bcfa18d0f54..ecc5c3df051 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java @@ -1,9 +1,19 @@ package org.mage.test.serverside.base; -import mage.constants.PhaseStep; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Scanner; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import mage.cards.Card; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; +import mage.constants.PhaseStep; import mage.constants.RangeOfInfluence; import mage.constants.Zone; import mage.game.Game; @@ -25,19 +35,13 @@ import org.junit.BeforeClass; import org.mage.test.player.RandomPlayer; import org.mage.test.player.TestPlayer; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FilenameFilter; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - /** * Base class for all tests. * * @author ayratn */ public abstract class MageTestBase { + protected static Logger logger = Logger.getLogger(MageTestBase.class); public static PluginClassLoader classLoader = new PluginClassLoader(); @@ -46,17 +50,17 @@ public abstract class MageTestBase { protected Pattern pattern = Pattern.compile("([a-zA-Z]*):([\\w]*):([a-zA-Z ,\\-.!'\\d]*):([\\d]*)(:\\{tapped\\})?"); - protected List handCardsA = new ArrayList(); - protected List handCardsB = new ArrayList(); - protected List battlefieldCardsA = new ArrayList(); - protected List battlefieldCardsB = new ArrayList(); - protected List graveyardCardsA = new ArrayList(); - protected List graveyardCardsB = new ArrayList(); - protected List libraryCardsA = new ArrayList(); - protected List libraryCardsB = new ArrayList(); + protected List handCardsA = new ArrayList<>(); + protected List handCardsB = new ArrayList<>(); + protected List battlefieldCardsA = new ArrayList<>(); + protected List battlefieldCardsB = new ArrayList<>(); + protected List graveyardCardsA = new ArrayList<>(); + protected List graveyardCardsB = new ArrayList<>(); + protected List libraryCardsA = new ArrayList<>(); + protected List libraryCardsB = new ArrayList<>(); - protected Map commandsA = new HashMap(); - protected Map commandsB = new HashMap(); + protected Map commandsA = new HashMap<>(); + protected Map commandsB = new HashMap<>(); protected TestPlayer playerA; protected TestPlayer playerB; @@ -67,8 +71,7 @@ public abstract class MageTestBase { protected static Game currentGame = null; /** - * Player thats starts the game first. - * By default, it is ComputerA. + * Player thats starts the game first. By default, it is ComputerA. */ protected static Player activePlayer = null; @@ -77,6 +80,7 @@ public abstract class MageTestBase { protected PhaseStep stopAtStep = PhaseStep.UNTAP; protected enum ParserState { + INIT, OPTIONS, EXPECTED @@ -85,18 +89,13 @@ public abstract class MageTestBase { protected ParserState parserState; /** - * Expected results of the test. - * Read from test case in {@link String} based format: + * Expected results of the test. Read from test case in {@link String} based + * format: *

- * Example: - * turn:1 - * result:won:ComputerA - * life:ComputerA:20 - * life:ComputerB:0 - * battlefield:ComputerB:Tine Shrike:0 - * graveyard:ComputerB:Tine Shrike:1 + * Example: turn:1 result:won:ComputerA life:ComputerA:20 life:ComputerB:0 + * battlefield:ComputerB:Tine Shrike:0 graveyard:ComputerB:Tine Shrike:1 */ - protected List expectedResults = new ArrayList(); + protected List expectedResults = new ArrayList<>(); protected static final String TESTS_PATH = "tests" + File.separator; @@ -163,8 +162,9 @@ public abstract class MageTestBase { private static void deleteSavedGames() { File directory = new File("saved/"); - if (!directory.exists()) + if (!directory.exists()) { directory.mkdirs(); + } File[] files = directory.listFiles( new FilenameFilter() { @Override @@ -185,7 +185,9 @@ public abstract class MageTestBase { try { while (scanner.hasNextLine()) { String line = scanner.nextLine().trim(); - if (line == null || line.isEmpty() || line.startsWith("#")) continue; + if (line == null || line.isEmpty() || line.startsWith("#")) { + continue; + } if (line.startsWith("$include")) { includeFrom(line); continue; diff --git a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java index d076ed3265c..18288af786a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java +++ b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java @@ -1237,4 +1237,10 @@ public class PlayerStub implements Player { public boolean addTargets(Ability ability, Game game) { return false; } + + @Override + public String getHistory() { + return ""; + } + } diff --git a/Mage.Tests/src/test/java/org/mage/test/stub/TournamentStub.java b/Mage.Tests/src/test/java/org/mage/test/stub/TournamentStub.java index acdc6c43e74..da331935d10 100644 --- a/Mage.Tests/src/test/java/org/mage/test/stub/TournamentStub.java +++ b/Mage.Tests/src/test/java/org/mage/test/stub/TournamentStub.java @@ -25,23 +25,26 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package org.mage.test.stub; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.UUID; import mage.cards.ExpansionSet; import mage.cards.decks.Deck; import mage.game.draft.Draft; import mage.game.events.Listener; import mage.game.events.PlayerQueryEvent; import mage.game.events.TableEvent; -import mage.game.tournament.*; +import mage.game.result.ResultProtos; +import mage.game.tournament.Round; +import mage.game.tournament.Tournament; +import mage.game.tournament.TournamentOptions; +import mage.game.tournament.TournamentPlayer; +import mage.game.tournament.TournamentType; import mage.players.Player; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.UUID; - /** * * @author Quercitron @@ -70,6 +73,11 @@ public class TournamentStub implements Tournament { return null; } + @Override + public ResultProtos.TourneyProto toProto() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + @Override public Collection getPlayers() { return null; diff --git a/Mage.Tests/src/test/java/org/mage/test/utils/ManaOptionsTest.java b/Mage.Tests/src/test/java/org/mage/test/utils/ManaOptionsTest.java index d5db6555a91..f6b6e8b7aca 100644 --- a/Mage.Tests/src/test/java/org/mage/test/utils/ManaOptionsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/utils/ManaOptionsTest.java @@ -90,12 +90,17 @@ public class ManaOptionsTest extends CardTestPlayerBase { ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); - Assert.assertEquals("mana variations don't fit", 4, manaOptions.size()); - Assert.assertEquals("{W}{W}{W}", getManaOption(0, manaOptions)); - Assert.assertEquals("{U}{W}{W}", getManaOption(1, manaOptions)); - Assert.assertEquals("{U}{U}{W}", getManaOption(2, manaOptions)); - Assert.assertEquals("{U}{U}{U}", getManaOption(3, manaOptions)); - + Assert.assertEquals("mana variations don't fit", 10, manaOptions.size()); + Assert.assertEquals("{C}{C}{C}", getManaOption(0, manaOptions)); + Assert.assertEquals("{C}{C}{W}", getManaOption(1, manaOptions)); + Assert.assertEquals("{C}{C}{U}", getManaOption(2, manaOptions)); + Assert.assertEquals("{C}{W}{W}", getManaOption(3, manaOptions)); + Assert.assertEquals("{C}{U}{W}", getManaOption(4, manaOptions)); + Assert.assertEquals("{C}{U}{U}", getManaOption(5, manaOptions)); + Assert.assertEquals("{W}{W}{W}", getManaOption(6, manaOptions)); + Assert.assertEquals("{U}{W}{W}", getManaOption(7, manaOptions)); + Assert.assertEquals("{U}{U}{W}", getManaOption(8, manaOptions)); + Assert.assertEquals("{U}{U}{U}", getManaOption(9, manaOptions)); } // Chromatic Sphere @@ -146,7 +151,7 @@ public class ManaOptionsTest extends CardTestPlayerBase { ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); - Assert.assertEquals("{1}{G}{G}{W}{W}", getManaOption(0, manaOptions)); + Assert.assertEquals("{C}{G}{G}{W}{W}", getManaOption(0, manaOptions)); } // Crystal Quarry @@ -164,7 +169,7 @@ public class ManaOptionsTest extends CardTestPlayerBase { ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); Assert.assertEquals("mana variations don't fit", 2, manaOptions.size()); - Assert.assertEquals("{1}{G}{G}{G}{W}{W}", getManaOption(0, manaOptions)); + Assert.assertEquals("{C}{G}{G}{G}{W}{W}", getManaOption(0, manaOptions)); Assert.assertEquals("{R}{G}{U}{W}{B}", getManaOption(1, manaOptions)); } @@ -182,8 +187,9 @@ public class ManaOptionsTest extends CardTestPlayerBase { ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); - Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); - Assert.assertEquals("{G}{G}{G}{G}{G}", getManaOption(0, manaOptions)); + Assert.assertEquals("mana variations don't fit", 2, manaOptions.size()); + Assert.assertEquals("{C}{G}{G}{G}", getManaOption(0, manaOptions)); + Assert.assertEquals("{G}{G}{G}{G}{G}", getManaOption(1, manaOptions)); } @Test @@ -198,9 +204,10 @@ public class ManaOptionsTest extends CardTestPlayerBase { ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); - Assert.assertEquals("mana variations don't fit", 2, manaOptions.size()); - Assert.assertEquals("{G}{G}{G}{G}{G}", getManaOption(0, manaOptions)); - Assert.assertEquals("{R}{R}{R}{G}", getManaOption(1, manaOptions)); + Assert.assertEquals("mana variations don't fit", 3, manaOptions.size()); + Assert.assertEquals("{C}{G}{G}{G}", getManaOption(0, manaOptions)); + Assert.assertEquals("{G}{G}{G}{G}{G}", getManaOption(1, manaOptions)); + Assert.assertEquals("{R}{R}{R}{G}", getManaOption(2, manaOptions)); } @Test @@ -215,7 +222,7 @@ public class ManaOptionsTest extends CardTestPlayerBase { ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); - Assert.assertEquals("{1}{G}{Any}", getManaOption(0, manaOptions)); + Assert.assertEquals("{C}{G}{Any}", getManaOption(0, manaOptions)); } @Test @@ -251,10 +258,11 @@ public class ManaOptionsTest extends CardTestPlayerBase { ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); - Assert.assertEquals("mana variations don't fit", 3, manaOptions.size()); - Assert.assertEquals("{W}{W}", getManaOption(0, manaOptions)); - Assert.assertEquals("{W}{B}", getManaOption(1, manaOptions)); - Assert.assertEquals("{B}{B}", getManaOption(2, manaOptions)); + Assert.assertEquals("mana variations don't fit", 4, manaOptions.size()); + Assert.assertEquals("{C}{W}", getManaOption(0, manaOptions)); + Assert.assertEquals("{W}{W}", getManaOption(1, manaOptions)); + Assert.assertEquals("{W}{B}", getManaOption(2, manaOptions)); + Assert.assertEquals("{B}{B}", getManaOption(3, manaOptions)); } /** @@ -306,7 +314,7 @@ public class ManaOptionsTest extends CardTestPlayerBase { ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); - Assert.assertEquals("{1}{W}{B}", getManaOption(0, manaOptions)); + Assert.assertEquals("{C}{W}{B}", getManaOption(0, manaOptions)); } @Test @@ -324,8 +332,9 @@ public class ManaOptionsTest extends CardTestPlayerBase { ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); - Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); - Assert.assertEquals("{4}{W}{B}", getManaOption(0, manaOptions)); + Assert.assertEquals("mana variations don't fit", 2, manaOptions.size()); + Assert.assertEquals("{C}{W}{B}", getManaOption(0, manaOptions)); + Assert.assertEquals("{4}{W}{B}", getManaOption(1, manaOptions)); } @Test diff --git a/Mage.Updater/pom.xml b/Mage.Updater/pom.xml index 43acb01f144..cc2e47e1b97 100644 --- a/Mage.Updater/pom.xml +++ b/Mage.Updater/pom.xml @@ -5,7 +5,7 @@ mage-root org.mage - 1.4.6 + 1.4.8 4.0.0 diff --git a/Mage/pom.xml b/Mage/pom.xml index a026de69dac..30c0b461c1e 100644 --- a/Mage/pom.xml +++ b/Mage/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.6 + 1.4.8 mage @@ -36,6 +36,11 @@ junit 4.12 + + com.google.protobuf + protobuf-java + ${protobuf.version} + @@ -51,11 +56,141 @@ + + + + org.apache.maven.plugins + maven-dependency-plugin + ${maven-dependency-plugin.version} + + + copy-protoc + generate-sources + + copy + + + + + com.google.protobuf + protoc + ${protobuf.version} + ${os.detected.classifier} + exe + true + ${project.build.directory} + + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + ${maven-antrun-plugin.version} + + + exec-protoc + generate-sources + + + + + + + + + + + + + + + + + + + + + + + run + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + ${build-helper-maven-plugin.version} + + + add-classes + generate-sources + + add-source + + + + ${protobuf.output.directory} + + + + + + + + org.apache.maven.plugins + maven-shade-plugin + ${maven-shade-plugin.version} + + + package + + shade + + + + + com.google.protobuf + ${project.groupId}.${project.artifactId}.shaded.protobuf + + + + + + mage + + + + + + kr.motd.maven + os-maven-plugin + ${os-maven-plugin.version} + + - + + + + ${project.basedir}/src/main/proto + ${project.build.directory}/generated-sources + + + 1.9.1 + 1.8 + 2.10 + 2.4.2 + 1.4.1.Final + 3.0.0-beta-1 + diff --git a/Mage/src/main/java/mage/ConditionalMana.java b/Mage/src/main/java/mage/ConditionalMana.java index 4f0d17293b5..1489b91a6c5 100644 --- a/Mage/src/main/java/mage/ConditionalMana.java +++ b/Mage/src/main/java/mage/ConditionalMana.java @@ -1,30 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage; import java.io.Serializable; @@ -33,26 +33,27 @@ import java.util.List; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.Condition; +import mage.abilities.costs.Cost; import mage.abilities.mana.conditional.ManaCondition; import mage.constants.ManaType; import mage.filter.Filter; import mage.filter.FilterMana; import mage.game.Game; - /** * @author nantuko */ public class ConditionalMana extends Mana implements Serializable { /** - * Conditions that should be met (all or any depending on comparison scope) to allow spending {@link Mana} mana. + * Conditions that should be met (all or any depending on comparison scope) + * to allow spending {@link Mana} mana. */ private List conditions = new ArrayList<>(); /** - * Text displayed as a description for conditional mana. - * Usually includes the conditions that should be met to use this mana. + * Text displayed as a description for conditional mana. Usually includes + * the conditions that should be met to use this mana. */ protected String staticText = "Conditional mana."; @@ -92,13 +93,13 @@ public class ConditionalMana extends Mana implements Serializable { this.scope = scope; } - public boolean apply(Ability ability, Game game, UUID manaProducerId) { + public boolean apply(Ability ability, Game game, UUID manaProducerId, Cost costToPay) { if (conditions.isEmpty()) { throw new IllegalStateException("Conditional mana should contain at least one Condition"); } for (Condition condition : conditions) { - boolean applied = (condition instanceof ManaCondition) ? - ((ManaCondition)condition).apply(game, ability, manaProducerId) : condition.apply(game, ability); + boolean applied = (condition instanceof ManaCondition) + ? ((ManaCondition) condition).apply(game, ability, manaProducerId, costToPay) : condition.apply(game, ability); if (!applied) { // if one condition fails, return false only if All conditions should be met @@ -151,6 +152,9 @@ public class ConditionalMana extends Mana implements Serializable { if (filter.isColorless()) { colorless = 0; } + if (filter.isGeneric()) { + generic = 0; + } } public UUID getManaProducerId() { @@ -168,9 +172,9 @@ public class ConditionalMana extends Mana implements Serializable { public void setManaProducerOriginalId(UUID manaProducerOriginalId) { this.manaProducerOriginalId = manaProducerOriginalId; } - + public void clear(ManaType manaType) { - switch(manaType) { + switch (manaType) { case BLACK: black = 0; break; @@ -186,31 +190,42 @@ public class ConditionalMana extends Mana implements Serializable { case WHITE: white = 0; break; + case GENERIC: + generic = 0; + break; case COLORLESS: colorless = 0; break; } } - + public void add(ManaType manaType, int amount) { - switch(manaType) { + switch (manaType) { case BLACK: black += amount; break; case BLUE: - blue += amount;; + blue += amount; + ; break; case GREEN: - green += amount;; + green += amount; + ; break; case RED: - red += amount;; + red += amount; + ; break; case WHITE: - white += amount;; + white += amount; + ; break; case COLORLESS: - colorless += amount;; + colorless += amount; + ; + case GENERIC: + generic += amount; + ; break; } } diff --git a/Mage/src/main/java/mage/MageObjectImpl.java b/Mage/src/main/java/mage/MageObjectImpl.java index f9402ad3df4..d5f8e26e522 100644 --- a/Mage/src/main/java/mage/MageObjectImpl.java +++ b/Mage/src/main/java/mage/MageObjectImpl.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage; import java.util.ArrayList; @@ -89,19 +88,19 @@ public abstract class MageObjectImpl implements MageObject { @Override public UUID getId() { - return objectId; + return objectId; } @Override public String getName() { return name; } - + @Override public String getIdName() { - return getName() + " ["+getId().toString().substring(0,3) +"]"; + return getName() + " [" + getId().toString().substring(0, 3) + "]"; } - + @Override public String getLogName() { return GameLog.getColoredObjectIdName(this); @@ -123,17 +122,17 @@ public abstract class MageObjectImpl implements MageObject { } @Override - public List getSubtype(){ + public List getSubtype() { return subtype; } @Override - public List getSupertype(){ + public List getSupertype() { return supertype; } @Override - public Abilities getAbilities(){ + public Abilities getAbilities() { return abilities; } @@ -143,7 +142,7 @@ public abstract class MageObjectImpl implements MageObject { return true; } Abilities otherAbilities = game.getState().getAllOtherAbilities(getId()); - return otherAbilities != null && otherAbilities.containsKey(abilityId); + return otherAbilities != null && otherAbilities.containsKey(abilityId); } @Override @@ -167,13 +166,16 @@ public abstract class MageObjectImpl implements MageObject { } @Override - public void adjustChoices(Ability ability, Game game) {} - - @Override - public void adjustCosts(Ability ability, Game game) {} + public void adjustChoices(Ability ability, Game game) { + } @Override - public void adjustTargets(Ability ability, Game game) {} + public void adjustCosts(Ability ability, Game game) { + } + + @Override + public void adjustTargets(Ability ability, Game game) { + } @Override public boolean hasSubtype(String value) { @@ -182,14 +184,15 @@ public abstract class MageObjectImpl implements MageObject { } if (this.subtype.contains(value)) { return true; - } else { // checking for Changeling - // first make sure input parameter is a creature type - // if so, then ChangelingAbility doesn't matter + } else { + // checking for Changeling + // first make sure input parameter is a creature subtype + // if not, then ChangelingAbility doesn't matter if (CardUtil.isNonCreatureSubtype(value)) { return false; } // as it is creature subtype, then check the existence of Changeling - return abilities.contains(ChangelingAbility.getInstance()) || this.subtype.contains(ChangelingAbility.ALL_CREATURE_TYPE); + return abilities.contains(ChangelingAbility.getInstance()) || this.subtype.contains(ChangelingAbility.ALL_CREATURE_TYPE); } } @@ -202,7 +205,7 @@ public abstract class MageObjectImpl implements MageObject { public boolean isCopy() { return copy; } - + @Override public int getZoneChangeCounter(Game game) { return game.getState().getZoneChangeCounter(objectId); @@ -217,5 +220,5 @@ public abstract class MageObjectImpl implements MageObject { public void setZoneChangeCounter(int value, Game game) { game.getState().setZoneChangeCounter(objectId, value); } - + } diff --git a/Mage/src/main/java/mage/MageObjectReference.java b/Mage/src/main/java/mage/MageObjectReference.java index b2516798d20..d44226ce0db 100644 --- a/Mage/src/main/java/mage/MageObjectReference.java +++ b/Mage/src/main/java/mage/MageObjectReference.java @@ -47,7 +47,7 @@ public class MageObjectReference implements Comparable, Ser private static final Logger logger = Logger.getLogger(MageObjectReference.class); private final UUID sourceId; - private final int zoneChangeCounter; + private int zoneChangeCounter; public MageObjectReference(MageObject mageObject, Game game) { this.sourceId = mageObject.getId(); @@ -67,6 +67,11 @@ public class MageObjectReference implements Comparable, Ser this.zoneChangeCounter = zoneChangeCounter; } + public MageObjectReference(UUID sourceId) { + this.sourceId = sourceId; + this.zoneChangeCounter = -1; + } + public MageObjectReference(UUID sourceId, Game game) { this.sourceId = sourceId; MageObject mageObject = game.getObject(sourceId); @@ -163,4 +168,7 @@ public class MageObjectReference implements Comparable, Ser return null; } + public void setZoneChangeCounter(int zoneChangeCounter) { + this.zoneChangeCounter = zoneChangeCounter; + } } diff --git a/Mage/src/main/java/mage/Mana.java b/Mage/src/main/java/mage/Mana.java index ae00967049a..779d31f7cc5 100644 --- a/Mage/src/main/java/mage/Mana.java +++ b/Mage/src/main/java/mage/Mana.java @@ -29,12 +29,9 @@ package mage; import java.io.Serializable; import java.util.Objects; - import mage.constants.ColoredManaSymbol; import mage.constants.ManaType; - import static mage.constants.ManaType.COLORLESS; - import mage.filter.FilterMana; import mage.util.Copyable; import org.apache.log4j.Logger; @@ -51,6 +48,7 @@ public class Mana implements Comparable, Serializable, Copyable { protected int blue; protected int white; protected int black; + protected int generic; protected int colorless; protected int any; protected boolean flag; @@ -70,16 +68,17 @@ public class Mana implements Comparable, Serializable, Copyable { * @param blue total Blue mana to have. * @param white total White mana to have. * @param black total Black mana to have. - * @param colorless total Colorless mana to have. + * @param generic total Generic mana to have. * @param any total Any mana to have. + * @param colorless total Colorless mana to have. */ - public Mana(final int red, final int green, final int blue, final int white, - final int black, final int colorless, final int any) { + public Mana(final int red, final int green, final int blue, final int white, final int black, final int generic, final int any, final int colorless) { this.red = notNegative(red, "Red"); this.green = notNegative(green, "Green"); this.blue = notNegative(blue, "Blue"); this.white = notNegative(white, "White"); this.black = notNegative(black, "Black"); + this.generic = notNegative(generic, "Generic"); this.colorless = notNegative(colorless, "Colorless"); this.any = notNegative(any, "Any"); } @@ -97,6 +96,7 @@ public class Mana implements Comparable, Serializable, Copyable { this.blue = mana.blue; this.white = mana.white; this.black = mana.black; + this.generic = mana.generic; this.colorless = mana.colorless; this.any = mana.any; this.flag = mana.flag; @@ -141,7 +141,7 @@ public class Mana implements Comparable, Serializable, Copyable { * @return a {@link Mana} object with the passed in {@code num} of Red mana. */ public static Mana RedMana(int num) { - return new Mana(notNegative(num, "Red"), 0, 0, 0, 0, 0, 0); + return new Mana(notNegative(num, "Red"), 0, 0, 0, 0, 0, 0, 0); } /** @@ -154,7 +154,7 @@ public class Mana implements Comparable, Serializable, Copyable { * mana. */ public static Mana GreenMana(int num) { - return new Mana(0, notNegative(num, "Green"), 0, 0, 0, 0, 0); + return new Mana(0, notNegative(num, "Green"), 0, 0, 0, 0, 0, 0); } /** @@ -167,7 +167,7 @@ public class Mana implements Comparable, Serializable, Copyable { * mana. */ public static Mana BlueMana(int num) { - return new Mana(0, 0, notNegative(num, "Blue"), 0, 0, 0, 0); + return new Mana(0, 0, notNegative(num, "Blue"), 0, 0, 0, 0, 0); } /** @@ -180,7 +180,7 @@ public class Mana implements Comparable, Serializable, Copyable { * mana. */ public static Mana WhiteMana(int num) { - return new Mana(0, 0, 0, notNegative(num, "White"), 0, 0, 0); + return new Mana(0, 0, 0, notNegative(num, "White"), 0, 0, 0, 0); } /** @@ -193,7 +193,20 @@ public class Mana implements Comparable, Serializable, Copyable { * mana. */ public static Mana BlackMana(int num) { - return new Mana(0, 0, 0, 0, notNegative(num, "Black"), 0, 0); + return new Mana(0, 0, 0, 0, notNegative(num, "Black"), 0, 0, 0); + } + + /** + * Creates a {@link Mana} object with the passed in {@code num} of Generic + * mana. {@code num} can not be a negative value. Negative values will be + * logged and set to 0. + * + * @param num value of Generic mana to create. + * @return a {@link Mana} object with the passed in {@code num} of Generic + * mana. + */ + public static Mana GenericMana(int num) { + return new Mana(0, 0, 0, 0, 0, notNegative(num, "Generic"), 0, 0); } /** @@ -206,7 +219,7 @@ public class Mana implements Comparable, Serializable, Copyable { * mana. */ public static Mana ColorlessMana(int num) { - return new Mana(0, 0, 0, 0, 0, notNegative(num, "Colorless"), 0); + return new Mana(0, 0, 0, 0, 0, 0, 0, notNegative(num, "Colorless")); } /** @@ -220,6 +233,7 @@ public class Mana implements Comparable, Serializable, Copyable { blue += mana.getBlue(); white += mana.getWhite(); black += mana.getBlack(); + generic += mana.getGeneric(); colorless += mana.getColorless(); any += mana.getAny(); } @@ -259,6 +273,13 @@ public class Mana implements Comparable, Serializable, Copyable { black++; } + /** + * Increases the Generic mana by one. + */ + public void increaseGeneric() { + generic++; + } + /** * Increases the Colorless mana by one. */ @@ -277,6 +298,7 @@ public class Mana implements Comparable, Serializable, Copyable { blue -= mana.blue; white -= mana.white; black -= mana.black; + generic -= mana.generic; colorless -= mana.colorless; any -= mana.any; } @@ -284,12 +306,11 @@ public class Mana implements Comparable, Serializable, Copyable { /** * Subtracts the passed in mana values from this instance. The difference * between this and {@code subtract()} is that if we do not have the - * available colorless mana to pay, we take mana from our colored mana - * pools. + * available generic mana to pay, we take mana from our colored mana pools. * * @param mana mana values to subtract * @throws ArithmeticException thrown if there is not enough available - * colored mana to pay the colorless cost + * colored mana to pay the generic cost */ public void subtractCost(final Mana mana) throws ArithmeticException { red -= mana.red; @@ -298,39 +319,44 @@ public class Mana implements Comparable, Serializable, Copyable { white -= mana.white; black -= mana.black; any -= mana.any; + generic -= mana.generic; colorless -= mana.colorless; - while (colorless < 0) { - int oldColorless = colorless; + while (generic < 0) { + int oldColorless = generic; if (red > 0) { red--; - colorless++; + generic++; continue; } if (green > 0) { green--; - colorless++; + generic++; continue; } if (blue > 0) { blue--; - colorless++; + generic++; continue; } if (white > 0) { white--; - colorless++; + generic++; continue; } if (black > 0) { black--; - colorless++; + generic++; + } + if (colorless > 0) { + colorless--; + generic++; } if (any > 0) { any--; - colorless++; + generic++; } - if (oldColorless == colorless) { + if (oldColorless == generic) { throw new ArithmeticException("Not enough mana to pay colorless"); } } @@ -342,7 +368,7 @@ public class Mana implements Comparable, Serializable, Copyable { * @return the total count of all combined mana. */ public int count() { - return red + green + blue + white + black + colorless + any; + return red + green + blue + white + black + generic + colorless + any; } /** @@ -383,6 +409,9 @@ public class Mana implements Comparable, Serializable, Copyable { if (filter.isRed()) { count += red; } + if (filter.isGeneric()) { + count += generic; + } if (filter.isColorless()) { count += colorless; } @@ -398,6 +427,7 @@ public class Mana implements Comparable, Serializable, Copyable { blue = 0; white = 0; black = 0; + generic = 0; colorless = 0; any = 0; } @@ -410,8 +440,11 @@ public class Mana implements Comparable, Serializable, Copyable { @Override public String toString() { StringBuilder sbMana = new StringBuilder(); - if (colorless > 0) { - sbMana.append("{").append(Integer.toString(colorless)).append("}"); + if (generic > 0) { + sbMana.append("{").append(Integer.toString(generic)).append("}"); + } + for (int i = 0; i < colorless; i++) { + sbMana.append("{C}"); } for (int i = 0; i < red; i++) { sbMana.append("{R}"); @@ -490,8 +523,15 @@ public class Mana implements Comparable, Serializable, Copyable { compare.white = 0; } if (compare.colorless < 0) { - int remaining = compare.red + compare.green + compare.black + compare.blue + compare.white + compare.any; - if (compare.colorless + remaining < 0) { + compare.any = compare.getAny() + compare.getColorless(); + if (compare.any < 0) { + return false; + } + compare.colorless = 0; + } + if (compare.generic < 0) { + int remaining = compare.red + compare.green + compare.black + compare.blue + compare.white + compare.colorless + compare.any; + if (compare.generic + remaining < 0) { return false; } } @@ -532,17 +572,23 @@ public class Mana implements Comparable, Serializable, Copyable { compare.any = compare.any - diff; compare.white = compare.white + diff; } - if (compare.colorless < 0) { + if (compare.colorless < 0 && compare.any > 0) { + int diff = Math.min(compare.any, Math.abs(compare.colorless)); + compare.any = compare.any - diff; + compare.colorless = compare.colorless + diff; + } + if (compare.generic < 0) { int remaining = 0; remaining += Math.min(0, compare.red); remaining += Math.min(0, compare.white); remaining += Math.min(0, compare.green); remaining += Math.min(0, compare.black); remaining += Math.min(0, compare.blue); + remaining += Math.min(0, compare.colorless); remaining += Math.min(0, compare.any); if (remaining > 0) { - int diff = Math.min(remaining, Math.abs(compare.colorless)); - compare.colorless = compare.colorless + diff; + int diff = Math.min(remaining, Math.abs(compare.generic)); + compare.generic = compare.generic + diff; } } Mana needed = new Mana(); @@ -564,6 +610,9 @@ public class Mana implements Comparable, Serializable, Copyable { if (compare.colorless < 0) { needed.colorless = Math.abs(compare.colorless); } + if (compare.generic < 0) { + needed.generic = Math.abs(compare.generic); + } return needed; } @@ -662,6 +711,25 @@ public class Mana implements Comparable, Serializable, Copyable { this.black = notNegative(black, "Black"); } + /** + * Returns total Generic mana. + * + * @return total Generic mana. + */ + public int getGeneric() { + return generic; + } + + /** + * Sets the total Generic mana. Can not be negative. Negative values will be + * logged and set to 0. + * + * @param generic total Generic mana. + */ + public void setGeneric(int generic) { + this.generic = notNegative(generic, "Generic"); + } + /** * Returns total Colorless mana. * @@ -734,7 +802,10 @@ public class Mana implements Comparable, Serializable, Copyable { if (mana.green > 0 && this.green > 0) { return true; } - if (mana.colorless > 0 && this.count() > 0) { + if (mana.colorless > 0 && this.colorless > 0) { + return true; + } + if (mana.generic > 0 && this.count() > 0) { return true; } @@ -789,7 +860,7 @@ public class Mana implements Comparable, Serializable, Copyable { case WHITE: return white; case COLORLESS: - return colorless; + return generic + colorless; } return 0; } @@ -847,6 +918,7 @@ public class Mana implements Comparable, Serializable, Copyable { this.blue = mana.blue; this.black = mana.black; this.colorless = mana.colorless; + this.generic = mana.generic; } /** @@ -862,7 +934,8 @@ public class Mana implements Comparable, Serializable, Copyable { && this.white == mana.white && this.blue == mana.blue && this.black == mana.black - && this.colorless == mana.colorless; + && this.colorless == mana.colorless + && this.generic == mana.generic; } /** @@ -879,14 +952,15 @@ public class Mana implements Comparable, Serializable, Copyable { && this.white >= mana.white && this.black >= mana.black && this.red >= mana.red - && (this.colorless >= mana.colorless - || this.countColored() >= mana.countColored() + mana.colorless); + && this.colorless >= mana.colorless + && (this.generic >= mana.generic + || this.countColored() >= mana.countColored() + mana.generic); } /** * Returns the mana that is more colored or has a greater amount but does - * not contain one less mana in any color but colorless if you call with + * not contain one less mana in any color but generic if you call with * {1}{W}{R} and {G}{W}{R} you get back {G}{W}{R} if you call with {G}{W}{R} * and {G}{W}{R} you get back {G}{W}{R} if you call with {G}{W}{B} and * {G}{W}{R} you get back null @@ -910,6 +984,7 @@ public class Mana implements Comparable, Serializable, Copyable { || lessMana.getGreen() > moreMana.getGreen() || lessMana.getBlue() > moreMana.getBlue() || lessMana.getBlack() > moreMana.getBlack() + || lessMana.getColorless() > moreMana.getColorless() || lessMana.getAny() > moreMana.getAny()) { return null; } @@ -970,6 +1045,9 @@ public class Mana implements Comparable, Serializable, Copyable { if (colorless != mana.colorless) { return false; } + if (generic != mana.generic) { + return false; + } if (any != mana.any) { return false; } @@ -984,6 +1062,7 @@ public class Mana implements Comparable, Serializable, Copyable { result = 31 * result + blue; result = 31 * result + white; result = 31 * result + black; + result = 31 * result + generic; result = 31 * result + colorless; result = 31 * result + any; result = 31 * result + (flag ? 1 : 0); diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index c4d7e73616a..cfd9f99555f 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -229,11 +229,11 @@ public abstract class AbilityImpl implements Ability { game.resetShortLivingLKI(); /** * game.applyEffects() has to be done at least for every effect - * that moves cards/permanent between zones, or chnages control + * that moves cards/permanent between zones, or changes control * of objects so Static effects work as intened if dependant * from the moved objects zone it is in Otherwise for example - * were static abilities with replacement effects deactivated to - * late Example: + * were static abilities with replacement effects deactivated + * too late Example: * {@link org.mage.test.cards.replacement.DryadMilitantTest#testDiesByDestroy testDiesByDestroy} */ if (effect.applyEffectsAfter()) { @@ -379,7 +379,7 @@ public abstract class AbilityImpl implements Ability { } // this is a hack to prevent mana abilities with mana costs from causing endless loops - pay other costs first - if (this instanceof ManaAbility && !costs.pay(this, game, sourceId, controllerId, noMana)) { + if (this instanceof ManaAbility && !costs.pay(this, game, sourceId, controllerId, noMana, null)) { logger.debug("activate mana ability failed - non mana costs"); return false; } @@ -399,13 +399,13 @@ public abstract class AbilityImpl implements Ability { if (!useAlternativeCost(game)) { // old way still used? //20100716 - 601.2f (noMana is not used here, because mana costs were cleared for this ability before adding additional costs and applying cost modification effects) - if (!manaCostsToPay.pay(this, game, sourceId, activatorId, false)) { + if (!manaCostsToPay.pay(this, game, sourceId, activatorId, false, null)) { return false; // cancel during mana payment } } //20100716 - 601.2g - if (!costs.pay(this, game, sourceId, activatorId, noMana)) { + if (!costs.pay(this, game, sourceId, activatorId, noMana, null)) { logger.debug("activate failed - non mana costs"); return false; } @@ -554,7 +554,7 @@ public abstract class AbilityImpl implements Ability { xValue = controller.announceXMana(variableManaCost.getMinX(), variableManaCost.getMaxX(), "Announce the value for " + variableManaCost.getText(), game, this); int amountMana = xValue * variableManaCost.getMultiplier(); StringBuilder manaString = threadLocalBuilder.get(); - if (variableManaCost.getFilter() == null || variableManaCost.getFilter().isColorless()) { + if (variableManaCost.getFilter() == null || variableManaCost.getFilter().isGeneric()) { manaString.append("{").append(amountMana).append("}"); } else { String manaSymbol = null; @@ -596,7 +596,7 @@ public abstract class AbilityImpl implements Ability { for (AlternativeCost cost : alternativeCosts) { if (cost.isAvailable(game, this)) { if (game.getPlayer(this.controllerId).chooseUse(Outcome.Neutral, "Use alternative cost " + cost.getName(), this, game)) { - return cost.pay(this, game, sourceId, controllerId, false); + return cost.pay(this, game, sourceId, controllerId, false, null); } } } diff --git a/Mage/src/main/java/mage/abilities/common/CastCommanderAbility.java b/Mage/src/main/java/mage/abilities/common/CastCommanderAbility.java index faaf804a0e6..b980bd45ca6 100644 --- a/Mage/src/main/java/mage/abilities/common/CastCommanderAbility.java +++ b/Mage/src/main/java/mage/abilities/common/CastCommanderAbility.java @@ -27,7 +27,6 @@ */ package mage.abilities.common; - import mage.abilities.SpellAbility; import mage.cards.Card; import mage.constants.SpellAbilityType; @@ -57,22 +56,14 @@ public class CastCommanderAbility extends SpellAbility { public boolean activate(Game game, boolean noMana) { if (super.activate(game, noMana)) { // save amount of times commander was cast - Integer castCount = (Integer)game.getState().getValue(sourceId + "_castCount"); - if(castCount != null){ - castCount++; - game.getState().setValue(sourceId + "_castCount", castCount); - } - else { - castCount = 1; - game.getState().setValue(sourceId + "_castCount", castCount); - } + Integer castCount = (Integer) game.getState().getValue(sourceId + "_castCount"); + castCount++; + game.getState().setValue(sourceId + "_castCount", castCount); return true; } return false; } - - @Override public CastCommanderAbility copy() { return new CastCommanderAbility(this); diff --git a/Mage/src/main/java/mage/abilities/common/CastOnlyDuringPhaseStepSourceAbility.java b/Mage/src/main/java/mage/abilities/common/CastOnlyDuringPhaseStepSourceAbility.java new file mode 100644 index 00000000000..66794eb59dc --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/CastOnlyDuringPhaseStepSourceAbility.java @@ -0,0 +1,56 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.common; + +import mage.abilities.condition.Condition; +import mage.abilities.effects.common.ruleModifying.CastOnlyDuringPhaseStepSourceEffect; +import mage.constants.PhaseStep; +import mage.constants.TurnPhase; +import mage.constants.Zone; + +/** + * + * @author LevelX2 + */ +public class CastOnlyDuringPhaseStepSourceAbility extends SimpleStaticAbility { + + public CastOnlyDuringPhaseStepSourceAbility(TurnPhase turnPhase) { + this(turnPhase, null, null); + } + + public CastOnlyDuringPhaseStepSourceAbility(TurnPhase turnPhase, Condition condition) { + this(turnPhase, null, condition); + } + + public CastOnlyDuringPhaseStepSourceAbility(PhaseStep phaseStep) { + this(null, phaseStep, null); + } + + public CastOnlyDuringPhaseStepSourceAbility(PhaseStep phaseStep, Condition condition) { + this(null, phaseStep, condition); + } + + public CastOnlyDuringPhaseStepSourceAbility(TurnPhase turnPhase, PhaseStep phaseStep, Condition condition) { + this(turnPhase, phaseStep, condition, null); + } + + public CastOnlyDuringPhaseStepSourceAbility(TurnPhase turnPhase, PhaseStep phaseStep, Condition condition, String effectText) { + super(Zone.ALL, new CastOnlyDuringPhaseStepSourceEffect(turnPhase, phaseStep, condition)); + this.setRuleAtTheTop(true); + if (effectText != null) { + getEffects().get(0).setText(effectText); + } + } + + private CastOnlyDuringPhaseStepSourceAbility(final CastOnlyDuringPhaseStepSourceAbility ability) { + super(ability); + } + + @Override + public CastOnlyDuringPhaseStepSourceAbility copy() { + return new CastOnlyDuringPhaseStepSourceAbility(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/common/GemstoneCavernsAbility.java b/Mage/src/main/java/mage/abilities/common/GemstoneCavernsAbility.java index 47e4057a5f3..4dc853d6e12 100644 --- a/Mage/src/main/java/mage/abilities/common/GemstoneCavernsAbility.java +++ b/Mage/src/main/java/mage/abilities/common/GemstoneCavernsAbility.java @@ -93,7 +93,7 @@ class GemstoneCavernsEffect extends OneShotEffect { permanent.addCounters(CounterType.LUCK.createInstance(), game); Cost cost = new ExileFromHandCost(new TargetCardInHand()); if (cost.canPay(source, source.getSourceId(), source.getControllerId(), game)) { - cost.pay(source, game, source.getSourceId(), source.getControllerId(), true); + cost.pay(source, game, source.getSourceId(), source.getControllerId(), true, null); } } } diff --git a/Mage/src/main/java/mage/abilities/common/delayed/PactDelayedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/delayed/PactDelayedTriggeredAbility.java index e922c99382e..1545aeeda01 100644 --- a/Mage/src/main/java/mage/abilities/common/delayed/PactDelayedTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/delayed/PactDelayedTriggeredAbility.java @@ -100,7 +100,7 @@ class PactEffect extends OneShotEffect { if (player != null) { if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "?", source, game)) { cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)){ + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)){ return true; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/AfterBlockersAreDeclaredCondition.java b/Mage/src/main/java/mage/abilities/condition/common/AfterBlockersAreDeclaredCondition.java new file mode 100644 index 00000000000..8ea96295cf7 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/AfterBlockersAreDeclaredCondition.java @@ -0,0 +1,37 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.constants.PhaseStep; +import mage.game.Game; + +/** + * This condtion does not check that the turnPhase is combat. You have to check + * this if needed on another place. + * + * @author LevelX2 + */ +public class AfterBlockersAreDeclaredCondition implements Condition { + + private static final AfterBlockersAreDeclaredCondition fInstance = new AfterBlockersAreDeclaredCondition(); + + public static Condition getInstance() { + return fInstance; + } + + @Override + public boolean apply(Game game, Ability source) { + return !(game.getStep().getType().equals(PhaseStep.BEGIN_COMBAT) + || game.getStep().getType().equals(PhaseStep.DECLARE_ATTACKERS)); + } + + @Override + public String toString() { + return "after blockers are declared"; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/AfterUpkeepStepCondtion.java b/Mage/src/main/java/mage/abilities/condition/common/AfterUpkeepStepCondtion.java new file mode 100644 index 00000000000..cb711abad2c --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/AfterUpkeepStepCondtion.java @@ -0,0 +1,35 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.constants.PhaseStep; +import mage.game.Game; + +/** + * + * @author LevelX2 + */ +public class AfterUpkeepStepCondtion implements Condition { + + private static final AfterUpkeepStepCondtion fInstance = new AfterUpkeepStepCondtion(); + + public static Condition getInstance() { + return fInstance; + } + + @Override + public boolean apply(Game game, Ability source) { + return !(game.getStep().getType().equals(PhaseStep.UNTAP) + || game.getStep().getType().equals(PhaseStep.UPKEEP)); + } + + @Override + public String toString() { + return "after upkeep step"; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/BeforeAttackersAreDeclaredCondition.java b/Mage/src/main/java/mage/abilities/condition/common/BeforeAttackersAreDeclaredCondition.java new file mode 100644 index 00000000000..34904e23b98 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/BeforeAttackersAreDeclaredCondition.java @@ -0,0 +1,33 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.game.Game; + +/** + * + * @author LevelX2 + */ +public class BeforeAttackersAreDeclaredCondition implements Condition { + + private static final BeforeAttackersAreDeclaredCondition fInstance = new BeforeAttackersAreDeclaredCondition(); + + public static Condition getInstance() { + return fInstance; + } + + @Override + public boolean apply(Game game, Ability source) { + return !game.getTurn().isDeclareAttackersStepStarted(); + } + + @Override + public String toString() { + return "before attackers are declared"; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/BeforeBlockersAreDeclaredCondition.java b/Mage/src/main/java/mage/abilities/condition/common/BeforeBlockersAreDeclaredCondition.java new file mode 100644 index 00000000000..4c4798cc355 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/BeforeBlockersAreDeclaredCondition.java @@ -0,0 +1,39 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.constants.PhaseStep; +import mage.game.Game; + +/** + * This condtion does not check that the turnPhase is combat. You have to check + * this if needed on another place. + * + * @author LevelX2 + */ +public class BeforeBlockersAreDeclaredCondition implements Condition { + + private static final BeforeBlockersAreDeclaredCondition fInstance = new BeforeBlockersAreDeclaredCondition(); + + public static Condition getInstance() { + return fInstance; + } + + @Override + public boolean apply(Game game, Ability source) { + return !(game.getStep().getType().equals(PhaseStep.DECLARE_BLOCKERS) + || game.getStep().getType().equals(PhaseStep.FIRST_COMBAT_DAMAGE) + || game.getStep().getType().equals(PhaseStep.COMBAT_DAMAGE) + || game.getStep().getType().equals(PhaseStep.END_COMBAT)); + } + + @Override + public String toString() { + return "before blockers are declared"; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/OnOpponentsTurnCondition.java b/Mage/src/main/java/mage/abilities/condition/common/OnOpponentsTurnCondition.java new file mode 100644 index 00000000000..41d43c8cd9f --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/OnOpponentsTurnCondition.java @@ -0,0 +1,33 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.game.Game; + +/** + * + * @author LevelX2 + */ +public class OnOpponentsTurnCondition implements Condition { + + private static final OnOpponentsTurnCondition fInstance = new OnOpponentsTurnCondition(); + + public static Condition getInstance() { + return fInstance; + } + + @Override + public boolean apply(Game game, Ability source) { + return !game.getOpponents(source.getControllerId()).contains(game.getActivePlayerId()); + } + + @Override + public String toString() { + return "on an opponent's turn"; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/ProwlCondition.java b/Mage/src/main/java/mage/abilities/condition/common/ProwlCondition.java index c539a4717a8..1f7091e3285 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/ProwlCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/ProwlCondition.java @@ -24,8 +24,7 @@ * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. -*/ - + */ package mage.abilities.condition.common; import mage.abilities.Ability; @@ -35,16 +34,16 @@ import mage.cards.Card; import mage.game.Game; /** - * Checks if a the spell was cast with the alternate prowl costs + * Checks if a the spell was cast with the alternate prowl costs * * @author LevelX2 */ - public class ProwlCondition implements Condition { private static ProwlCondition fInstance = null; - private ProwlCondition() {} + private ProwlCondition() { + } public static Condition getInstance() { if (fInstance == null) { @@ -57,9 +56,9 @@ public class ProwlCondition implements Condition { public boolean apply(Game game, Ability source) { Card card = game.getCard(source.getSourceId()); if (card != null) { - for (Ability ability: card.getAbilities()) { + for (Ability ability : card.getAbilities()) { if (ability instanceof ProwlAbility) { - if(((ProwlAbility) ability).isActivated(source, game)) { + if (((ProwlAbility) ability).isActivated(source, game)) { return true; } } @@ -67,4 +66,10 @@ public class ProwlCondition implements Condition { } return false; } + + @Override + public String toString() { + return "{source}'s prowl cost was paid"; + } + } diff --git a/Mage/src/main/java/mage/abilities/costs/CompositeCost.java b/Mage/src/main/java/mage/abilities/costs/CompositeCost.java index 1d497d43793..eed48cebd2b 100644 --- a/Mage/src/main/java/mage/abilities/costs/CompositeCost.java +++ b/Mage/src/main/java/mage/abilities/costs/CompositeCost.java @@ -45,7 +45,13 @@ public class CompositeCost implements Cost { @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { - return firstCost.pay(ability, game, sourceId, controllerId, noMana) && secondCost.pay(ability, game, sourceId, controllerId, noMana); + return pay(ability, game, sourceId, controllerId, noMana, this); + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { + return firstCost.pay(ability, game, sourceId, controllerId, noMana, costToPay) + && secondCost.pay(ability, game, sourceId, controllerId, noMana, costToPay); } @Override diff --git a/Mage/src/main/java/mage/abilities/costs/Cost.java b/Mage/src/main/java/mage/abilities/costs/Cost.java index 885ff8376fd..d7b67ee921a 100644 --- a/Mage/src/main/java/mage/abilities/costs/Cost.java +++ b/Mage/src/main/java/mage/abilities/costs/Cost.java @@ -45,6 +45,8 @@ public interface Cost extends Serializable { boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana); + boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay); + boolean isPaid(); void clearPaid(); diff --git a/Mage/src/main/java/mage/abilities/costs/CostImpl.java b/Mage/src/main/java/mage/abilities/costs/CostImpl.java index 57f6c5a7471..909de0a541a 100644 --- a/Mage/src/main/java/mage/abilities/costs/CostImpl.java +++ b/Mage/src/main/java/mage/abilities/costs/CostImpl.java @@ -28,6 +28,8 @@ package mage.abilities.costs; import java.util.UUID; +import mage.abilities.Ability; +import mage.game.Game; import mage.target.Target; import mage.target.Targets; @@ -51,6 +53,11 @@ public abstract class CostImpl implements Cost { this.targets = cost.targets.copy(); } + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + return pay(ability, game, sourceId, controllerId, noMana, this); + } + @Override public String getText() { return text; diff --git a/Mage/src/main/java/mage/abilities/costs/CostsImpl.java b/Mage/src/main/java/mage/abilities/costs/CostsImpl.java index df64087a373..2d070ac91a1 100644 --- a/Mage/src/main/java/mage/abilities/costs/CostsImpl.java +++ b/Mage/src/main/java/mage/abilities/costs/CostsImpl.java @@ -99,10 +99,15 @@ public class CostsImpl extends ArrayList implements Costs @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + return pay(ability, game, sourceId, controllerId, noMana, this); + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { if (this.size() > 0) { while (!isPaid()) { T cost = getFirstUnpaid(); - if (!cost.pay(ability, game, sourceId, controllerId, noMana)) { + if (!cost.pay(ability, game, sourceId, controllerId, noMana, costToPay)) { return false; } } diff --git a/Mage/src/main/java/mage/abilities/costs/OrCost.java b/Mage/src/main/java/mage/abilities/costs/OrCost.java index 0707741244f..07f26e24304 100644 --- a/Mage/src/main/java/mage/abilities/costs/OrCost.java +++ b/Mage/src/main/java/mage/abilities/costs/OrCost.java @@ -78,6 +78,11 @@ public class OrCost implements Cost { @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + return pay(ability, game, sourceId, controllerId, noMana, this); + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { selectedCost = null; // if only one can be paid select it if (!firstCost.canPay(ability, sourceId, controllerId, game)) { @@ -105,7 +110,7 @@ public class OrCost implements Cost { if (selectedCost == null) { return false; } - return selectedCost.pay(ability, game, sourceId, controllerId, noMana); + return selectedCost.pay(ability, game, sourceId, controllerId, noMana, costToPay); } diff --git a/Mage/src/main/java/mage/abilities/costs/VariableCostImpl.java b/Mage/src/main/java/mage/abilities/costs/VariableCostImpl.java index e1002b91eb4..8290bc2d8bf 100644 --- a/Mage/src/main/java/mage/abilities/costs/VariableCostImpl.java +++ b/Mage/src/main/java/mage/abilities/costs/VariableCostImpl.java @@ -124,6 +124,11 @@ public abstract class VariableCostImpl implements Cost, VariableCost { return this.id; } + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + return pay(ability, game, sourceId, controllerId, noMana, this); + } + @Override public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { return true; /* not used */ @@ -131,7 +136,7 @@ public abstract class VariableCostImpl implements Cost, VariableCost { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { return true; /* not used */ } diff --git a/Mage/src/main/java/mage/abilities/costs/common/ControlPermanentCost.java b/Mage/src/main/java/mage/abilities/costs/common/ControlPermanentCost.java index 6f2b4558cc2..aca24a91659 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ControlPermanentCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ControlPermanentCost.java @@ -6,6 +6,7 @@ import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import java.util.UUID; +import mage.abilities.costs.Cost; public class ControlPermanentCost extends CostImpl { private FilterControlledPermanent filter; @@ -26,7 +27,7 @@ public class ControlPermanentCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { this.paid = true; return paid; } diff --git a/Mage/src/main/java/mage/abilities/costs/common/DiscardHandCost.java b/Mage/src/main/java/mage/abilities/costs/common/DiscardHandCost.java index e3d533fc756..53943eefa13 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/DiscardHandCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/DiscardHandCost.java @@ -30,6 +30,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.cards.Card; import mage.game.Game; @@ -61,7 +62,7 @@ public class DiscardHandCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player player = game.getPlayer(controllerId); if (player != null) { for (Card card : player.getHand().getCards(game)) { diff --git a/Mage/src/main/java/mage/abilities/costs/common/DiscardSourceCost.java b/Mage/src/main/java/mage/abilities/costs/common/DiscardSourceCost.java index 88d1331d149..ecdca74662e 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/DiscardSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/DiscardSourceCost.java @@ -30,6 +30,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.cards.Card; import mage.game.Game; @@ -53,7 +54,7 @@ public class DiscardSourceCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player player = game.getPlayer(controllerId); if (player != null) { Card card = player.getHand().get(sourceId, game); diff --git a/Mage/src/main/java/mage/abilities/costs/common/DiscardTargetCost.java b/Mage/src/main/java/mage/abilities/costs/common/DiscardTargetCost.java index da388060961..d34f2c49c7e 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/DiscardTargetCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/DiscardTargetCost.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.cards.Card; import mage.constants.Outcome; @@ -64,7 +65,7 @@ public class DiscardTargetCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { this.cards.clear(); this.targets.clearChosen();; Player player = game.getPlayer(controllerId); diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileFromGraveCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileFromGraveCost.java index 7ad275dfa39..6e267bcc56f 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileFromGraveCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileFromGraveCost.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.cards.Card; import mage.cards.Cards; @@ -83,7 +84,7 @@ public class ExileFromGraveCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { if (targets.choose(Outcome.Exile, controllerId, sourceId, game)) { diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileFromHandCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileFromHandCost.java index 6f696804f85..c5264037392 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileFromHandCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileFromHandCost.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.mana.VariableManaCost; import mage.cards.Card; @@ -76,7 +77,7 @@ public class ExileFromHandCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { if (targets.choose(Outcome.Exile, controllerId, sourceId, game)) { Player player = game.getPlayer(controllerId); int cmc = 0; diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileFromStackCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileFromStackCost.java index ec143a97e72..d104ae85457 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileFromStackCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileFromStackCost.java @@ -29,6 +29,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.constants.Outcome; import mage.game.Game; @@ -52,7 +53,7 @@ public class ExileFromStackCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { if (targets.choose(Outcome.Exile, controllerId, sourceId, game)) { Player player = game.getPlayer(controllerId); for (UUID targetId : targets.get(0).getTargets()) { diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileFromTopOfLibraryCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileFromTopOfLibraryCost.java index cee479c6fd7..9a2a3c5e981 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileFromTopOfLibraryCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileFromTopOfLibraryCost.java @@ -29,6 +29,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.constants.Zone; import mage.game.Game; @@ -64,7 +65,7 @@ public class ExileFromTopOfLibraryCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { controller.moveCards(controller.getLibrary().getTopCards(game, amount), Zone.EXILED, ability, game); diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileOpponentsCardFromExileToGraveyardCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileOpponentsCardFromExileToGraveyardCost.java index 061767a1124..8448c46939b 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileOpponentsCardFromExileToGraveyardCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileOpponentsCardFromExileToGraveyardCost.java @@ -7,6 +7,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.cards.Card; import mage.constants.Outcome; @@ -38,7 +39,7 @@ public class ExileOpponentsCardFromExileToGraveyardCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { FilterCard filter = new FilterCard(); diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileSourceCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileSourceCost.java index 8db34d265d8..9afd2fbd7bf 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileSourceCost.java @@ -30,6 +30,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.cards.Card; import mage.game.Game; @@ -66,7 +67,7 @@ public class ExileSourceCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { MageObject sourceObject = ability.getSourceObject(game); Player controller = game.getPlayer(controllerId); if (controller != null && sourceObject != null && (sourceObject instanceof Card)) { diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileSourceFromGraveCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileSourceFromGraveCost.java index ff72d067267..6432d08ced5 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileSourceFromGraveCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileSourceFromGraveCost.java @@ -29,6 +29,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.cards.Card; import mage.constants.Zone; @@ -50,7 +51,7 @@ public class ExileSourceFromGraveCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { Card card = game.getCard(sourceId); diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileTargetCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileTargetCost.java index f650f470852..073c121112b 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileTargetCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileTargetCost.java @@ -32,6 +32,7 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.constants.Outcome; import mage.constants.Zone; @@ -64,7 +65,7 @@ public class ExileTargetCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { if (targets.choose(Outcome.Exile, controllerId, sourceId, game)) { for (UUID targetId: targets.get(0).getTargets()) { Permanent permanent = game.getPermanent(targetId); diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileTopCardOfGraveyardCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileTopCardOfGraveyardCost.java index 997753dc722..dfb871086e3 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileTopCardOfGraveyardCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileTopCardOfGraveyardCost.java @@ -7,6 +7,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.cards.Card; import mage.constants.Zone; @@ -41,7 +42,7 @@ public class ExileTopCardOfGraveyardCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if(controller != null) { Card topCard = null; diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileTopCreatureCardOfGraveyardCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileTopCreatureCardOfGraveyardCost.java index 00f0b18eef0..3781f3e4ed7 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileTopCreatureCardOfGraveyardCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileTopCreatureCardOfGraveyardCost.java @@ -7,6 +7,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.cards.Card; import mage.constants.CardType; @@ -42,7 +43,7 @@ public class ExileTopCreatureCardOfGraveyardCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if(controller != null) { Card topCard = null; diff --git a/Mage/src/main/java/mage/abilities/costs/common/GainLifeOpponentCost.java b/Mage/src/main/java/mage/abilities/costs/common/GainLifeOpponentCost.java index 31e0eaf3ed7..69204293dcd 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/GainLifeOpponentCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/GainLifeOpponentCost.java @@ -8,6 +8,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.constants.Outcome; import mage.constants.TargetController; @@ -59,7 +60,7 @@ public class GainLifeOpponentCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { TargetPlayer target = new TargetPlayer(1, 1, true, filter); diff --git a/Mage/src/main/java/mage/abilities/costs/common/GainLifePlayersCost.java b/Mage/src/main/java/mage/abilities/costs/common/GainLifePlayersCost.java index cc58f40833d..825f4f88a4e 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/GainLifePlayersCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/GainLifePlayersCost.java @@ -30,6 +30,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.game.Game; import mage.players.Player; @@ -71,7 +72,7 @@ public class GainLifePlayersCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { for (UUID playerId: controller.getInRange()) { diff --git a/Mage/src/main/java/mage/abilities/costs/common/PayLifeCost.java b/Mage/src/main/java/mage/abilities/costs/common/PayLifeCost.java index 39c81213d96..cb8eb5238bc 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/PayLifeCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/PayLifeCost.java @@ -35,6 +35,7 @@ import mage.abilities.dynamicvalue.common.StaticValue; import mage.game.Game; import java.util.UUID; +import mage.abilities.costs.Cost; /** * @@ -73,7 +74,7 @@ public class PayLifeCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { int lifeToPayAmount = amount.calculate(game, ability, null); this.paid = game.getPlayer(controllerId).loseLife(lifeToPayAmount, game) == lifeToPayAmount; return paid; diff --git a/Mage/src/main/java/mage/abilities/costs/common/PayLoyaltyCost.java b/Mage/src/main/java/mage/abilities/costs/common/PayLoyaltyCost.java index 16c0c4d959a..04e96a416e8 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/PayLoyaltyCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/PayLoyaltyCost.java @@ -31,6 +31,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.counters.CounterType; import mage.game.Game; @@ -64,7 +65,7 @@ public class PayLoyaltyCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent planeswalker = game.getPermanent(sourceId); if (planeswalker.getCounters().getCount(CounterType.LOYALTY) + amount >= 0 && planeswalker.canLoyaltyBeUsed(game)) { if (amount > 0) { diff --git a/Mage/src/main/java/mage/abilities/costs/common/PutCountersSourceCost.java b/Mage/src/main/java/mage/abilities/costs/common/PutCountersSourceCost.java index e715c0d69d2..69385fd2006 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/PutCountersSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/PutCountersSourceCost.java @@ -30,6 +30,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.counters.Counter; import mage.game.Game; @@ -69,7 +70,7 @@ public class PutCountersSourceCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { permanent.addCounters(counter, game); diff --git a/Mage/src/main/java/mage/abilities/costs/common/PutTopCardOfYourLibraryToGraveyardCost.java b/Mage/src/main/java/mage/abilities/costs/common/PutTopCardOfYourLibraryToGraveyardCost.java index 2b1b4f28595..0e135306341 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/PutTopCardOfYourLibraryToGraveyardCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/PutTopCardOfYourLibraryToGraveyardCost.java @@ -29,6 +29,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.constants.Zone; import mage.game.Game; @@ -54,7 +55,7 @@ public class PutTopCardOfYourLibraryToGraveyardCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player player = game.getPlayer(controllerId); if (player != null && player.getLibrary().size() >= numberOfCards) { paid = true; diff --git a/Mage/src/main/java/mage/abilities/costs/common/RemoveCounterCost.java b/Mage/src/main/java/mage/abilities/costs/common/RemoveCounterCost.java index 0167f67807f..67a6d3324e3 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/RemoveCounterCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/RemoveCounterCost.java @@ -31,6 +31,7 @@ import java.util.HashSet; import java.util.Set; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.choices.Choice; import mage.choices.ChoiceImpl; @@ -79,7 +80,7 @@ public class RemoveCounterCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { paid = false; int countersRemoved = 0; Player controller = game.getPlayer(controllerId); diff --git a/Mage/src/main/java/mage/abilities/costs/common/RemoveCountersSourceCost.java b/Mage/src/main/java/mage/abilities/costs/common/RemoveCountersSourceCost.java index 4e035be6259..ebf92959f44 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/RemoveCountersSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/RemoveCountersSourceCost.java @@ -30,6 +30,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.counters.Counter; import mage.game.Game; @@ -70,7 +71,7 @@ public class RemoveCountersSourceCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null && permanent.getCounters().getCount(name) >= amount) { permanent.removeCounters(name, amount, game); diff --git a/Mage/src/main/java/mage/abilities/costs/common/RemoveVariableCountersTargetCost.java b/Mage/src/main/java/mage/abilities/costs/common/RemoveVariableCountersTargetCost.java index ff9bb65ce69..86087203893 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/RemoveVariableCountersTargetCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/RemoveVariableCountersTargetCost.java @@ -72,7 +72,7 @@ public class RemoveVariableCountersTargetCost extends VariableCostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { return paid; } diff --git a/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandChosenControlledPermanentCost.java b/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandChosenControlledPermanentCost.java index 2366e9d7dfe..7045e9dfebe 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandChosenControlledPermanentCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandChosenControlledPermanentCost.java @@ -31,6 +31,7 @@ import java.util.HashSet; import java.util.Set; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.cards.Card; import mage.constants.Outcome; @@ -61,7 +62,7 @@ public class ReturnToHandChosenControlledPermanentCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { if (targets.choose(Outcome.ReturnToHand, controllerId, sourceId, game)) { diff --git a/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandFromBattlefieldSourceCost.java b/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandFromBattlefieldSourceCost.java index 5f4d4c6396a..4ee56c0fbf6 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandFromBattlefieldSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandFromBattlefieldSourceCost.java @@ -29,6 +29,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.constants.Zone; import mage.game.Game; @@ -49,7 +50,7 @@ public class ReturnToHandFromBattlefieldSourceCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(sourceId); Player controller = game.getPlayer(controllerId); if (permanent == null || controller == null) { diff --git a/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandFromGraveyardCost.java b/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandFromGraveyardCost.java index e12103dc964..767d60cb32f 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandFromGraveyardCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandFromGraveyardCost.java @@ -31,6 +31,7 @@ import java.util.LinkedHashSet; import java.util.Set; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.cards.Card; import mage.constants.Outcome; @@ -59,7 +60,7 @@ public class ReturnToHandFromGraveyardCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { if (targets.choose(Outcome.ReturnToHand, controllerId, sourceId, game)) { diff --git a/Mage/src/main/java/mage/abilities/costs/common/RevealHandSourceControllerCost.java b/Mage/src/main/java/mage/abilities/costs/common/RevealHandSourceControllerCost.java index 3850e142e29..de88fc13546 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/RevealHandSourceControllerCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/RevealHandSourceControllerCost.java @@ -30,6 +30,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.game.Game; import mage.players.Player; @@ -50,7 +51,7 @@ public class RevealHandSourceControllerCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); MageObject sourceObject = game.getObject(sourceId); if (controller != null && sourceObject != null) { diff --git a/Mage/src/main/java/mage/abilities/costs/common/RevealSourceFromYourHandCost.java b/Mage/src/main/java/mage/abilities/costs/common/RevealSourceFromYourHandCost.java index d48de68a1e6..fb6afbbde6d 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/RevealSourceFromYourHandCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/RevealSourceFromYourHandCost.java @@ -29,6 +29,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.cards.Card; import mage.cards.Cards; @@ -54,7 +55,7 @@ public class RevealSourceFromYourHandCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { paid = false; Player player = game.getPlayer(controllerId); if (player != null) { diff --git a/Mage/src/main/java/mage/abilities/costs/common/RevealTargetFromHandCost.java b/Mage/src/main/java/mage/abilities/costs/common/RevealTargetFromHandCost.java index a5ef7e33cba..f47c7367b35 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/RevealTargetFromHandCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/RevealTargetFromHandCost.java @@ -33,6 +33,7 @@ import java.util.List; import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.cards.Card; import mage.cards.Cards; @@ -62,7 +63,7 @@ public class RevealTargetFromHandCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { if (targets.choose(Outcome.Benefit, controllerId, sourceId, game)) { convertedManaCosts = 0; numberCardsRevealed = 0; diff --git a/Mage/src/main/java/mage/abilities/costs/common/SacrificeAllCost.java b/Mage/src/main/java/mage/abilities/costs/common/SacrificeAllCost.java index be3a652f472..de8595052eb 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/SacrificeAllCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/SacrificeAllCost.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.filter.FilterPermanent; import mage.game.Game; @@ -59,7 +60,7 @@ public class SacrificeAllCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, controllerId, game)) { permanents.add(permanent.copy()); permanent.sacrifice(sourceId, game); diff --git a/Mage/src/main/java/mage/abilities/costs/common/SacrificeSourceCost.java b/Mage/src/main/java/mage/abilities/costs/common/SacrificeSourceCost.java index 7db5a6d0d91..00af162be30 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/SacrificeSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/SacrificeSourceCost.java @@ -1,40 +1,39 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.costs.common; +import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.game.Game; import mage.game.permanent.Permanent; -import java.util.UUID; - /** * * @author BetaSteward_at_googlemail.com @@ -50,7 +49,7 @@ public class SacrificeSourceCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { paid = permanent.sacrifice(sourceId, game); diff --git a/Mage/src/main/java/mage/abilities/costs/common/SacrificeTargetCost.java b/Mage/src/main/java/mage/abilities/costs/common/SacrificeTargetCost.java index be90768d5fd..19f83fdb684 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/SacrificeTargetCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/SacrificeTargetCost.java @@ -32,6 +32,7 @@ import java.util.List; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.ActivatedAbilityImpl; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.constants.AbilityType; import mage.constants.Outcome; @@ -66,7 +67,7 @@ public class SacrificeTargetCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { UUID activator = controllerId; if (ability.getAbilityType().equals(AbilityType.ACTIVATED) || ability.getAbilityType().equals(AbilityType.SPECIAL_ACTION)) { activator = ((ActivatedAbilityImpl) ability).getActivatorId(); diff --git a/Mage/src/main/java/mage/abilities/costs/common/TapSourceCost.java b/Mage/src/main/java/mage/abilities/costs/common/TapSourceCost.java index 2faab014371..e53a75282b3 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/TapSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/TapSourceCost.java @@ -30,6 +30,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.constants.AsThoughEffectType; import mage.game.Game; @@ -50,7 +51,7 @@ public class TapSourceCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { paid = permanent.tap(game); 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 8f448eaa093..38d2c5c4207 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/TapTargetCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/TapTargetCost.java @@ -30,6 +30,7 @@ package mage.abilities.costs.common; import java.util.List; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.constants.Outcome; import mage.game.Game; @@ -61,7 +62,7 @@ public class TapTargetCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { if (target.choose(Outcome.Tap, controllerId, sourceId, game)) { for (UUID targetId : (List) target.getTargets()) { Permanent permanent = game.getPermanent(targetId); diff --git a/Mage/src/main/java/mage/abilities/costs/common/UntapSourceCost.java b/Mage/src/main/java/mage/abilities/costs/common/UntapSourceCost.java index 8c28bce5b52..506de1be8f9 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/UntapSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/UntapSourceCost.java @@ -29,6 +29,7 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.game.Game; import mage.game.permanent.Permanent; @@ -48,7 +49,7 @@ public class UntapSourceCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { paid = permanent.untap(game); diff --git a/Mage/src/main/java/mage/abilities/costs/common/UntapTargetCost.java b/Mage/src/main/java/mage/abilities/costs/common/UntapTargetCost.java index 89dc66c2b20..50fae7bf7f2 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/UntapTargetCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/UntapTargetCost.java @@ -37,6 +37,7 @@ import mage.target.common.TargetControlledPermanent; import java.util.List; import java.util.UUID; +import mage.abilities.costs.Cost; /** * @@ -57,7 +58,7 @@ public class UntapTargetCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { if (target.choose(Outcome.Untap, controllerId, sourceId, game)) { for (UUID targetId: (List)target.getTargets()) { Permanent permanent = game.getPermanent(targetId); diff --git a/Mage/src/main/java/mage/abilities/costs/mana/ColoredManaCost.java b/Mage/src/main/java/mage/abilities/costs/mana/ColoredManaCost.java index 2ab6f139f20..1bec6f7149c 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/ColoredManaCost.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/ColoredManaCost.java @@ -1,35 +1,35 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.costs.mana; import mage.Mana; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.constants.ColoredManaSymbol; import mage.game.Game; import mage.players.ManaPool; @@ -63,8 +63,8 @@ public class ColoredManaCost extends ManaCostImpl { } @Override - public void assignPayment(Game game, Ability ability, ManaPool pool) { - this.assignColored(ability, game, pool, mana); + public void assignPayment(Game game, Ability ability, ManaPool pool, Cost costToPay) { + this.assignColored(ability, game, pool, mana, costToPay); } @Override @@ -106,5 +106,5 @@ public class ColoredManaCost extends ManaCostImpl { public boolean containsColor(ColoredManaSymbol coloredManaSymbol) { return mana.equals(coloredManaSymbol); } - + } diff --git a/Mage/src/main/java/mage/abilities/costs/mana/ColorlessManaCost.java b/Mage/src/main/java/mage/abilities/costs/mana/ColorlessManaCost.java index 9fe8f15410d..268df2c164a 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/ColorlessManaCost.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/ColorlessManaCost.java @@ -29,6 +29,7 @@ package mage.abilities.costs.mana; import mage.Mana; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.constants.ColoredManaSymbol; import mage.game.Game; import mage.players.ManaPool; @@ -70,8 +71,8 @@ public class ColorlessManaCost extends ManaCostImpl { } @Override - public void assignPayment(Game game, Ability ability, ManaPool pool) { - this.assignColorless(ability, game, pool, mana); + public void assignPayment(Game game, Ability ability, ManaPool pool, Cost costToPay) { + this.assignColorless(ability, game, pool, mana, costToPay); } @Override diff --git a/Mage/src/main/java/mage/abilities/costs/mana/GenericManaCost.java b/Mage/src/main/java/mage/abilities/costs/mana/GenericManaCost.java index a216b74b5c3..58e203ba61a 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/GenericManaCost.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/GenericManaCost.java @@ -1,35 +1,35 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.costs.mana; import mage.Mana; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.constants.ColoredManaSymbol; import mage.game.Game; import mage.players.ManaPool; @@ -40,8 +40,8 @@ public class GenericManaCost extends ManaCostImpl { public GenericManaCost(int mana) { this.mana = mana; - this.cost = Mana.ColorlessMana(mana); - this.options.addMana(Mana.ColorlessMana(mana)); + this.cost = Mana.GenericMana(mana); + this.options.addMana(Mana.GenericMana(mana)); } public GenericManaCost(GenericManaCost manaCost) { @@ -67,8 +67,8 @@ public class GenericManaCost extends ManaCostImpl { } @Override - public void assignPayment(Game game, Ability ability, ManaPool pool) { - this.assignColorless(ability, game, pool, mana); + public void assignPayment(Game game, Ability ability, ManaPool pool, Cost costsToPay) { + this.assignGeneric(ability, game, pool, mana, costsToPay); } @Override @@ -94,6 +94,7 @@ public class GenericManaCost extends ManaCostImpl { public GenericManaCost copy() { return new GenericManaCost(this); } + @Override public boolean containsColor(ColoredManaSymbol coloredManaSymbol) { return false; diff --git a/Mage/src/main/java/mage/abilities/costs/mana/HybridManaCost.java b/Mage/src/main/java/mage/abilities/costs/mana/HybridManaCost.java index b8f9cdedb93..7c8f29ce6b6 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/HybridManaCost.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/HybridManaCost.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.List; import mage.Mana; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.constants.ColoredManaSymbol; import mage.game.Game; import mage.players.ManaPool; @@ -66,11 +67,11 @@ public class HybridManaCost extends ManaCostImpl { } @Override - public void assignPayment(Game game, Ability ability, ManaPool pool) { - if (assignColored(ability, game, pool, this.mana1)) { + public void assignPayment(Game game, Ability ability, ManaPool pool, Cost costToPay) { + if (assignColored(ability, game, pool, this.mana1, costToPay)) { return; } - assignColored(ability, game, pool, this.mana2); + assignColored(ability, game, pool, this.mana2, costToPay); } @Override diff --git a/Mage/src/main/java/mage/abilities/costs/mana/ManaCost.java b/Mage/src/main/java/mage/abilities/costs/mana/ManaCost.java index b1616aaa577..be6109e9b98 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/ManaCost.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/ManaCost.java @@ -47,7 +47,7 @@ public interface ManaCost extends Cost { Mana getPayment(); - void assignPayment(Game game, Ability ability, ManaPool pool); + void assignPayment(Game game, Ability ability, ManaPool pool, Cost costsToPay); void setPayment(Mana mana); diff --git a/Mage/src/main/java/mage/abilities/costs/mana/ManaCostImpl.java b/Mage/src/main/java/mage/abilities/costs/mana/ManaCostImpl.java index c87f2c0be5c..ac02b532abc 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/ManaCostImpl.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/ManaCostImpl.java @@ -32,6 +32,7 @@ import java.util.List; import java.util.UUID; import mage.Mana; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.mana.ManaOptions; import mage.constants.ColoredManaSymbol; @@ -113,35 +114,35 @@ public abstract class ManaCostImpl extends CostImpl implements ManaCost { this.sourceFilter = filter; } - protected boolean assignColored(Ability ability, Game game, ManaPool pool, ColoredManaSymbol mana) { + protected boolean assignColored(Ability ability, Game game, ManaPool pool, ColoredManaSymbol mana, Cost costToPay) { // first check special mana switch (mana) { case B: - if (pool.pay(ManaType.BLACK, ability, sourceFilter, game)) { + if (pool.pay(ManaType.BLACK, ability, sourceFilter, game, costToPay)) { this.payment.increaseBlack(); return true; } break; case U: - if (pool.pay(ManaType.BLUE, ability, sourceFilter, game)) { + if (pool.pay(ManaType.BLUE, ability, sourceFilter, game, costToPay)) { this.payment.increaseBlue(); return true; } break; case W: - if (pool.pay(ManaType.WHITE, ability, sourceFilter, game)) { + if (pool.pay(ManaType.WHITE, ability, sourceFilter, game, costToPay)) { this.payment.increaseWhite(); return true; } break; case G: - if (pool.pay(ManaType.GREEN, ability, sourceFilter, game)) { + if (pool.pay(ManaType.GREEN, ability, sourceFilter, game, costToPay)) { this.payment.increaseGreen(); return true; } break; case R: - if (pool.pay(ManaType.RED, ability, sourceFilter, game)) { + if (pool.pay(ManaType.RED, ability, sourceFilter, game, costToPay)) { this.payment.increaseRed(); return true; } @@ -150,30 +151,40 @@ public abstract class ManaCostImpl extends CostImpl implements ManaCost { return false; } - protected boolean assignColorless(Ability ability, Game game, ManaPool pool, int mana) { - int conditionalCount = pool.getConditionalCount(ability, game, null); + protected void assignColorless(Ability ability, Game game, ManaPool pool, int mana, Cost costToPay) { + int conditionalCount = pool.getConditionalCount(ability, game, null, costToPay); while (mana > payment.count() && (pool.count() > 0 || conditionalCount > 0)) { - if (pool.pay(ManaType.COLORLESS, ability, sourceFilter, game)) { + if (pool.pay(ManaType.COLORLESS, ability, sourceFilter, game, costToPay)) { + this.payment.increaseColorless(); + } + break; + } + } + + protected boolean assignGeneric(Ability ability, Game game, ManaPool pool, int mana, Cost costToPay) { + int conditionalCount = pool.getConditionalCount(ability, game, null, costToPay); + while (mana > payment.count() && (pool.count() > 0 || conditionalCount > 0)) { + if (pool.pay(ManaType.COLORLESS, ability, sourceFilter, game, costToPay)) { this.payment.increaseColorless(); continue; } - if (pool.pay(ManaType.BLACK, ability, sourceFilter, game)) { + if (pool.pay(ManaType.BLACK, ability, sourceFilter, game, costToPay)) { this.payment.increaseBlack(); continue; } - if (pool.pay(ManaType.BLUE, ability, sourceFilter, game)) { + if (pool.pay(ManaType.BLUE, ability, sourceFilter, game, costToPay)) { this.payment.increaseBlue(); continue; } - if (pool.pay(ManaType.WHITE, ability, sourceFilter, game)) { + if (pool.pay(ManaType.WHITE, ability, sourceFilter, game, costToPay)) { this.payment.increaseWhite(); continue; } - if (pool.pay(ManaType.GREEN, ability, sourceFilter, game)) { + if (pool.pay(ManaType.GREEN, ability, sourceFilter, game, costToPay)) { this.payment.increaseGreen(); continue; } - if (pool.pay(ManaType.RED, ability, sourceFilter, game)) { + if (pool.pay(ManaType.RED, ability, sourceFilter, game, costToPay)) { this.payment.increaseRed(); continue; } @@ -208,19 +219,19 @@ public abstract class ManaCostImpl extends CostImpl implements ManaCost { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { if (noMana) { setPaid(); return true; } Player player = game.getPlayer(controllerId); - assignPayment(game, ability, player.getManaPool()); + assignPayment(game, ability, player.getManaPool(), costToPay); game.getState().getSpecialActions().removeManaActions(); while (!isPaid()) { ManaCost unpaid = this.getUnpaid(); String promptText = ManaUtil.addSpecialManaPayAbilities(ability, game, unpaid); if (player.playMana(ability, unpaid, promptText, game)) { - assignPayment(game, ability, player.getManaPool()); + assignPayment(game, ability, player.getManaPool(), costToPay); } else { return false; } diff --git a/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java b/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java index 579c0b4bd90..0de107d2e32 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java @@ -34,6 +34,7 @@ import java.util.Map; import java.util.UUID; import mage.Mana; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.VariableCost; import mage.abilities.mana.ManaOptions; import mage.constants.ColoredManaSymbol; @@ -121,19 +122,24 @@ public class ManaCostsImpl extends ArrayList implements M @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + return pay(ability, game, sourceId, controllerId, noMana, this); + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { if (this.size() == 0 || noMana) { setPaid(); return true; } Player player = game.getPlayer(controllerId); - assignPayment(game, ability, player.getManaPool()); + assignPayment(game, ability, player.getManaPool(), this); game.getState().getSpecialActions().removeManaActions(); while (!isPaid()) { ManaCost unpaid = this.getUnpaid(); String promptText = ManaUtil.addSpecialManaPayAbilities(ability, game, unpaid); if (player.playMana(ability, unpaid, promptText, game)) { - assignPayment(game, ability, player.getManaPool()); + assignPayment(game, ability, player.getManaPool(), this); } else { return false; } @@ -155,7 +161,7 @@ public class ManaCostsImpl extends ArrayList implements M @Override public boolean payOrRollback(Ability ability, Game game, UUID sourceId, UUID payingPlayerId) { int bookmark = game.bookmarkState(); - if (pay(ability, game, sourceId, payingPlayerId, false)) { + if (pay(ability, game, sourceId, payingPlayerId, false, null)) { game.removeBookmark(bookmark); return true; } @@ -219,26 +225,24 @@ public class ManaCostsImpl extends ArrayList implements M } @Override - public void assignPayment(Game game, Ability ability, ManaPool pool) { + public void assignPayment(Game game, Ability ability, ManaPool pool, Cost costToPay) { if (!pool.isAutoPayment() && pool.getUnlockedManaType() == null) { // if auto payment is inactive and no mana type was clicked manually - do nothing return; } // attempt to pay colorless costs (not generic) mana costs first - if (pool.getColorless() > 0) { - for (ManaCost cost : this) { - if (!cost.isPaid() && cost instanceof ColorlessManaCost) { - cost.assignPayment(game, ability, pool); - if (pool.count() == 0) { - return; - } + for (ManaCost cost : this) { + if (!cost.isPaid() && cost instanceof ColorlessManaCost) { + cost.assignPayment(game, ability, pool, costToPay); + if (pool.count() == 0) { + return; } } } //attempt to pay colored costs first for (ManaCost cost : this) { if (!cost.isPaid() && cost instanceof ColoredManaCost) { - cost.assignPayment(game, ability, pool); + cost.assignPayment(game, ability, pool, costToPay); if (pool.count() == 0) { return; } @@ -247,7 +251,7 @@ public class ManaCostsImpl extends ArrayList implements M for (ManaCost cost : this) { if (!cost.isPaid() && cost instanceof HybridManaCost) { - cost.assignPayment(game, ability, pool); + cost.assignPayment(game, ability, pool, costToPay); if (pool.count() == 0) { return; } @@ -263,7 +267,7 @@ public class ManaCostsImpl extends ArrayList implements M || ((((MonoHybridManaCost) cost).containsColor(ColoredManaSymbol.R)) && pool.getRed() > 0) || ((((MonoHybridManaCost) cost).containsColor(ColoredManaSymbol.G)) && pool.getGreen() > 0) || ((((MonoHybridManaCost) cost).containsColor(ColoredManaSymbol.U)) && pool.getBlue() > 0)) { - cost.assignPayment(game, ability, pool); + cost.assignPayment(game, ability, pool, costToPay); if (pool.count() == 0) { return; } @@ -273,7 +277,7 @@ public class ManaCostsImpl extends ArrayList implements M // if colored didn't fit pay colorless with the mana for (ManaCost cost : this) { if (!cost.isPaid() && cost instanceof MonoHybridManaCost) { - cost.assignPayment(game, ability, pool); + cost.assignPayment(game, ability, pool, costToPay); if (pool.count() == 0) { return; } @@ -282,7 +286,7 @@ public class ManaCostsImpl extends ArrayList implements M for (ManaCost cost : this) { if (!cost.isPaid() && cost instanceof SnowManaCost) { - cost.assignPayment(game, ability, pool); + cost.assignPayment(game, ability, pool, costToPay); if (pool.count() == 0) { return; } @@ -291,7 +295,7 @@ public class ManaCostsImpl extends ArrayList implements M for (ManaCost cost : this) { if (!cost.isPaid() && cost instanceof GenericManaCost) { - cost.assignPayment(game, ability, pool); + cost.assignPayment(game, ability, pool, costToPay); if (pool.count() == 0) { return; } @@ -300,7 +304,7 @@ public class ManaCostsImpl extends ArrayList implements M for (ManaCost cost : this) { if (!cost.isPaid() && cost instanceof VariableManaCost) { - cost.assignPayment(game, ability, pool); + cost.assignPayment(game, ability, pool, costToPay); } } // stop using mana of the clicked mana type diff --git a/Mage/src/main/java/mage/abilities/costs/mana/MonoHybridManaCost.java b/Mage/src/main/java/mage/abilities/costs/mana/MonoHybridManaCost.java index 1d4a6170140..2e7b2a7a94a 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/MonoHybridManaCost.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/MonoHybridManaCost.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.List; import mage.Mana; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.constants.ColoredManaSymbol; import mage.game.Game; import mage.players.ManaPool; @@ -43,9 +44,9 @@ public class MonoHybridManaCost extends ManaCostImpl { public MonoHybridManaCost(ColoredManaSymbol mana) { this.mana = mana; this.cost = new Mana(mana); - this.cost.add(Mana.ColorlessMana(2)); + this.cost.add(Mana.GenericMana(2)); addColoredOption(mana); - options.add(Mana.ColorlessMana(2)); + options.add(Mana.GenericMana(2)); } public MonoHybridManaCost(MonoHybridManaCost manaCost) { @@ -68,9 +69,9 @@ public class MonoHybridManaCost extends ManaCostImpl { } @Override - public void assignPayment(Game game, Ability ability, ManaPool pool) { - if (!assignColored(ability, game, pool, mana)) { - assignColorless(ability, game, pool, mana2); + public void assignPayment(Game game, Ability ability, ManaPool pool, Cost costToPay) { + if (!assignColored(ability, game, pool, mana, costToPay)) { + assignGeneric(ability, game, pool, mana2, costToPay); } } @@ -125,7 +126,7 @@ public class MonoHybridManaCost extends ManaCostImpl { public List getManaOptions() { List manaList = new ArrayList<>(); manaList.add(new Mana(mana)); - manaList.add(Mana.ColorlessMana(2)); + manaList.add(Mana.GenericMana(2)); return manaList; } } diff --git a/Mage/src/main/java/mage/abilities/costs/mana/PhyrexianManaCost.java b/Mage/src/main/java/mage/abilities/costs/mana/PhyrexianManaCost.java index 6bfeceb31af..4ba907801d2 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/PhyrexianManaCost.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/PhyrexianManaCost.java @@ -1,51 +1,49 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.costs.mana; import java.util.UUID; -import mage.constants.ColoredManaSymbol; import mage.Mana; import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.constants.ColoredManaSymbol; import mage.game.Game; import mage.players.ManaPool; - - /** - * + * * @author nantuko */ public class PhyrexianManaCost extends ColoredManaCost { public PhyrexianManaCost(ColoredManaSymbol mana) { super(mana); - options.add(Mana.ColorlessMana(0)); + options.add(Mana.GenericMana(0)); } public PhyrexianManaCost(PhyrexianManaCost manaCost) { @@ -53,8 +51,8 @@ public class PhyrexianManaCost extends ColoredManaCost { } @Override - public void assignPayment(Game game, Ability ability, ManaPool pool) { - assignColored(ability, game, pool, this.mana); + public void assignPayment(Game game, Ability ability, ManaPool pool, Cost costToPay) { + assignColored(ability, game, pool, this.mana, costToPay); } @Override @@ -76,7 +74,7 @@ public class PhyrexianManaCost extends ColoredManaCost { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { this.paid = game.getPlayer(controllerId).loseLife(2, game) == 2; return paid; } diff --git a/Mage/src/main/java/mage/abilities/costs/mana/SnowManaCost.java b/Mage/src/main/java/mage/abilities/costs/mana/SnowManaCost.java index eaa722de91c..b5e119a5fa6 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/SnowManaCost.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/SnowManaCost.java @@ -1,35 +1,35 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.costs.mana; import mage.Mana; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.constants.ColoredManaSymbol; import mage.filter.FilterObject; import mage.filter.predicate.mageobject.SupertypePredicate; @@ -39,13 +39,14 @@ import mage.players.ManaPool; public class SnowManaCost extends ManaCostImpl { private static final FilterObject filter = new FilterObject("Snow object"); - static{ + + static { filter.add(new SupertypePredicate("Snow")); } public SnowManaCost() { - this.cost = Mana.ColorlessMana(1); - this.options.addMana(Mana.ColorlessMana(1)); + this.cost = Mana.GenericMana(1); + this.options.addMana(Mana.GenericMana(1)); this.setSourceFilter(filter); } @@ -59,10 +60,10 @@ public class SnowManaCost extends ManaCostImpl { } @Override - public void assignPayment(Game game, Ability ability, ManaPool pool) { - this.assignColorless(ability, game, pool, 1); + public void assignPayment(Game game, Ability ability, ManaPool pool, Cost costToPay) { + this.assignGeneric(ability, game, pool, 1, costToPay); } - + @Override public boolean isPaid() { if (paid) { @@ -90,6 +91,7 @@ public class SnowManaCost extends ManaCostImpl { public SnowManaCost copy() { return new SnowManaCost(this); } + @Override public boolean containsColor(ColoredManaSymbol coloredManaSymbol) { return false; diff --git a/Mage/src/main/java/mage/abilities/costs/mana/VariableManaCost.java b/Mage/src/main/java/mage/abilities/costs/mana/VariableManaCost.java index ee08fe83b0b..fb7c27268bf 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/VariableManaCost.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/VariableManaCost.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.costs.mana; import mage.Mana; @@ -74,7 +73,7 @@ public class VariableManaCost extends ManaCostImpl implements VariableCost { } @Override - public void assignPayment(Game game, Ability ability, ManaPool pool) { + public void assignPayment(Game game, Ability ability, ManaPool pool, Cost costToPay) { payment.add(pool.getMana(filter)); payment.add(pool.getAllConditionalMana(ability, game, filter)); pool.payX(ability, game, filter); @@ -88,8 +87,7 @@ public class VariableManaCost extends ManaCostImpl implements VariableCost { symbol += "{X}"; } return symbol; - } - else { + } else { return "{X}"; } } @@ -106,7 +104,7 @@ public class VariableManaCost extends ManaCostImpl implements VariableCost { @Override public void setAmount(int amount) { - payment.setColorless(amount); + payment.setGeneric(amount); } @Override @@ -120,11 +118,11 @@ public class VariableManaCost extends ManaCostImpl implements VariableCost { } public int getMultiplier() { - return multiplier; + return multiplier; } public int getMinX() { - return minX; + return minX; } public void setMinX(int minX) { diff --git a/Mage/src/main/java/mage/abilities/effects/PayCostToAttackBlockEffectImpl.java b/Mage/src/main/java/mage/abilities/effects/PayCostToAttackBlockEffectImpl.java index d31b8e71cf3..304a9c36af6 100644 --- a/Mage/src/main/java/mage/abilities/effects/PayCostToAttackBlockEffectImpl.java +++ b/Mage/src/main/java/mage/abilities/effects/PayCostToAttackBlockEffectImpl.java @@ -159,7 +159,7 @@ public abstract class PayCostToAttackBlockEffectImpl extends ReplacementEffectIm if (attackBlockOtherTax.canPay(source, source.getSourceId(), event.getPlayerId(), game) && player.chooseUse(Outcome.Neutral, attackBlockOtherTax.getText() + " to " + (event.getType().equals(EventType.DECLARE_ATTACKER) ? "attack?" : "block?"), source, game)) { - if (attackBlockOtherTax.pay(source, game, source.getSourceId(), event.getPlayerId(), false)) { + if (attackBlockOtherTax.pay(source, game, source.getSourceId(), event.getPlayerId(), false, null)) { return false; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/AddConditionalColorlessManaEffect.java b/Mage/src/main/java/mage/abilities/effects/common/AddConditionalColorlessManaEffect.java index 7e0de77c756..efcf108acfb 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/AddConditionalColorlessManaEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/AddConditionalColorlessManaEffect.java @@ -24,7 +24,9 @@ public class AddConditionalColorlessManaEffect extends ManaEffect { super(); this.amount = amount; this.manaBuilder = manaBuilder; - staticText = "Add {" + amount + "} to your mana pool. " + manaBuilder.getRule(); + + staticText = "Add " + String.format(String.format("%%%ds", amount), " ").replace(" ", "{C}") + + " to your mana pool. " + manaBuilder.getRule(); } public AddConditionalColorlessManaEffect(final AddConditionalColorlessManaEffect effect) { @@ -54,6 +56,6 @@ public class AddConditionalColorlessManaEffect extends ManaEffect { } public Mana getMana() { - return new Mana(0, 0, 0, 0, 0, amount, 0); + return new Mana(0, 0, 0, 0, 0, 0, 0, amount); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/AddManaOfAnyColorEffect.java b/Mage/src/main/java/mage/abilities/effects/common/AddManaOfAnyColorEffect.java index fb7ad296c42..a2c556ce82f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/AddManaOfAnyColorEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/AddManaOfAnyColorEffect.java @@ -46,7 +46,7 @@ public class AddManaOfAnyColorEffect extends BasicManaEffect { } public AddManaOfAnyColorEffect(final int amount) { - super(new Mana(0,0,0,0,0,0, amount)); + super(new Mana(0,0,0,0,0,0, amount, 0)); this.amount = amount; this.staticText = new StringBuilder("add ") .append(CardUtil.numberToText(amount)) @@ -103,7 +103,7 @@ public class AddManaOfAnyColorEffect extends BasicManaEffect { @Override public Mana getMana() { - return (new Mana(0,0,0,0,0,0,amount)); + return (new Mana(0,0,0,0,0,0,amount, 0)); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/AddManaOfAnyTypeProducedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/AddManaOfAnyTypeProducedEffect.java index c230ee146f5..c171f78c9be 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/AddManaOfAnyTypeProducedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/AddManaOfAnyTypeProducedEffect.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.effects.common; import mage.Mana; @@ -40,7 +39,6 @@ import mage.players.Player; * * @author LevelX2 */ - public class AddManaOfAnyTypeProducedEffect extends ManaEffect { public AddManaOfAnyTypeProducedEffect() { @@ -110,10 +108,10 @@ public class AddManaOfAnyTypeProducedEffect extends ManaEffect { case "Colorless": newMana.setColorless(1); break; - } + } checkToFirePossibleEvents(newMana, game, source); targetController.getManaPool().addMana(newMana, game, source); - + } return true; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/AffinityEffect.java b/Mage/src/main/java/mage/abilities/effects/common/AffinityEffect.java index d1b30c14c25..e7d12be0f80 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/AffinityEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/AffinityEffect.java @@ -29,13 +29,13 @@ public class AffinityEffect extends CostModificationEffectImpl { public boolean apply(Game game, Ability source, Ability abilityToModify) { SpellAbility spellAbility = (SpellAbility)abilityToModify; Mana mana = spellAbility.getManaCostsToPay().getMana(); - if (mana.getColorless() > 0) { + if (mana.getGeneric() > 0) { int count = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); - int newCount = mana.getColorless() - count; + int newCount = mana.getGeneric() - count; if (newCount < 0) { newCount = 0; } - mana.setColorless(newCount); + mana.setGeneric(newCount); spellAbility.getManaCostsToPay().load(mana.toString()); return true; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ChangeATargetOfTargetSpellAbilityToSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ChangeATargetOfTargetSpellAbilityToSourceEffect.java index d332b7ac6cd..40d64df9a7d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChangeATargetOfTargetSpellAbilityToSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChangeATargetOfTargetSpellAbilityToSourceEffect.java @@ -58,6 +58,9 @@ public class ChangeATargetOfTargetSpellAbilityToSourceEffect extends OneShotEffe boolean twoTimesTarget = false; if (targets.size() == 1 && targets.get(0).getTargets().size() == 1) { Target target = targets.get(0); + if (target.getFirstTarget().equals(source.getSourceId())) { + return true; // Target was already the same source, so no change / target event to create + } if (target.canTarget(stackObject.getControllerId(), source.getSourceId(), sourceAbility, game)) { oldTargetName = getTargetName(targets.getFirstTarget(), game); target.clearChosen(); diff --git a/Mage/src/main/java/mage/abilities/effects/common/CounterUnlessPaysEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CounterUnlessPaysEffect.java index 585d8a8118e..ef7ea34b3dd 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CounterUnlessPaysEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CounterUnlessPaysEffect.java @@ -93,7 +93,7 @@ public class CounterUnlessPaysEffect extends OneShotEffect { message = costToPay.getText() + " to prevent counter effect?"; } costToPay.clearPaid(); - if (!(player.chooseUse(Outcome.Benefit, message, source, game) && costToPay.pay(source, game, spell.getSourceId(), spell.getControllerId(), false))) { + if (!(player.chooseUse(Outcome.Benefit, message, source, game) && costToPay.pay(source, game, spell.getSourceId(), spell.getControllerId(), false, null))) { return game.getStack().counter(spell.getId(), source.getSourceId(), game); } return true; diff --git a/Mage/src/main/java/mage/abilities/effects/common/CreateDelayedTriggeredAbilityEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CreateDelayedTriggeredAbilityEffect.java index 5d56cd403c8..c6076bf94fd 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CreateDelayedTriggeredAbilityEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CreateDelayedTriggeredAbilityEffect.java @@ -74,9 +74,6 @@ public class CreateDelayedTriggeredAbilityEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { DelayedTriggeredAbility delayedAbility = ability.copy(); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); if (this.copyTargets) { if (source.getTargets().isEmpty()) { for (Effect effect : delayedAbility.getEffects()) { @@ -92,7 +89,7 @@ public class CreateDelayedTriggeredAbilityEffect extends OneShotEffect { if (initAbility) { delayedAbility.init(game); } - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DestroyTargetAtBeginningOfNextEndStepEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DestroyTargetAtBeginningOfNextEndStepEffect.java index 02bb9967730..25e928e355b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DestroyTargetAtBeginningOfNextEndStepEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DestroyTargetAtBeginningOfNextEndStepEffect.java @@ -30,7 +30,6 @@ package mage.abilities.effects.common; import mage.abilities.Ability; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DestroyTargetEffect; import mage.constants.Outcome; import mage.game.Game; import mage.target.targetpointer.FixedTarget; @@ -60,10 +59,7 @@ public class DestroyTargetAtBeginningOfNextEndStepEffect extends OneShotEffect { DestroyTargetEffect effect = new DestroyTargetEffect(); effect.setTargetPointer(new FixedTarget(source.getFirstTarget())); AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DetainTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DetainTargetEffect.java index 6dba9637b2a..af0501ed48c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DetainTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DetainTargetEffect.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.effects.common; import java.util.UUID; @@ -47,8 +46,6 @@ import mage.util.CardUtil; * * @author LevelX2 */ - - // // 701.26. Detain // @@ -56,7 +53,6 @@ import mage.util.CardUtil; // turn of the controller of that spell or ability, that permanent can’t attack // or block and its activated abilities can’t be activated. // - public class DetainTargetEffect extends OneShotEffect { public DetainTargetEffect() { @@ -80,7 +76,7 @@ public class DetainTargetEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { if (!game.isSimulation()) { - for (UUID target: this.getTargetPointer().getTargets(game, source)) { + for (UUID target : this.getTargetPointer().getTargets(game, source)) { Permanent permanent = game.getPermanent(target); if (permanent != null) { game.informPlayers("Detained permanent: " + permanent.getName()); @@ -99,40 +95,37 @@ public class DetainTargetEffect extends OneShotEffect { } StringBuilder sb = new StringBuilder(); Target target = mode.getTargets().get(0); - + if (target.getMaxNumberOfTargets() == target.getNumberOfTargets()) { if (target.getMaxNumberOfTargets() == 1) { sb.append("detain target ").append(target.getTargetName()); - } - else { + } else { sb.append("detain ").append(target.getMaxNumberOfTargets()).append(" target ").append(target.getTargetName()); } } else { - sb.append("detain up to ").append(CardUtil.numberToText(target.getMaxNumberOfTargets())).append(" target ").append(target.getTargetName()); + sb.append("detain up to ").append(CardUtil.numberToText(target.getMaxNumberOfTargets())).append(" target ").append(target.getTargetName()); } sb.append(". (Until your next turn, "); - if (target instanceof TargetCreaturePermanent) { - sb.append(target.getMaxNumberOfTargets() == 1 ? "that creature": "those creatures"); - } - else { - sb.append(target.getMaxNumberOfTargets() == 1 ? "that permanent": "those permanents"); + sb.append(target.getMaxNumberOfTargets() == 1 ? "that creature" : "those creatures"); + } else { + sb.append(target.getMaxNumberOfTargets() == 1 ? "that permanent" : "those permanents"); } sb.append(" can't attack or block and "); - sb.append(target.getMaxNumberOfTargets() == 1 ? "its": "their"); + sb.append(target.getMaxNumberOfTargets() == 1 ? "its" : "their"); sb.append(" activated abilities can't be activated)"); return sb.toString(); } } - + class DetainRestrictionEffect extends RestrictionEffect { - + public DetainRestrictionEffect() { super(Duration.Custom); staticText = ""; } - + public DetainRestrictionEffect(final DetainRestrictionEffect effect) { super(effect); } @@ -140,23 +133,22 @@ class DetainRestrictionEffect extends RestrictionEffect { @Override public void init(Ability source, Game game) { super.init(source, game); - for(UUID targetId :this.getTargetPointer().getTargets(game, source)) { + for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { Permanent permanent = game.getPermanent(targetId); if (permanent != null) { - permanent.addInfo(new StringBuilder("detain").append(getId()).toString(),"[Detained]", game); + permanent.addInfo(new StringBuilder("detain").append(getId()).toString(), "[Detained]", game); } } } @Override public boolean isInactive(Ability source, Game game) { - if (game.getPhase().getStep().getType() == PhaseStep.UNTAP && game.getStep().getStepPart() == Step.StepPart.PRE) - { + if (game.getPhase().getStep().getType() == PhaseStep.UNTAP && game.getStep().getStepPart() == Step.StepPart.PRE) { if (game.getActivePlayerId().equals(source.getControllerId()) || game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving()) { - for(UUID targetId :this.getTargetPointer().getTargets(game, source)) { + for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { Permanent permanent = game.getPermanent(targetId); if (permanent != null) { - permanent.addInfo(new StringBuilder("detain").append(getId()).toString(),"", game); + permanent.addInfo("detain" + getId(), "", game); } } return true; @@ -164,7 +156,7 @@ class DetainRestrictionEffect extends RestrictionEffect { } return false; } - + @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (this.targetPointer.getTargets(game, source).contains(permanent.getId())) { @@ -172,12 +164,12 @@ class DetainRestrictionEffect extends RestrictionEffect { } return false; } - + @Override public boolean canAttack(Game game) { return false; } - + @Override public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { return false; @@ -192,5 +184,5 @@ class DetainRestrictionEffect extends RestrictionEffect { public DetainRestrictionEffect copy() { return new DetainRestrictionEffect(this); } - + } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DoUnlessAnyPlayerPaysEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DoUnlessAnyPlayerPaysEffect.java index c7e8ab933dc..5062f785630 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DoUnlessAnyPlayerPaysEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DoUnlessAnyPlayerPaysEffect.java @@ -93,7 +93,7 @@ public class DoUnlessAnyPlayerPaysEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null && cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(Outcome.Detriment, message, source, game)) { cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { + if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { if (!game.isSimulation()) game.informPlayers(player.getLogName() + " pays the cost to prevent the effect"); doEffect = false; diff --git a/Mage/src/main/java/mage/abilities/effects/common/DrawDiscardTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DrawDiscardTargetEffect.java index 4d8ef83bc7d..5684286d082 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DrawDiscardTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DrawDiscardTargetEffect.java @@ -55,7 +55,7 @@ public class DrawDiscardTargetEffect extends OneShotEffect { staticText = new StringBuilder("Target player draws ") .append(cardsToDraw == 1?"a": CardUtil.numberToText(cardsToDraw)) .append(" card").append(cardsToDraw == 1?" ": "s") - .append(", then discard ") + .append(", then discards ") .append(cardsToDiscard == 1?"a": CardUtil.numberToText(cardsToDiscard)) .append(" card").append(cardsToDiscard == 1?" ": "s").toString(); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DynamicManaEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DynamicManaEffect.java index 6d6cc7597a7..8dcdda4aa64 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DynamicManaEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DynamicManaEffect.java @@ -171,7 +171,7 @@ public class DynamicManaEffect extends BasicManaEffect { } } } else { - computedMana.setColorless(count); + computedMana.setGeneric(count); } return computedMana; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/EnterBattlefieldPayCostOrPutGraveyardEffect.java b/Mage/src/main/java/mage/abilities/effects/common/EnterBattlefieldPayCostOrPutGraveyardEffect.java index e4b3e481310..5a49099c7dd 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/EnterBattlefieldPayCostOrPutGraveyardEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/EnterBattlefieldPayCostOrPutGraveyardEffect.java @@ -78,7 +78,7 @@ public class EnterBattlefieldPayCostOrPutGraveyardEffect extends ReplacementEffe if (cost.canPay(source, source.getSourceId(), player.getId(), game)) { if (player.chooseUse(outcome, cost.getText() + "? (otherwise " + sourceObject.getLogName() + " is put into graveyard)", source, game)) { cost.clearPaid(); - replace = !cost.pay(source, game, source.getSourceId(), source.getControllerId(), false); + replace = !cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null); } } if (replace) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/EpicEffect.java b/Mage/src/main/java/mage/abilities/effects/common/EpicEffect.java index 144fc253889..e3456a76811 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/EpicEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/EpicEffect.java @@ -64,9 +64,7 @@ public class EpicEffect extends OneShotEffect { } spell.getSpellAbility().getEffects().remove(epicEffect); DelayedTriggeredAbility ability = new AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility(new EpicPushEffect(spell, rule), Duration.EndOfGame, false); - ability.setSourceId(source.getSourceId()); - ability.setControllerId(source.getControllerId()); - game.addDelayedTriggeredAbility(ability); + game.addDelayedTriggeredAbility(ability, source); game.addEffect(new EpicReplacementEffect(), source); return true; } @@ -104,7 +102,7 @@ class EpicReplacementEffect extends ContinuousRuleModifyingEffectImpl { public String getInfoMessage(Ability source, GameEvent event, Game game) { MageObject mageObject = game.getObject(source.getSourceId()); if (mageObject != null) { - return "For the rest of the game, you can't cast spells (Epic - " + mageObject.getName() +")"; + return "For the rest of the game, you can't cast spells (Epic - " + mageObject.getName() + ")"; } return null; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileReturnToBattlefieldOwnerNextEndStepEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileReturnBattlefieldOwnerNextEndStepSourceEffect.java similarity index 82% rename from Mage/src/main/java/mage/abilities/effects/common/ExileReturnToBattlefieldOwnerNextEndStepEffect.java rename to Mage/src/main/java/mage/abilities/effects/common/ExileReturnBattlefieldOwnerNextEndStepSourceEffect.java index e608d796bf8..6f2f5511037 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileReturnToBattlefieldOwnerNextEndStepEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileReturnBattlefieldOwnerNextEndStepSourceEffect.java @@ -40,12 +40,12 @@ import mage.players.Player; * * @author LevelX2 */ -public class ExileReturnToBattlefieldOwnerNextEndStepEffect extends OneShotEffect { +public class ExileReturnBattlefieldOwnerNextEndStepSourceEffect extends OneShotEffect { private static final String effectText = "exile {this}. Return it to the battlefield under its owner's control at the beginning of the next end step"; private boolean returnAlways; - public ExileReturnToBattlefieldOwnerNextEndStepEffect() { + public ExileReturnBattlefieldOwnerNextEndStepSourceEffect() { this(false); } @@ -55,13 +55,13 @@ public class ExileReturnToBattlefieldOwnerNextEndStepEffect extends OneShotEffec * but is moved to another zone (e.g. command zone by commander replacement * effect) */ - public ExileReturnToBattlefieldOwnerNextEndStepEffect(boolean returnAlways) { + public ExileReturnBattlefieldOwnerNextEndStepSourceEffect(boolean returnAlways) { super(Outcome.Benefit); staticText = effectText; this.returnAlways = returnAlways; } - public ExileReturnToBattlefieldOwnerNextEndStepEffect(ExileReturnToBattlefieldOwnerNextEndStepEffect effect) { + public ExileReturnBattlefieldOwnerNextEndStepSourceEffect(ExileReturnBattlefieldOwnerNextEndStepSourceEffect effect) { super(effect); this.returnAlways = effect.returnAlways; } @@ -78,10 +78,7 @@ public class ExileReturnToBattlefieldOwnerNextEndStepEffect extends OneShotEffec //create delayed triggered ability and return it from every public zone he was next moved to AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility( new ReturnToBattlefieldUnderOwnerControlSourceEffect(false, zcc + 1)); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); } } return true; @@ -90,8 +87,8 @@ public class ExileReturnToBattlefieldOwnerNextEndStepEffect extends OneShotEffec } @Override - public ExileReturnToBattlefieldOwnerNextEndStepEffect copy() { - return new ExileReturnToBattlefieldOwnerNextEndStepEffect(this); + public ExileReturnBattlefieldOwnerNextEndStepSourceEffect copy() { + return new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(this); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileSourceUnlessPaysEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileSourceUnlessPaysEffect.java index 489de50c10d..f6043e913f2 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileSourceUnlessPaysEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileSourceUnlessPaysEffect.java @@ -68,7 +68,7 @@ public class ExileSourceUnlessPaysEffect extends OneShotEffect { message = Character.toUpperCase(message.charAt(0)) + message.substring(1); if (controller.chooseUse(Outcome.Benefit, message, source, game)) { cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { return true; } } 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 697c07435ab..2ac10f4471f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileTargetForSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileTargetForSourceEffect.java @@ -27,6 +27,8 @@ */ package mage.abilities.effects.common; +import java.util.LinkedHashSet; +import java.util.Set; import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; @@ -37,6 +39,8 @@ import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.Target; +import mage.target.targetpointer.FirstTargetPointer; import mage.util.CardUtil; /** @@ -63,16 +67,27 @@ public class ExileTargetForSourceEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); - if (permanent != null) { - return controller.moveCardsToExile(permanent, source, game, true, exileId, sourceObject.getIdName()); - } else { - Card card = game.getCard(getTargetPointer().getFirst(game, source)); - if (card != null) { - return controller.moveCardsToExile(card, source, game, true, exileId, sourceObject.getIdName()); + Set cards = new LinkedHashSet<>(); + if (source.getTargets().size() > 1 && targetPointer instanceof FirstTargetPointer) { + for (Target target : source.getTargets()) { + for (UUID targetId : target.getTargets()) { + MageObject mageObject = game.getObject(targetId); + if (mageObject instanceof Card) { + cards.add((Card) mageObject); + } + } } } + else { + for (UUID targetId : targetPointer.getTargets(game, source)) { + MageObject mageObject = game.getObject(targetId); + if (mageObject != null) { + cards.add((Card) mageObject); + } + } + } + UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); + return controller.moveCardsToExile(cards, source, game, true, exileId, sourceObject.getIdName()); } return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/PutTokenOntoBattlefieldCopyTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PutTokenOntoBattlefieldCopyTargetEffect.java index 61f433d298f..3c98f5d5c8a 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PutTokenOntoBattlefieldCopyTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PutTokenOntoBattlefieldCopyTargetEffect.java @@ -42,6 +42,7 @@ import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.EmptyToken; +import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; import mage.util.functions.ApplyToPermanent; import mage.util.functions.EmptyApplyToPermanent; @@ -125,7 +126,13 @@ public class PutTokenOntoBattlefieldCopyTargetEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); + UUID targetId; + if (getTargetPointer() instanceof FixedTarget) { + targetId = ((FixedTarget) getTargetPointer()).getTarget(); + } else { + targetId = getTargetPointer().getFirst(game, source); + } + Permanent permanent = game.getPermanentOrLKIBattlefield(targetId); Card copyFrom; ApplyToPermanent applier = new EmptyApplyToPermanent(); if (permanent != null) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToHandTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToHandTargetEffect.java index 7e086481be5..dcae8028808 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToHandTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToHandTargetEffect.java @@ -61,7 +61,7 @@ public class ReturnFromGraveyardToHandTargetEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - return controller.moveCards(new CardsImpl(getTargetPointer().getTargets(game, source)), null, Zone.HAND, source, game); + return controller.moveCards(new CardsImpl(getTargetPointer().getTargets(game, source)), Zone.HAND, source, game); } return false; } 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 5d868a5bdcc..b708e75fe4c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlTargetEffect.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.effects.common; import mage.abilities.Ability; @@ -34,6 +33,7 @@ import mage.cards.Card; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; +import mage.players.Player; /** * @@ -41,13 +41,21 @@ import mage.game.Game; */ public class ReturnToBattlefieldUnderOwnerControlTargetEffect extends OneShotEffect { + private boolean tapped; + public ReturnToBattlefieldUnderOwnerControlTargetEffect() { + this(false); + } + + public ReturnToBattlefieldUnderOwnerControlTargetEffect(boolean tapped) { super(Outcome.Benefit); staticText = "return that card to the battlefield under its owner's control"; + this.tapped = tapped; } public ReturnToBattlefieldUnderOwnerControlTargetEffect(final ReturnToBattlefieldUnderOwnerControlTargetEffect effect) { super(effect); + this.tapped = effect.tapped; } @Override @@ -57,14 +65,14 @@ public class ReturnToBattlefieldUnderOwnerControlTargetEffect extends OneShotEff @Override public boolean apply(Game game, Ability source) { - Card card = game.getCard(targetPointer.getFirst(game, source)); - if (card != null) { - Zone currentZone = game.getState().getZone(card.getId()); - if (card.putOntoBattlefield(game, currentZone, source.getSourceId(), card.getOwnerId())) { - return true; + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Card card = game.getCard(targetPointer.getFirst(game, source)); + if (card != null) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, true, null); } + return true; } return false; } - } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandTargetEffect.java index c4f1fd5a98c..7733ab85114 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandTargetEffect.java @@ -48,19 +48,26 @@ import mage.util.CardUtil; public class ReturnToHandTargetEffect extends OneShotEffect { boolean withName; + protected boolean multitargetHandling; public ReturnToHandTargetEffect() { this(true); } public ReturnToHandTargetEffect(boolean withName) { + this(withName, false); + } + + public ReturnToHandTargetEffect(boolean withName, boolean multitargetHandling) { super(Outcome.ReturnToHand); this.withName = withName; + this.multitargetHandling = multitargetHandling; } public ReturnToHandTargetEffect(final ReturnToHandTargetEffect effect) { super(effect); this.withName = effect.withName; + this.multitargetHandling = effect.multitargetHandling; } @Override @@ -75,10 +82,21 @@ public class ReturnToHandTargetEffect extends OneShotEffect { return false; } Set cards = new LinkedHashSet<>(); - for (UUID targetId : targetPointer.getTargets(game, source)) { - MageObject mageObject = game.getObject(targetId); - if (mageObject instanceof Card) { - cards.add((Card) mageObject); + if (multitargetHandling) { + for (Target target : source.getTargets()) { + for (UUID targetId : target.getTargets()) { + MageObject mageObject = game.getObject(targetId); + if (mageObject instanceof Card) { + cards.add((Card) mageObject); + } + } + } + } else { + for (UUID targetId : targetPointer.getTargets(game, source)) { + MageObject mageObject = game.getObject(targetId); + if (mageObject != null) { + cards.add((Card) mageObject); + } } } return controller.moveCards(cards, Zone.HAND, source, game); diff --git a/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java index f0904271903..33e0f0b7a2b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java @@ -40,7 +40,7 @@ public class SacrificeSourceUnlessPaysEffect extends OneShotEffect { message = Character.toUpperCase(message.charAt(0)) + message.substring(1); if (player.chooseUse(Outcome.Benefit, message, source, game)) { cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { return true; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java b/Mage/src/main/java/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java index 15fbc93dbff..ddc099db09b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java @@ -66,7 +66,7 @@ public class TapSourceUnlessPaysEffect extends OneShotEffect { if (cost.canPay(source, source.getSourceId(), source.getControllerId(), game) && player.chooseUse(Outcome.Benefit, cost.getText() + "? (otherwise " + permanent.getName() + " becomes tapped)", source, game)) { cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { return true; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/UnlessPaysDelayedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/UnlessPaysDelayedEffect.java index a474a2a19e2..60e965ea764 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/UnlessPaysDelayedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/UnlessPaysDelayedEffect.java @@ -35,20 +35,18 @@ import mage.abilities.SpecialAction; import mage.abilities.costs.Cost; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.RemoveDelayedTriggeredAbilityEffect; -import mage.abilities.effects.common.RemoveSpecialActionEffect; import mage.constants.Outcome; import mage.constants.PhaseStep; import mage.game.Game; -import mage.game.events.GameEvent.EventType; import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; import mage.target.targetpointer.FixedTarget; /** * - * @author LoneFox (based on Quenchable Fire code by BetaSteward_at_googlemail.com) + * @author LoneFox (based on Quenchable Fire code by + * BetaSteward_at_googlemail.com) */ - public class UnlessPaysDelayedEffect extends OneShotEffect { private final Cost cost; @@ -63,7 +61,7 @@ public class UnlessPaysDelayedEffect extends OneShotEffect { this.step = step; this.affectedPlayersTurn = affectedPlayersTurn; staticText = text + "
Use the Special button to pay the " + cost.getText() - + " with a special action before that step."; + + " with a special action before that step."; } public UnlessPaysDelayedEffect(final UnlessPaysDelayedEffect effect) { @@ -91,11 +89,8 @@ public class UnlessPaysDelayedEffect extends OneShotEffect { UUID turnPlayer = affectedPlayersTurn ? getTargetPointer().getFirst(game, source) : source.getControllerId(); effect.setTargetPointer(new FixedTarget(getTargetPointer().getFirst(game, source))); UnlessPaysDelayedEffectTriggeredAbility delayedAbility = new UnlessPaysDelayedEffectTriggeredAbility(turnPlayer, step, effect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(sourceObject, game); delayedAbility.setSpecialActionId(newAction.getId()); - UUID delayedAbilityId = game.addDelayedTriggeredAbility(delayedAbility); + UUID delayedAbilityId = game.addDelayedTriggeredAbility(delayedAbility, source); // update special action newAction.addCost(cost); @@ -143,7 +138,7 @@ class UnlessPaysDelayedEffectTriggeredAbility extends DelayedTriggeredAbility { @Override public boolean checkEventType(GameEvent event, Game game) { - switch(step) { + switch (step) { case UPKEEP: return event.getType() == EventType.UPKEEP_STEP_PRE; case DRAW: @@ -156,7 +151,7 @@ class UnlessPaysDelayedEffectTriggeredAbility extends DelayedTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { if (event.getPlayerId().equals(turnPlayer)) { - for (SpecialAction action: game.getState().getSpecialActions()) { + for (SpecialAction action : game.getState().getSpecialActions()) { if (action.getId().equals(specialActionId)) { game.getState().getSpecialActions().remove(action); break; diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockAdditionalCreatureEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockAdditionalCreatureEffect.java index efeb94f2f64..09d3157b3e4 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockAdditionalCreatureEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockAdditionalCreatureEffect.java @@ -96,15 +96,18 @@ public class CanBlockAdditionalCreatureEffect extends ContinuousEffectImpl { } private String setText() { - StringBuilder sb = new StringBuilder("{this} can block "); + String text = "{this} can block "; switch(amount) { case 0: - sb.append("any number of creatures"); + text += "any number of creatures"; break; default: - sb.append(CardUtil.numberToText(amount, "an")).append(" additional creature").append(amount > 1 ? "s":""); + text += CardUtil.numberToText(amount, "an") + " additional creature" + (amount > 1 ? "s" : ""); } - return sb.toString(); + if(duration == Duration.EndOfTurn) { + text += " this turn"; + } + return text; } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouAllEffect.java index 519ad93ff71..0ce92ebb150 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouAllEffect.java @@ -45,13 +45,13 @@ public class CantAttackYouAllEffect extends RestrictionEffect { private final FilterCreaturePermanent filterAttacker; public CantAttackYouAllEffect(Duration duration) { - this(duration, new FilterCreaturePermanent()); + this(duration, new FilterCreaturePermanent("creatures")); } public CantAttackYouAllEffect(Duration duration, FilterCreaturePermanent filter) { super(duration, Outcome.Benefit); this.filterAttacker = filter; - staticText = "Creatures can't attack you"; + staticText = filterAttacker.getMessage() + " can't attack you"; } CantAttackYouAllEffect(final CantAttackYouAllEffect effect) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/CommanderManaReplacementEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/CommanderManaReplacementEffect.java index b3e4e3de2c1..c8f0656e373 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/CommanderManaReplacementEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/CommanderManaReplacementEffect.java @@ -81,31 +81,31 @@ public class CommanderManaReplacementEffect extends ReplacementEffectImpl { Mana mana = ((ManaEvent) event).getMana(); if (mana.getBlack() > 0 && !commanderMana.isBlack()) { for (int i = 0; i < mana.getBlack(); i++) { - mana.increaseColorless(); + mana.increaseGeneric(); } mana.setBlack(0); } if (mana.getBlue() > 0 && !commanderMana.isBlue()) { for (int i = 0; i < mana.getBlue(); i++) { - mana.increaseColorless(); + mana.increaseGeneric(); } mana.setBlue(0); } if (mana.getGreen() > 0 && !commanderMana.isGreen()) { for (int i = 0; i < mana.getGreen(); i++) { - mana.increaseColorless(); + mana.increaseGeneric(); } mana.setGreen(0); } if (mana.getRed() > 0 && !commanderMana.isRed()) { for (int i = 0; i < mana.getRed(); i++) { - mana.increaseColorless(); + mana.increaseGeneric(); } mana.setRed(0); } if (mana.getWhite() > 0 && !commanderMana.isWhite()) { for (int i = 0; i < mana.getWhite(); i++) { - mana.increaseColorless(); + mana.increaseGeneric(); } mana.setWhite(0); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityAllEffect.java index 7ac0ca017e2..c396066e68d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityAllEffect.java @@ -33,6 +33,7 @@ import java.util.UUID; import mage.MageObject; import mage.MageObjectReference; import mage.abilities.Ability; +import mage.abilities.Mode; import mage.abilities.TriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.effects.ContinuousEffectImpl; @@ -77,7 +78,6 @@ public class GainAbilityAllEffect extends ContinuousEffectImpl { this.ability = ability; this.filter = filter; this.excludeSource = excludeSource; - setText(); } public GainAbilityAllEffect(final GainAbilityAllEffect effect) { @@ -141,8 +141,14 @@ public class GainAbilityAllEffect extends ContinuousEffectImpl { return true; } - private void setText() { + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + StringBuilder sb = new StringBuilder(); + boolean quotes = (ability instanceof SimpleActivatedAbility) || (ability instanceof TriggeredAbility); if (excludeSource) { sb.append("Other "); @@ -171,6 +177,6 @@ public class GainAbilityAllEffect extends ContinuousEffectImpl { if (duration.toString().length() > 0) { sb.append(" ").append(duration.toString()); } - staticText = sb.toString(); + return sb.toString(); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainProtectionFromColorAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainProtectionFromColorAllEffect.java new file mode 100644 index 00000000000..de153c0b625 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainProtectionFromColorAllEffect.java @@ -0,0 +1,103 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.abilities.effects.common.continuous; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.keyword.ProtectionAbility; +import mage.choices.ChoiceColor; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author LoneFox + */ +public class GainProtectionFromColorAllEffect extends GainAbilityAllEffect { + + protected ChoiceColor choice; + + public GainProtectionFromColorAllEffect(Duration duration, FilterPermanent filter) { + super(new ProtectionAbility(new FilterCard()), duration, filter); + choice = new ChoiceColor(true); + } + + public GainProtectionFromColorAllEffect(final GainProtectionFromColorAllEffect effect) { + super(effect); + choice = effect.choice; + } + + @Override + public GainProtectionFromColorAllEffect copy() { + return new GainProtectionFromColorAllEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + FilterCard protectionFilter = (FilterCard)((ProtectionAbility)ability).getFilter(); + protectionFilter.add(new ColorPredicate(choice.getColor())); + protectionFilter.setMessage(choice.getChoice()); + ((ProtectionAbility)ability).setFilter(protectionFilter); + return super.apply(game, source); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + MageObject sourceObject = game.getObject(source.getSourceId()); + Player controller = game.getPlayer(source.getControllerId()); + if(sourceObject != null && controller != null) { + choice.clearChoice(); + while(!choice.isChosen()) { + controller.choose(Outcome.Protect, choice, game); + if(!controller.canRespond()) { + return; + } + } + if(choice.isChosen() && !game.isSimulation()) { + game.informPlayers(sourceObject.getLogName() + ": " + controller.getLogName() + " has chosen protection from " + choice.getChoice()); } + } + } + + @Override + public String getText(Mode mode) { + if(staticText != null && !staticText.isEmpty()) { + return staticText; + } + + String text = "Choose a color. " + filter.getMessage() + " gain protection from the chosen color " + duration.toString(); + + return text; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/UntapSourceDuringEachOtherPlayersUntapStepEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/UntapSourceDuringEachOtherPlayersUntapStepEffect.java index 9cb410a024c..4d7010102b6 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/UntapSourceDuringEachOtherPlayersUntapStepEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/UntapSourceDuringEachOtherPlayersUntapStepEffect.java @@ -65,7 +65,9 @@ public class UntapSourceDuringEachOtherPlayersUntapStepEffect extends Continuous applied = Boolean.FALSE; } if (!applied && layer.equals(Layer.RulesEffects)) { - if (!source.getControllerId().equals(game.getActivePlayerId()) && game.getStep().getType() == PhaseStep.UNTAP) { + if (!source.getControllerId().equals(game.getActivePlayerId()) + && game.getStep() != null + && game.getStep().getType() == PhaseStep.UNTAP) { game.getState().setValue(source.getSourceId() + "applied", true); Permanent permanent = (Permanent) game.getPermanent(source.getSourceId()); if (permanent != null) { @@ -79,7 +81,7 @@ public class UntapSourceDuringEachOtherPlayersUntapStepEffect extends Continuous } } } else if (applied && layer.equals(Layer.RulesEffects)) { - if (game.getStep().getType() == PhaseStep.END_TURN) { + if (game.getStep() != null && game.getStep().getType() == PhaseStep.END_TURN) { game.getState().setValue(source.getSourceId() + "applied", false); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/CommanderCostModification.java b/Mage/src/main/java/mage/abilities/effects/common/cost/CommanderCostModification.java index 73cb10d7700..dc503ffccd1 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/cost/CommanderCostModification.java +++ b/Mage/src/main/java/mage/abilities/effects/common/cost/CommanderCostModification.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,7 +20,7 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. @@ -40,15 +40,14 @@ import mage.game.Game; * * @author Plopman */ - //20130711 /*903.10. A player may cast a commander he or she owns from the command zone. * Doing so costs that player an additional {2} for each previous time he or she cast that commander from the command zone that game. * */ public class CommanderCostModification extends CostModificationEffectImpl { - private UUID commanderId; - + private final UUID commanderId; + public CommanderCostModification(UUID commanderId) { super(Duration.Custom, Outcome.Neutral, CostModificationType.INCREASE_COST); this.commanderId = commanderId; @@ -61,22 +60,17 @@ public class CommanderCostModification extends CostModificationEffectImpl { @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { - Integer castCount = (Integer)game.getState().getValue(commanderId + "_castCount"); - if(castCount == null){ - castCount = 0; - game.getState().setValue(commanderId + "_castCount", castCount); - } - abilityToModify.getManaCostsToPay().add(new GenericManaCost(2*castCount)); + Integer castCount = (Integer) game.getState().getValue(commanderId + "_castCount"); + if (castCount > 0) { + abilityToModify.getManaCostsToPay().add(new GenericManaCost(2 * castCount)); + } return true; - + } @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify instanceof CastCommanderAbility && abilityToModify.getSourceId().equals(commanderId)) { - return true; - } - return false; + return abilityToModify instanceof CastCommanderAbility && abilityToModify.getSourceId().equals(commanderId); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionAllEffect.java index 7384cc01ac1..155753c83f0 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionAllEffect.java @@ -81,7 +81,7 @@ public class SpellsCostReductionAllEffect extends CostModificationEffectImpl { public boolean apply(Game game, Ability source, Ability abilityToModify) { if (upTo) { Mana mana = abilityToModify.getManaCostsToPay().getMana(); - int reduceMax = mana.getColorless(); + int reduceMax = mana.getGeneric(); if (reduceMax > 2) { reduceMax = 2; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionControllerEffect.java index 9fd1453f429..dab53df1b32 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionControllerEffect.java @@ -101,7 +101,7 @@ public class SpellsCostReductionControllerEffect extends CostModificationEffectI } else { if (upTo) { Mana mana = abilityToModify.getManaCostsToPay().getMana(); - int reduceMax = mana.getColorless(); + int reduceMax = mana.getGeneric(); if (reduceMax > amount) { reduceMax = amount; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersTargetEffect.java index 9f421323473..c5e48f6f8d1 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersTargetEffect.java @@ -88,7 +88,11 @@ public class AddCountersTargetEffect extends OneShotEffect { if (permanent != null) { if (counter != null) { Counter newCounter = counter.copy(); - newCounter.add(amount.calculate(game, source, this)); + int calculated = amount.calculate(game, source, this); + if (calculated > 0 && newCounter.getCount() > 0) { + newCounter.remove(newCounter.getCount()); + } + newCounter.add(calculated); int before = permanent.getCounters().getCount(counter.getName()); permanent.addCounters(newCounter, game); int numberAdded = permanent.getCounters().getCount(counter.getName()) - before; diff --git a/Mage/src/main/java/mage/abilities/effects/common/counter/DistributeCountersEffect.java b/Mage/src/main/java/mage/abilities/effects/common/counter/DistributeCountersEffect.java index d1fdf6be711..d0135d2cd52 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/counter/DistributeCountersEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/counter/DistributeCountersEffect.java @@ -37,7 +37,6 @@ import mage.constants.Outcome; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.Target; import mage.util.CardUtil; @@ -75,23 +74,20 @@ public class DistributeCountersEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - if(source.getTargets().size() > 0) { + if (source.getTargets().size() > 0) { Target multiTarget = source.getTargets().get(0); - for(UUID target : multiTarget.getTargets()) { + for (UUID target : multiTarget.getTargets()) { Permanent permanent = game.getPermanent(target); - if(permanent != null) { + if (permanent != null) { permanent.addCounters(counterType.createInstance(multiTarget.getTargetAmount(target)), game); } } - if(removeAtEndOfTurn) { + if (removeAtEndOfTurn) { DelayedTriggeredAbility ability = new AtTheBeginOfNextCleanupDelayedTriggeredAbility( - new RemoveCountersAtEndOfTurn(counterType)); - ability.setSourceId(source.getSourceId()); - ability.setControllerId(source.getControllerId()); - ability.setSourceObject(source.getSourceObject(game), game); + new RemoveCountersAtEndOfTurn(counterType)); ability.getTargets().addAll(source.getTargets()); - game.addDelayedTriggeredAbility(ability); + game.addDelayedTriggeredAbility(ability, source); } return true; @@ -107,9 +103,9 @@ public class DistributeCountersEffect extends OneShotEffect { String name = counterType.getName(); String text = "distribute " + CardUtil.numberToText(amount) + " " + name + " counters among " + targetDescription + "."; - if(removeAtEndOfTurn) { + if (removeAtEndOfTurn) { text += " For each " + name + " counter you put on a creature this way, remove a " - + name + " counter from that creature at the beginning of the next cleanup step."; + + name + " counter from that creature at the beginning of the next cleanup step."; } return text; } @@ -124,7 +120,7 @@ class RemoveCountersAtEndOfTurn extends OneShotEffect { this.counterType = counterType; String name = counterType.getName(); staticText = "For each " + name + " counter you put on a creature this way, remove a " - + name + " counter from that creature at the beginning of the next cleanup step."; + + name + " counter from that creature at the beginning of the next cleanup step."; } public RemoveCountersAtEndOfTurn(final RemoveCountersAtEndOfTurn effect) { @@ -139,11 +135,11 @@ class RemoveCountersAtEndOfTurn extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - if(source.getTargets().size() > 0) { + if (source.getTargets().size() > 0) { Target multiTarget = source.getTargets().get(0); - for(UUID target : multiTarget.getTargets()) { + for (UUID target : multiTarget.getTargets()) { Permanent permanent = game.getPermanent(target); - if(permanent != null) { + if (permanent != null) { permanent.removeCounters(counterType.getName(), multiTarget.getTargetAmount(target), game); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/CastOnlyDuringPhaseStepSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/CastOnlyDuringPhaseStepSourceEffect.java new file mode 100644 index 00000000000..04a5308816e --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/CastOnlyDuringPhaseStepSourceEffect.java @@ -0,0 +1,76 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.effects.common.ruleModifying; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.constants.TurnPhase; +import mage.game.Game; +import mage.game.events.GameEvent; + +/** + * + * @author LevelX2 + */ +public class CastOnlyDuringPhaseStepSourceEffect extends ContinuousRuleModifyingEffectImpl { + + private final TurnPhase turnPhase; + private final PhaseStep phaseStep; + private final Condition condition; + + public CastOnlyDuringPhaseStepSourceEffect(TurnPhase turnPhase, PhaseStep phaseStep, Condition condition) { + super(Duration.EndOfGame, Outcome.Detriment); + this.turnPhase = turnPhase; + this.phaseStep = phaseStep; + this.condition = condition; + staticText = setText(); + } + + private CastOnlyDuringPhaseStepSourceEffect(final CastOnlyDuringPhaseStepSourceEffect effect) { + super(effect); + this.turnPhase = effect.turnPhase; + this.phaseStep = effect.phaseStep; + this.condition = effect.condition; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return GameEvent.EventType.CAST_SPELL.equals(event.getType()); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getSourceId().equals(source.getSourceId())) { + return (turnPhase == null || !game.getPhase().getType().equals(turnPhase)) + && (phaseStep == null || !game.getTurn().getStepType().equals(phaseStep)) + && (condition == null || !condition.apply(game, source)); + } + return false; + } + + @Override + public CastOnlyDuringPhaseStepSourceEffect copy() { + return new CastOnlyDuringPhaseStepSourceEffect(this); + } + + private String setText() { + StringBuilder sb = new StringBuilder("cast {this} only during "); + if (turnPhase != null) { + sb.append(turnPhase.toString()); + } + if (phaseStep != null) { + sb.append("the ").append(phaseStep.getStepText()); + } + if (condition != null) { + sb.append(" ").append(condition.toString()); + } + return sb.toString(); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/turn/AddExtraTurnControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/turn/AddExtraTurnControllerEffect.java index 82ada6f9893..dd4a0e9ad51 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/turn/AddExtraTurnControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/turn/AddExtraTurnControllerEffect.java @@ -78,10 +78,8 @@ public class AddExtraTurnControllerEffect extends OneShotEffect { game.getState().getTurnMods().add(extraTurn); if (loseGameAtEnd) { LoseGameDelayedTriggeredAbility delayedTriggeredAbility = new LoseGameDelayedTriggeredAbility(); - delayedTriggeredAbility.setSourceId(source.getSourceId()); - delayedTriggeredAbility.setControllerId(source.getControllerId()); delayedTriggeredAbility.setConnectedTurnMod(extraTurn.getId()); - game.addDelayedTriggeredAbility(delayedTriggeredAbility); + game.addDelayedTriggeredAbility(delayedTriggeredAbility, source); } } return true; 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 9d33f9cf9b7..2f97f77f28e 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/SupportEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/SupportEffect.java @@ -44,27 +44,22 @@ import mage.util.CardUtil; public class SupportEffect extends AddCountersTargetEffect { private final DynamicValue amountSupportTargets; - private boolean otherPermanent; + private final boolean otherPermanent; - public SupportEffect(Card card, int amount) { - this(new StaticValue(amount)); + public SupportEffect(Card card, int amount, boolean otherPermanent) { + super(CounterType.P1P1.createInstance(0), new StaticValue(1)); + this.amountSupportTargets = new StaticValue(amount); + this.otherPermanent = otherPermanent; if (card.getCardType().contains(CardType.INSTANT) || card.getCardType().contains(CardType.SORCERY)) { - otherPermanent = false; card.getSpellAbility().addTarget(new TargetCreaturePermanent(0, amount, new FilterCreaturePermanent("target creatures"), false)); - } else { - otherPermanent = true; } - } - - public SupportEffect(DynamicValue amount) { - super(CounterType.P1P1.createInstance(), new StaticValue(1)); - this.amountSupportTargets = amount; - this.staticText = setText(); + staticText = setText(); } public SupportEffect(final SupportEffect effect) { super(effect); this.amountSupportTargets = effect.amountSupportTargets; + this.otherPermanent = effect.otherPermanent; } @Override diff --git a/Mage/src/main/java/mage/abilities/keyword/ChampionAbility.java b/Mage/src/main/java/mage/abilities/keyword/ChampionAbility.java index 568a1ef9463..21becfa5503 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ChampionAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ChampionAbility.java @@ -34,6 +34,7 @@ import mage.abilities.Ability; import mage.abilities.StaticAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.effects.common.ReturnFromExileForSourceEffect; import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; @@ -161,7 +162,7 @@ class ChampionExileCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); MageObject sourceObject = ability.getSourceObject(game); if (controller != null && sourceObject != null) { diff --git a/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java b/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java index 232be52c57c..fc7cc422c07 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java @@ -122,7 +122,7 @@ public class ConvokeAbility extends SimpleStaticAbility implements AlternateMana // create filter for possible creatures to tap FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); filter.add(Predicates.not(new TappedPredicate())); - if (unpaid.getMana().getColorless() == 0) { + if (unpaid.getMana().getGeneric() == 0) { List colorPredicates = new ArrayList<>(); if (unpaid.getMana().getBlack() > 0) { colorPredicates.add(new ColorPredicate(ObjectColor.BLACK)); @@ -182,7 +182,7 @@ class ConvokeEffect extends OneShotEffect { public ConvokeEffect(ManaCost unpaid) { super(Outcome.Benefit); this.unpaid = unpaid; - this.staticText = "Convoke (Your creatures can help cast this spell. Each creature you tap while casting this spell pays for {1} or one mana of that creature's color.)"; + this.staticText = "Convoke (Your creatures can help cast this spell. Each creature you tap while casting this spell pays for {C} or one mana of that creature's color.)"; } public ConvokeEffect(final ConvokeEffect effect) { diff --git a/Mage/src/main/java/mage/abilities/keyword/CumulativeUpkeepAbility.java b/Mage/src/main/java/mage/abilities/keyword/CumulativeUpkeepAbility.java index 2e6c6d83fca..0526c58e20b 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CumulativeUpkeepAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CumulativeUpkeepAbility.java @@ -122,7 +122,7 @@ class CumulativeUpkeepEffect extends OneShotEffect { if (player.chooseUse(Outcome.Benefit, totalCost.getText() + "?", source, game)) { totalCost.clearPaid(); int bookmark = game.bookmarkState(); - if (totalCost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (totalCost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { game.fireEvent(new GameEvent(EventType.PAID_CUMULATIVE_UPKEEP, permanent.getId(), permanent.getId(), player.getId(), ageCounter, false)); return true; } else { diff --git a/Mage/src/main/java/mage/abilities/keyword/DashAbility.java b/Mage/src/main/java/mage/abilities/keyword/DashAbility.java index b6a876053b0..117f59775a4 100644 --- a/Mage/src/main/java/mage/abilities/keyword/DashAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/DashAbility.java @@ -232,10 +232,7 @@ class DashAddDelayedTriggeredAbilityEffect extends OneShotEffect { // init target pointer now because the dashed creature will only be returned from battlefield zone (now in entering state so zone change counter is not raised yet) effect.setTargetPointer(new FixedTarget(source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId()) + 1)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } return false; diff --git a/Mage/src/main/java/mage/abilities/keyword/DelveAbility.java b/Mage/src/main/java/mage/abilities/keyword/DelveAbility.java index 45d91c5e26e..b823c296340 100644 --- a/Mage/src/main/java/mage/abilities/keyword/DelveAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/DelveAbility.java @@ -98,11 +98,11 @@ public class DelveAbility extends SimpleStaticAbility implements AlternateManaPa public void addSpecialAction(Ability source, Game game, ManaCost unpaid) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null && controller.getGraveyard().size() > 0) { - if (unpaid.getMana().getColorless() > 0 && source.getAbilityType().equals(AbilityType.SPELL)) { + if (unpaid.getMana().getGeneric() > 0 && source.getAbilityType().equals(AbilityType.SPELL)) { SpecialAction specialAction = new DelveSpecialAction(); specialAction.setControllerId(source.getControllerId()); specialAction.setSourceId(source.getSourceId()); - int unpaidAmount = unpaid.getMana().getColorless(); + int unpaidAmount = unpaid.getMana().getGeneric(); if (!controller.getManaPool().isAutoPayment() && unpaidAmount > 1) { unpaidAmount = 1; } @@ -157,7 +157,7 @@ class DelveEffect extends OneShotEffect { List exiledCards = exileFromGraveCost.getExiledCards(); if (exiledCards.size() > 0) { ManaPool manaPool = controller.getManaPool(); - manaPool.addMana(new Mana(0, 0, 0, 0, 0, exiledCards.size(), 0), game, source); + manaPool.addMana(new Mana(0, 0, 0, 0, 0, 0, 0, exiledCards.size()), game, source); manaPool.unlockManaType(ManaType.COLORLESS); String keyString = CardUtil.getCardZoneString("delvedCards", source.getSourceId(), game); @SuppressWarnings("unchecked") diff --git a/Mage/src/main/java/mage/abilities/keyword/DevoidAbility.java b/Mage/src/main/java/mage/abilities/keyword/DevoidAbility.java index 7aff3d5e46a..c05b3598915 100644 --- a/Mage/src/main/java/mage/abilities/keyword/DevoidAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/DevoidAbility.java @@ -22,6 +22,7 @@ public class DevoidAbility extends SimpleStaticAbility { color.setGreen(false); color.setBlue(false); color.setRed(false); + setRuleAtTheTop(true); } public DevoidAbility(final DevoidAbility ability) { diff --git a/Mage/src/main/java/mage/abilities/keyword/EchoAbility.java b/Mage/src/main/java/mage/abilities/keyword/EchoAbility.java index 6b8a129a809..e3c05310738 100644 --- a/Mage/src/main/java/mage/abilities/keyword/EchoAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/EchoAbility.java @@ -147,7 +147,7 @@ class EchoEffect extends OneShotEffect { if (controller != null && source.getSourceObjectIfItStillExists(game) != null) { if (controller.chooseUse(Outcome.Benefit, "Pay " + cost.getText() /* + " or sacrifice " + permanent.getName() */ + "?", source, game)) { cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { return true; } } diff --git a/Mage/src/main/java/mage/abilities/keyword/ExtortAbility.java b/Mage/src/main/java/mage/abilities/keyword/ExtortAbility.java index d700e557387..95d6e040aeb 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ExtortAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ExtortAbility.java @@ -103,7 +103,7 @@ class ExtortEffect extends OneShotEffect { if (player != null && permanent != null) { if (player.chooseUse(Outcome.Damage, new StringBuilder("Extort opponents? (").append(permanent.getName()).append(")").toString(), source, game)) { Cost cost = new ManaCostsImpl("{W/B}"); - if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { + if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { int loseLife = 0; for (UUID opponentId : game.getOpponents(source.getControllerId())) { loseLife += game.getPlayer(opponentId).loseLife(1, game); diff --git a/Mage/src/main/java/mage/abilities/keyword/MyriadAbility.java b/Mage/src/main/java/mage/abilities/keyword/MyriadAbility.java index a6da1169771..1043cb6475d 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MyriadAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MyriadAbility.java @@ -19,6 +19,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.targetpointer.FixedTarget; +import mage.target.targetpointer.FixedTargets; public class MyriadAbility extends AttacksTriggeredAbility { @@ -70,15 +71,10 @@ class MyriadEffect extends OneShotEffect { PutTokenOntoBattlefieldCopyTargetEffect effect = new PutTokenOntoBattlefieldCopyTargetEffect(controller.getId(), null, false, 1, true, true, playerId); effect.setTargetPointer(new FixedTarget(sourceObject, game)); effect.apply(game, source); - for (Permanent tokenPermanent : effect.getAddedPermanent()) { - ExileTargetEffect exileEffect = new ExileTargetEffect(); - exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); - DelayedTriggeredAbility delayedAbility = new AtTheEndOfCombatDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); - } + ExileTargetEffect exileEffect = new ExileTargetEffect(); + exileEffect.setTargetPointer(new FixedTargets(effect.getAddedPermanent(), game)); + DelayedTriggeredAbility delayedAbility = new AtTheEndOfCombatDelayedTriggeredAbility(exileEffect); + game.addDelayedTriggeredAbility(delayedAbility, source); } } diff --git a/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java b/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java index 8fc900bd3d1..c3716f5984f 100644 --- a/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java @@ -157,7 +157,7 @@ class ReturnAttackerToHandTargetCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { if (targets.choose(Outcome.ReturnToHand, controllerId, sourceId, game)) { for (UUID targetId : targets.get(0).getTargets()) { Permanent permanent = game.getPermanent(targetId); @@ -197,7 +197,7 @@ class RevealNinjutsuCardCost extends CostImpl { } @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player player = game.getPlayer(controllerId); Card card = player.getHand().get(ability.getSourceId(), game); diff --git a/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java b/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java index 7ab46d546e0..6ae658ce79b 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java @@ -127,9 +127,7 @@ class ReboundCastFromHandReplacementEffect extends ReplacementEffectImpl { if (player != null) { // Add the delayed triggered effect ReboundEffectCastFromExileDelayedTrigger trigger = new ReboundEffectCastFromExileDelayedTrigger(source.getSourceId(), source.getSourceId()); - trigger.setControllerId(source.getControllerId()); - trigger.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(trigger); + game.addDelayedTriggeredAbility(trigger, source); player.moveCardToExileWithInfo(sourceCard, sourceCard.getId(), player.getName() + " Rebound", source.getSourceId(), game, Zone.STACK, true); return true; diff --git a/Mage/src/main/java/mage/abilities/keyword/RecoverAbility.java b/Mage/src/main/java/mage/abilities/keyword/RecoverAbility.java index bd8cbb938d3..593ed80aa02 100644 --- a/Mage/src/main/java/mage/abilities/keyword/RecoverAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/RecoverAbility.java @@ -119,7 +119,7 @@ class RecoverEffect extends OneShotEffect { && game.getState().getZone(source.getSourceId()).equals(Zone.GRAVEYARD)) { if (controller.chooseUse(Outcome.Damage, "Pay " + cost.getText() + " to recover " + sourceCard.getLogName() + "? (Otherwise the card will be exiled)", source, game)) { cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), controller.getId(), false)) { + if (cost.pay(source, game, source.getSourceId(), controller.getId(), false, null)) { return new ReturnToHandSourceEffect().apply(game, source); } } diff --git a/Mage/src/main/java/mage/abilities/keyword/ReplicateAbility.java b/Mage/src/main/java/mage/abilities/keyword/ReplicateAbility.java index ed5c34e1a2f..752bcd6c7bd 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ReplicateAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ReplicateAbility.java @@ -192,9 +192,9 @@ class ReplicateTriggeredAbility extends TriggeredAbilityImpl { if (event.getSourceId().equals(this.sourceId)) { StackObject spell = game.getStack().getStackObject(this.sourceId); if (spell instanceof Spell) { - Card card = game.getCard(spell.getSourceId()); + Card card = ((Spell) spell).getCard(); if (card != null) { - for (Ability ability : card.getAbilities()) { + for (Ability ability : card.getAbilities(game)) { if (ability instanceof ReplicateAbility) { if (((ReplicateAbility) ability).isActivated()) { for (Effect effect : this.getEffects()) { @@ -237,7 +237,7 @@ class ReplicateCopyEffect extends OneShotEffect { // reset replicate now so the copies don't report x times Replicate Card card = game.getCard(spell.getSourceId()); if (card != null) { - for (Ability ability : card.getAbilities()) { + for (Ability ability : card.getAbilities(game)) { if (ability instanceof ReplicateAbility) { if (((ReplicateAbility) ability).isActivated()) { ((ReplicateAbility) ability).resetReplicate(); @@ -253,7 +253,7 @@ class ReplicateCopyEffect extends OneShotEffect { game.getStack().push(copy); copy.chooseNewTargets(game, source.getControllerId()); if (!game.isSimulation()) { - game.informPlayers(new StringBuilder(controller.getLogName()).append(copy.getActivatedMessage(game)).toString()); + game.informPlayers(controller.getLogName() + copy.getActivatedMessage(game)); } } return true; diff --git a/Mage/src/main/java/mage/abilities/keyword/SupportAbility.java b/Mage/src/main/java/mage/abilities/keyword/SupportAbility.java index 6f7b9fdff6d..248df3d5841 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SupportAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SupportAbility.java @@ -42,7 +42,7 @@ import mage.target.common.TargetCreaturePermanent; public class SupportAbility extends EntersBattlefieldTriggeredAbility { public SupportAbility(Card card, int amount) { - super(new SupportEffect(card, amount), false); + super(new SupportEffect(card, amount, true)); if (!card.getCardType().contains(CardType.INSTANT) && !card.getCardType().contains(CardType.SORCERY)) { FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures"); if (card.getCardType().contains(CardType.CREATURE)) { diff --git a/Mage/src/main/java/mage/abilities/keyword/SurgeAbility.java b/Mage/src/main/java/mage/abilities/keyword/SurgeAbility.java index 84c64cd49d5..6b82e3087af 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SurgeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SurgeAbility.java @@ -57,12 +57,13 @@ public class SurgeAbility extends SpellAbility { this.spellAbilityType = SpellAbilityType.BASE_ALTERNATE; this.timing = card.getSpellAbility().getTiming(); this.setRuleAtTheTop(true); - rule = "Surge " + surgeCosts + this.rule = "Surge " + surgeCosts + " (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn.)"; } public SurgeAbility(final SurgeAbility ability) { super(ability); + this.rule = ability.rule; } @Override diff --git a/Mage/src/main/java/mage/abilities/mana/ActivateOncePerTurnManaAbility.java b/Mage/src/main/java/mage/abilities/mana/ActivateOncePerTurnManaAbility.java index d906e8fd03c..0fdcfc4be51 100644 --- a/Mage/src/main/java/mage/abilities/mana/ActivateOncePerTurnManaAbility.java +++ b/Mage/src/main/java/mage/abilities/mana/ActivateOncePerTurnManaAbility.java @@ -61,7 +61,7 @@ public class ActivateOncePerTurnManaAbility extends ManaAbility { public ActivateOncePerTurnManaAbility(Zone zone, AddManaOfAnyColorEffect effect, Cost cost) { super(zone, effect, cost); - this.netMana.add(new Mana(0,0,0,0,0,0,effect.getAmount())); + this.netMana.add(new Mana(0,0,0,0,0,0,effect.getAmount(), 0)); } public ActivateOncePerTurnManaAbility(ActivateOncePerTurnManaAbility ability) { diff --git a/Mage/src/main/java/mage/abilities/mana/AnyColorOpponentLandsProduceManaAbility.java b/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java similarity index 78% rename from Mage/src/main/java/mage/abilities/mana/AnyColorOpponentLandsProduceManaAbility.java rename to Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java index 1deea82442e..a2db740523d 100644 --- a/Mage/src/main/java/mage/abilities/mana/AnyColorOpponentLandsProduceManaAbility.java +++ b/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java @@ -50,42 +50,42 @@ import mage.players.Player; * * @author LevelX2 */ +public class AnyColorLandsProduceManaAbility extends ManaAbility { -public class AnyColorOpponentLandsProduceManaAbility extends ManaAbility { - - public AnyColorOpponentLandsProduceManaAbility() { - super(Zone.BATTLEFIELD, new AnyColorOpponentLandsProduceManaEffect(),new TapSourceCost()); + public AnyColorLandsProduceManaAbility(TargetController targetController) { + super(Zone.BATTLEFIELD, new AnyColorLandsProduceManaEffect(targetController), new TapSourceCost()); } - public AnyColorOpponentLandsProduceManaAbility(final AnyColorOpponentLandsProduceManaAbility ability) { + public AnyColorLandsProduceManaAbility(final AnyColorLandsProduceManaAbility ability) { super(ability); } @Override - public AnyColorOpponentLandsProduceManaAbility copy() { - return new AnyColorOpponentLandsProduceManaAbility(this); + public AnyColorLandsProduceManaAbility copy() { + return new AnyColorLandsProduceManaAbility(this); } @Override public List getNetMana(Game game) { - return ((AnyColorOpponentLandsProduceManaEffect)getEffects().get(0)).getNetMana(game, this); + return ((AnyColorLandsProduceManaEffect) getEffects().get(0)).getNetMana(game, this); } } -class AnyColorOpponentLandsProduceManaEffect extends ManaEffect { +class AnyColorLandsProduceManaEffect extends ManaEffect { - private static final FilterPermanent filter = new FilterLandPermanent(); - static { - filter.add(new ControllerPredicate(TargetController.OPPONENT)); - } + private final FilterPermanent filter; - public AnyColorOpponentLandsProduceManaEffect() { + public AnyColorLandsProduceManaEffect(TargetController targetController) { super(); - staticText = "Add to your mana pool one mana of any color that a land an opponent controls could produce"; + filter = new FilterLandPermanent(); + filter.add(new ControllerPredicate(targetController)); + String text = targetController == TargetController.OPPONENT ? "an opponent controls" : "you control"; + staticText = "Add to your mana pool one mana of any color that a land " + text + " could produce"; } - public AnyColorOpponentLandsProduceManaEffect(final AnyColorOpponentLandsProduceManaEffect effect) { + public AnyColorLandsProduceManaEffect(final AnyColorLandsProduceManaEffect effect) { super(effect); + this.filter = effect.filter.copy(); } @Override @@ -140,7 +140,7 @@ class AnyColorOpponentLandsProduceManaEffect extends ManaEffect { case "White": mana.setWhite(1); break; - } + } checkToFirePossibleEvents(mana, game, source); player.getManaPool().addMana(mana, game, source); } @@ -160,7 +160,7 @@ class AnyColorOpponentLandsProduceManaEffect extends ManaEffect { Abilities mana = land.getAbilities().getManaAbilities(Zone.BATTLEFIELD); for (ManaAbility ability : mana) { if (!ability.equals(source) && ability.definesMana()) { - for (Mana netMana: ability.getNetMana(game)) { + for (Mana netMana : ability.getNetMana(game)) { types.add(netMana); } } @@ -169,7 +169,7 @@ class AnyColorOpponentLandsProduceManaEffect extends ManaEffect { return types; } - public List getNetMana(Game game, Ability source) { + public List getNetMana(Game game, Ability source) { List netManas = new ArrayList<>(); Mana types = getManaTypes(game, source); if (types.getBlack() > 0) { @@ -188,13 +188,13 @@ class AnyColorOpponentLandsProduceManaEffect extends ManaEffect { netManas.add(new Mana(ColoredManaSymbol.W)); } if (types.getColorless() > 0) { - netManas.add(new Mana(0,0,0,0,0,1,0)); + netManas.add(new Mana(0, 0, 0, 0, 0, 0, 0, 1)); } return netManas; } @Override - public AnyColorOpponentLandsProduceManaEffect copy() { - return new AnyColorOpponentLandsProduceManaEffect(this); + public AnyColorLandsProduceManaEffect copy() { + return new AnyColorLandsProduceManaEffect(this); } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/abilities/mana/AnyColorManaAbility.java b/Mage/src/main/java/mage/abilities/mana/AnyColorManaAbility.java index 6a0e98e090f..1b4b7f50950 100644 --- a/Mage/src/main/java/mage/abilities/mana/AnyColorManaAbility.java +++ b/Mage/src/main/java/mage/abilities/mana/AnyColorManaAbility.java @@ -40,7 +40,7 @@ public class AnyColorManaAbility extends ManaAbility { public AnyColorManaAbility(Cost cost) { super(Zone.BATTLEFIELD, new AddManaOfAnyColorEffect(), cost); - this.netMana.add(new Mana(0,0,0,0,0,0,1)); + this.netMana.add(new Mana(0,0,0,0,0,0,1, 0)); } public AnyColorManaAbility(final AnyColorManaAbility ability) { diff --git a/Mage/src/main/java/mage/abilities/mana/ColorlessManaAbility.java b/Mage/src/main/java/mage/abilities/mana/ColorlessManaAbility.java index 6b1c725d637..629d640e100 100644 --- a/Mage/src/main/java/mage/abilities/mana/ColorlessManaAbility.java +++ b/Mage/src/main/java/mage/abilities/mana/ColorlessManaAbility.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.mana; import mage.Mana; @@ -39,7 +38,7 @@ public class ColorlessManaAbility extends BasicManaAbility { public ColorlessManaAbility() { super(new BasicManaEffect(Mana.ColorlessMana(1))); - this.netMana.add(new Mana(0,0,0,0,0,1,0)); + this.netMana.add(new Mana(0, 0, 0, 0, 0, 0, 0, 1)); } public ColorlessManaAbility(ColorlessManaAbility ability) { diff --git a/Mage/src/main/java/mage/abilities/mana/ConditionalAnyColorManaAbility.java b/Mage/src/main/java/mage/abilities/mana/ConditionalAnyColorManaAbility.java index 70190ef50a0..46e0a7c052b 100644 --- a/Mage/src/main/java/mage/abilities/mana/ConditionalAnyColorManaAbility.java +++ b/Mage/src/main/java/mage/abilities/mana/ConditionalAnyColorManaAbility.java @@ -73,7 +73,7 @@ public class ConditionalAnyColorManaAbility extends ManaAbility { @Override public List getNetMana(Game game) { this.netMana.clear(); - this.netMana.add(new Mana(0,0,0,0,0,0, amount.calculate(game, this, null))); + this.netMana.add(new Mana(0,0,0,0,0,0, amount.calculate(game, this, null), 0)); return super.getNetMana(game); } diff --git a/Mage/src/main/java/mage/abilities/mana/ConditionalColorlessManaAbility.java b/Mage/src/main/java/mage/abilities/mana/ConditionalColorlessManaAbility.java index 37d1096b5b7..254eebd3cf3 100644 --- a/Mage/src/main/java/mage/abilities/mana/ConditionalColorlessManaAbility.java +++ b/Mage/src/main/java/mage/abilities/mana/ConditionalColorlessManaAbility.java @@ -3,7 +3,6 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ - package mage.abilities.mana; import mage.Mana; @@ -17,7 +16,6 @@ import mage.constants.Zone; * * @author LevelX2 */ - public class ConditionalColorlessManaAbility extends ManaAbility { public ConditionalColorlessManaAbility(int amount, ConditionalManaBuilder manaBuilder) { @@ -25,8 +23,8 @@ public class ConditionalColorlessManaAbility extends ManaAbility { } public ConditionalColorlessManaAbility(Cost cost, int amount, ConditionalManaBuilder manaBuilder) { - super(Zone.BATTLEFIELD, new AddConditionalColorlessManaEffect(amount, manaBuilder), cost); - this.netMana.add(new Mana(0,0,0,0,0,amount,0)); + super(Zone.BATTLEFIELD, new AddConditionalColorlessManaEffect(amount, manaBuilder), cost); + this.netMana.add(new Mana(0, 0, 0, 0, 0, 0, 0, amount)); } public ConditionalColorlessManaAbility(final ConditionalColorlessManaAbility ability) { diff --git a/Mage/src/main/java/mage/abilities/mana/ManaOptions.java b/Mage/src/main/java/mage/abilities/mana/ManaOptions.java index 65a3518e6af..0dfc4b55403 100644 --- a/Mage/src/main/java/mage/abilities/mana/ManaOptions.java +++ b/Mage/src/main/java/mage/abilities/mana/ManaOptions.java @@ -248,11 +248,11 @@ public class ManaOptions extends ArrayList { Mana oldMan = mana.copy(); if (mana.includesMana(cost)) { // colorless costs can be paid with different colored mana, can lead to different color combinations - if (cost.getColorless() > 0 && cost.getColorless() > mana.getColorless()) { + if (cost.getGeneric() > 0 && cost.getGeneric() > mana.getGeneric()) { Mana coloredCost = cost.copy(); - coloredCost.setColorless(0); + coloredCost.setGeneric(0); mana.subtract(coloredCost); - for (Mana payCombination : getPossiblePayCombinations(cost.getColorless(), mana)) { + for (Mana payCombination : getPossiblePayCombinations(cost.getGeneric(), mana)) { Mana newMana = mana.copy(); newMana.subtract(payCombination); newMana.add(addMana); @@ -319,7 +319,7 @@ public class ManaOptions extends ArrayList { } } } else { - payCombinations.add(new Mana(0, 0, 0, 0, 0, number, 0)); + payCombinations.add(new Mana(0, 0, 0, 0, 0, 0, 0, number)); } return payCombinations; } diff --git a/Mage/src/main/java/mage/abilities/mana/conditional/ArtifactCastManaCondition.java b/Mage/src/main/java/mage/abilities/mana/conditional/ArtifactCastManaCondition.java index 2125e5c7a7e..1a508c2a98d 100644 --- a/Mage/src/main/java/mage/abilities/mana/conditional/ArtifactCastManaCondition.java +++ b/Mage/src/main/java/mage/abilities/mana/conditional/ArtifactCastManaCondition.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.mana.conditional; import java.util.UUID; @@ -33,6 +32,7 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.condition.Condition; +import mage.abilities.costs.Cost; import mage.constants.CardType; import mage.game.Game; @@ -40,8 +40,8 @@ import mage.game.Game; * * @author LevelX2 */ - public class ArtifactCastManaCondition extends ManaCondition implements Condition { + @Override public boolean apply(Game game, Ability source) { if (source instanceof SpellAbility) { @@ -54,7 +54,7 @@ public class ArtifactCastManaCondition extends ManaCondition implements Conditio } @Override - public boolean apply(Game game, Ability source, UUID originalId) { + public boolean apply(Game game, Ability source, UUID originalId, Cost costToPay) { return apply(game, source); } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/abilities/mana/conditional/ConditionalSpellManaBuilder.java b/Mage/src/main/java/mage/abilities/mana/conditional/ConditionalSpellManaBuilder.java index 5dfe2f7c3ae..2cfaef6a330 100644 --- a/Mage/src/main/java/mage/abilities/mana/conditional/ConditionalSpellManaBuilder.java +++ b/Mage/src/main/java/mage/abilities/mana/conditional/ConditionalSpellManaBuilder.java @@ -12,6 +12,7 @@ import mage.Mana; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.condition.Condition; +import mage.abilities.costs.Cost; import mage.abilities.mana.builder.ConditionalManaBuilder; import mage.filter.FilterSpell; import mage.game.Game; @@ -70,7 +71,7 @@ class SpellCastManaCondition extends ManaCondition implements Condition { } @Override - public boolean apply(Game game, Ability source, UUID originalId) { + public boolean apply(Game game, Ability source, UUID originalId, Cost costToPay) { return apply(game, source); } diff --git a/Mage/src/main/java/mage/abilities/mana/conditional/CreatureCastManaCondition.java b/Mage/src/main/java/mage/abilities/mana/conditional/CreatureCastManaCondition.java index fcc999c35f2..f5f29b22a35 100644 --- a/Mage/src/main/java/mage/abilities/mana/conditional/CreatureCastManaCondition.java +++ b/Mage/src/main/java/mage/abilities/mana/conditional/CreatureCastManaCondition.java @@ -1,45 +1,46 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.mana.conditional; +import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.condition.Condition; +import mage.abilities.costs.Cost; import mage.constants.CardType; import mage.game.Game; -import java.util.UUID; - /** * @author noxx */ public class CreatureCastManaCondition extends ManaCondition implements Condition { + @Override public boolean apply(Game game, Ability source) { if (source instanceof SpellAbility) { @@ -52,7 +53,7 @@ public class CreatureCastManaCondition extends ManaCondition implements Conditio } @Override - public boolean apply(Game game, Ability source, UUID originalId) { + public boolean apply(Game game, Ability source, UUID originalId, Cost costToPay) { return apply(game, source); } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/abilities/mana/conditional/ManaCondition.java b/Mage/src/main/java/mage/abilities/mana/conditional/ManaCondition.java index 468c9769a7e..23eab9ef589 100644 --- a/Mage/src/main/java/mage/abilities/mana/conditional/ManaCondition.java +++ b/Mage/src/main/java/mage/abilities/mana/conditional/ManaCondition.java @@ -1,46 +1,47 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.mana.conditional; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.Condition; +import mage.abilities.costs.Cost; import mage.game.Game; -import java.util.UUID; - /** * @author noxx */ public abstract class ManaCondition implements Condition { + @Override public boolean apply(Game game, Ability source) { return false; } - public abstract boolean apply(Game game, Ability source, UUID originalId); -} \ No newline at end of file + public abstract boolean apply(Game game, Ability source, UUID originalId, Cost costToPay); +} diff --git a/Mage/src/main/java/mage/cards/CardImpl.java b/Mage/src/main/java/mage/cards/CardImpl.java index 055b21c318c..e4ff73b6c5c 100644 --- a/Mage/src/main/java/mage/cards/CardImpl.java +++ b/Mage/src/main/java/mage/cards/CardImpl.java @@ -206,7 +206,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { protected static final ArrayList rulesError = new ArrayList() { { - add("Exception occured in rules generation"); + add("Exception occurred in rules generation"); } }; diff --git a/Mage/src/main/java/mage/cards/ExpansionSet.java b/Mage/src/main/java/mage/cards/ExpansionSet.java index 99ef9952849..3c7c8463b87 100644 --- a/Mage/src/main/java/mage/cards/ExpansionSet.java +++ b/Mage/src/main/java/mage/cards/ExpansionSet.java @@ -156,7 +156,7 @@ public abstract class ExpansionSet implements Serializable { List specialLands = getSpecialLand(); List basicLands = getCardsByRarity(Rarity.LAND); for (int i = 0; i < numBoosterLands; i++) { - if (ratioBoosterSpecialLand > 0 && rnd.nextInt(ratioBoosterSpecialLand) == 1 && specialLands != null) { + if (ratioBoosterSpecialLand > 0 && rnd.nextInt(ratioBoosterSpecialLand) == 0 && specialLands != null) { addToBooster(booster, specialLands); } else { addToBooster(booster, basicLands); @@ -174,7 +174,7 @@ public abstract class ExpansionSet implements Serializable { List rares = getCardsByRarity(Rarity.RARE); List mythics = getCardsByRarity(Rarity.MYTHIC); for (int i = 0; i < numBoosterRare; i++) { - if (ratioBoosterMythic > 0 && rnd.nextInt(ratioBoosterMythic) == 1) { + if (ratioBoosterMythic > 0 && rnd.nextInt(ratioBoosterMythic) == 0) { addToBooster(booster, mythics); } else { addToBooster(booster, rares); diff --git a/Mage/src/main/java/mage/cards/decks/Constructed.java b/Mage/src/main/java/mage/cards/decks/Constructed.java index 8218afa0fc2..c8c385e76d7 100644 --- a/Mage/src/main/java/mage/cards/decks/Constructed.java +++ b/Mage/src/main/java/mage/cards/decks/Constructed.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.cards.decks; import java.util.ArrayList; @@ -47,7 +46,7 @@ import org.apache.log4j.Logger; public class Constructed extends DeckValidator { private static final Logger logger = Logger.getLogger(DeckValidator.class); - + protected List banned = new ArrayList<>(); protected List restricted = new ArrayList<>(); protected List setCodes = new ArrayList<>(); @@ -63,7 +62,7 @@ public class Constructed extends DeckValidator { @Override public boolean validate(Deck deck) { - logger.debug("DECK validate start: " + name + " deckname: " + deck.getName() ); + logger.debug("DECK validate start: " + name + " deckname: " + deck.getName()); boolean valid = true; //20091005 - 100.2a if (deck.getCards().size() < 60) { @@ -76,12 +75,12 @@ public class Constructed extends DeckValidator { valid = false; } - List basicLandNames = new ArrayList<>(Arrays.asList("Forest", "Island", "Mountain", "Swamp", "Plains", - "Snow-Covered Forest", "Snow-Covered Island", "Snow-Covered Mountain", "Snow-Covered Swamp", "Snow-Covered Plains")); + List basicLandNames = new ArrayList<>(Arrays.asList("Forest", "Island", "Mountain", "Swamp", "Plains", "Wastes", + "Snow-Covered Forest", "Snow-Covered Island", "Snow-Covered Mountain", "Snow-Covered Swamp", "Snow-Covered Plains")); Map counts = new HashMap<>(); countCards(counts, deck.getCards()); countCards(counts, deck.getSideboard()); - for (Entry entry: counts.entrySet()) { + for (Entry entry : counts.entrySet()) { if (entry.getValue() > 4) { if (!basicLandNames.contains(entry.getKey()) && !entry.getKey().equals("Relentless Rats") && !entry.getKey().equals("Shadowborn Apostle")) { invalid.put(entry.getKey(), "Too many: " + entry.getValue()); @@ -89,14 +88,14 @@ public class Constructed extends DeckValidator { } } } - for (String bannedCard: banned) { + for (String bannedCard : banned) { if (counts.containsKey(bannedCard)) { invalid.put(bannedCard, "Banned"); valid = false; } } - for (String restrictedCard: restricted) { + for (String restrictedCard : restricted) { if (counts.containsKey(restrictedCard)) { int count = counts.get(restrictedCard); if (count > 1) { @@ -107,27 +106,27 @@ public class Constructed extends DeckValidator { } if (!rarities.isEmpty()) { - for (Card card: deck.getCards()) { + for (Card card : deck.getCards()) { if (!rarities.contains(card.getRarity())) { invalid.put(card.getName(), "Invalid rarity: " + card.getRarity()); valid = false; } - } - for (Card card: deck.getSideboard()) { + } + for (Card card : deck.getSideboard()) { if (!rarities.contains(card.getRarity())) { invalid.put(card.getName(), "Invalid rarity: " + card.getRarity()); valid = false; } - } + } } if (!setCodes.isEmpty()) { - for (Card card: deck.getCards()) { + for (Card card : deck.getCards()) { if (!setCodes.contains(card.getExpansionSetCode())) { // check if card is legal if taken from other set boolean legal = false; List cardInfos = CardRepository.instance.findCards(card.getName()); - for (CardInfo cardInfo: cardInfos) { + for (CardInfo cardInfo : cardInfos) { if (setCodes.contains(cardInfo.getSetCode())) { legal = true; break; @@ -139,12 +138,12 @@ public class Constructed extends DeckValidator { } } } - for (Card card: deck.getSideboard()) { + for (Card card : deck.getSideboard()) { if (!setCodes.contains(card.getExpansionSetCode())) { // check if card is legal if taken from other set boolean legal = false; List cardInfos = CardRepository.instance.findCards(card.getName()); - for (CardInfo cardInfo: cardInfos) { + for (CardInfo cardInfo : cardInfos) { if (setCodes.contains(cardInfo.getSetCode())) { legal = true; break; diff --git a/Mage/src/main/java/mage/cards/repository/CardCriteria.java b/Mage/src/main/java/mage/cards/repository/CardCriteria.java index 38e25425db6..98f58bd0b01 100644 --- a/Mage/src/main/java/mage/cards/repository/CardCriteria.java +++ b/Mage/src/main/java/mage/cards/repository/CardCriteria.java @@ -63,6 +63,7 @@ public class CardCriteria { private String sortBy; private Long start; private Long count; + private int minCardNumber; private int maxCardNumber; public CardCriteria() { @@ -81,6 +82,7 @@ public class CardCriteria { this.white = true; this.colorless = true; + this.minCardNumber = Integer.MIN_VALUE; this.maxCardNumber = Integer.MAX_VALUE; } @@ -179,6 +181,11 @@ public class CardCriteria { return this; } + public CardCriteria minCardNumber(int minCardNumber) { + this.minCardNumber = minCardNumber; + return this; + } + public CardCriteria maxCardNumber(int maxCardNumber) { this.maxCardNumber = maxCardNumber; return this; @@ -292,6 +299,11 @@ public class CardCriteria { } } + if (minCardNumber != Integer.MIN_VALUE) { + where.ge("cardNumber", minCardNumber); + clausesCount++; + } + if (maxCardNumber != Integer.MAX_VALUE) { where.le("cardNumber", maxCardNumber); clausesCount++; diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java index 71553460886..cc140503ba2 100644 --- a/Mage/src/main/java/mage/cards/repository/CardRepository.java +++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java @@ -63,7 +63,7 @@ public enum CardRepository { // raise this if db structure was changed private static final long CARD_DB_VERSION = 43; // raise this if new cards were added to the server - private static final long CARD_CONTENT_VERSION = 43; + private static final long CARD_CONTENT_VERSION = 45; private final Random random = new Random(); private Dao cardDao; diff --git a/Mage/src/main/java/mage/constants/ManaType.java b/Mage/src/main/java/mage/constants/ManaType.java index f5a5c2cd35e..19d8a901d5e 100644 --- a/Mage/src/main/java/mage/constants/ManaType.java +++ b/Mage/src/main/java/mage/constants/ManaType.java @@ -5,11 +5,13 @@ package mage.constants; * @author North */ public enum ManaType { - BLACK ("black"), - BLUE ("blue"), - GREEN ("green"), - RED ("red"), - WHITE ("white"), + + BLACK("black"), + BLUE("blue"), + GREEN("green"), + RED("red"), + WHITE("white"), + GENERIC("generic"), COLORLESS("colorless"); private final String text; @@ -22,4 +24,4 @@ public enum ManaType { public String toString() { return text; } -}; \ No newline at end of file +}; diff --git a/Mage/src/main/java/mage/filter/FilterCard.java b/Mage/src/main/java/mage/filter/FilterCard.java index 2995a693184..a59885e9905 100644 --- a/Mage/src/main/java/mage/filter/FilterCard.java +++ b/Mage/src/main/java/mage/filter/FilterCard.java @@ -74,6 +74,9 @@ public class FilterCard extends FilterObject { */ @Override public boolean match(Card card, Game game) { + if (card == null) { + return false; + } if (card.isSplitCard()) { return super.match(((SplitCard) card).getLeftHalfCard(), game) || super.match(((SplitCard) card).getRightHalfCard(), game); diff --git a/Mage/src/main/java/mage/filter/FilterMana.java b/Mage/src/main/java/mage/filter/FilterMana.java index 04376af229a..913f41ecabe 100644 --- a/Mage/src/main/java/mage/filter/FilterMana.java +++ b/Mage/src/main/java/mage/filter/FilterMana.java @@ -39,6 +39,7 @@ public class FilterMana implements Serializable { protected boolean white; protected boolean red; protected boolean blue; + protected boolean generic; protected boolean colorless; public FilterMana() { @@ -50,6 +51,7 @@ public class FilterMana implements Serializable { white = filter.white; red = filter.red; blue = filter.blue; + generic = filter.generic; colorless = filter.colorless; } @@ -93,6 +95,14 @@ public class FilterMana implements Serializable { this.blue = blue; } + public boolean isGeneric() { + return generic; + } + + public void setGeneric(boolean generic) { + this.generic = generic; + } + public boolean isColorless() { return colorless; } diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/MulticoloredPredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/MulticoloredPredicate.java index 6aca6494c25..5acdfb2f682 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/MulticoloredPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/MulticoloredPredicate.java @@ -28,6 +28,8 @@ package mage.filter.predicate.mageobject; import mage.MageObject; +import mage.cards.SplitCardHalf; +import mage.constants.Zone; import mage.filter.predicate.Predicate; import mage.game.Game; @@ -39,7 +41,14 @@ public class MulticoloredPredicate implements Predicate { @Override public boolean apply(MageObject input, Game game) { - return 1 < input.getColor(game).getColorCount(); + // 708.3. Each split card that consists of two halves with different colored mana symbols in their mana costs + // is a multicolored card while it’s not a spell on the stack. While it’s a spell on the stack, it’s only the + // color or colors of the half or halves being cast. # + if (input instanceof SplitCardHalf && !game.getState().getZone(input.getId()).equals(Zone.STACK)) { + return 1 < ((SplitCardHalf) input).getMainCard().getColor(game).getColorCount(); + } else { + return 1 < input.getColor(game).getColorCount(); + } } @Override diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/EnteredThisTurnPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/EnteredThisTurnPredicate.java new file mode 100644 index 00000000000..ce79bc625ef --- /dev/null +++ b/Mage/src/main/java/mage/filter/predicate/permanent/EnteredThisTurnPredicate.java @@ -0,0 +1,27 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.filter.predicate.permanent; + +import mage.filter.predicate.Predicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author LevelX2 + */ +public class EnteredThisTurnPredicate implements Predicate { + + @Override + public boolean apply(Permanent input, Game game) { + return input.getTurnsOnBattlefield() == 0; + } + + @Override + public String toString() { + return "Entered this turn"; + } +} diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/EquippedPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/EquippedPredicate.java new file mode 100644 index 00000000000..556e839afac --- /dev/null +++ b/Mage/src/main/java/mage/filter/predicate/permanent/EquippedPredicate.java @@ -0,0 +1,34 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.filter.predicate.permanent; + +import java.util.UUID; +import mage.filter.predicate.Predicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author LevelX2 + */ +public class EquippedPredicate implements Predicate { + + @Override + public boolean apply(Permanent input, Game game) { + for (UUID attachmentId : input.getAttachments()) { + Permanent attachment = game.getPermanent(attachmentId); + if (attachment != null && attachment.getSubtype().contains("Equipment")) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return "equipped"; + } +} diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 54797d22c3e..38e76d28be6 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -1495,9 +1495,17 @@ public abstract class GameImpl implements Game, Serializable { delayedAbility.setSourceId(source.getSourceId()); delayedAbility.setControllerId(source.getControllerId()); delayedAbility.setSourceObject(source.getSourceObject(this), this); - return addDelayedTriggeredAbility(delayedAbility); + // return addDelayedTriggeredAbility(delayedAbility); + DelayedTriggeredAbility newAbility = delayedAbility.copy(); + newAbility.newId(); + // ability.init is called as the ability triggeres not now. + // If a FixedTarget pointer is already set from the effect setting up this delayed ability + // it has to be already initialized so it won't be overwitten as the ability triggers + state.addDelayedTriggeredAbility(newAbility); + return newAbility.getId(); } + @Deprecated @Override public UUID addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility) { DelayedTriggeredAbility newAbility = delayedAbility.copy(); diff --git a/Mage/src/main/java/mage/game/GameState.java b/Mage/src/main/java/mage/game/GameState.java index 748ead016f2..752c7ed53fb 100644 --- a/Mage/src/main/java/mage/game/GameState.java +++ b/Mage/src/main/java/mage/game/GameState.java @@ -530,6 +530,12 @@ public class GameState implements Serializable, Copyable { this.gameOver = true; } + // 608.2e + public void processAction(Game game) { + game.getState().handleSimultaneousEvent(game); + applyEffects(game); + } + public void applyEffects(Game game) { game.resetShortLivingLKI(); for (Player player : players.values()) { @@ -863,8 +869,20 @@ public class GameState implements Serializable, Copyable { * @param ability */ public void addOtherAbility(Card attachedTo, Ability ability) { + addOtherAbility(attachedTo, ability, true); + } + + /** + * Adds the ability to continuous or triggered abilities + * + * @param attachedTo + * @param ability + * @param copyAbility copies non MageSingleton abilities before adding to + * state + */ + public void addOtherAbility(Card attachedTo, Ability ability, boolean copyAbility) { Ability newAbility; - if (ability instanceof MageSingleton) { + if (ability instanceof MageSingleton || !copyAbility) { newAbility = ability; } else { newAbility = ability.copy(); diff --git a/Mage/src/main/java/mage/game/GameTinyLeadersImpl.java b/Mage/src/main/java/mage/game/GameTinyLeadersImpl.java index 6addf9f0c9e..4c4b887bbdb 100644 --- a/Mage/src/main/java/mage/game/GameTinyLeadersImpl.java +++ b/Mage/src/main/java/mage/game/GameTinyLeadersImpl.java @@ -110,11 +110,9 @@ public abstract class GameTinyLeadersImpl extends GameImpl{ /** * Name of Tiny Leader comes from the deck name (it's not in the sideboard) * Additionally, it was taken into account that WOTC had missed a few color combinations - * when making Legendary Creatures at 3 CMC. There are three Commanders available to use + * when making Legendary Creatures at 3 CMC. There are two Commanders available to use * for the missing color identities: - * Mardu [WBR 2/2], - * Sultai [UBG 2/2], and - * Jeskai [WUR 2/2]. + * Sultai [UBG 3/3] and Glass [colorless 3/3] * * @param commanderName * @param ownerId @@ -127,6 +125,9 @@ public abstract class GameTinyLeadersImpl extends GameImpl{ case "Sultai": commander = new DefaultCommander(ownerId, commanderName, "{U}{B}{G}"); break; + case "Glass": + commander = new DefaultCommander(ownerId, commanderName, "{C}{C}{C}"); + break; default: CardInfo cardInfo = CardRepository.instance.findCard(commanderName); if (cardInfo != null) { @@ -184,8 +185,8 @@ class DefaultCommander extends CardImpl { if (manaString.contains("{R}")) { this.color.setRed(true); } - this.power = new MageInt(2); - this.toughness = new MageInt(2); + this.power = new MageInt(3); + this.toughness = new MageInt(3); } diff --git a/Mage/src/main/java/mage/game/Seat.java b/Mage/src/main/java/mage/game/Seat.java index 751a18d3932..f9a3325ac23 100644 --- a/Mage/src/main/java/mage/game/Seat.java +++ b/Mage/src/main/java/mage/game/Seat.java @@ -24,8 +24,7 @@ * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. -*/ - + */ package mage.game; import java.io.Serializable; @@ -38,7 +37,6 @@ import mage.players.Player; public class Seat implements Serializable { // private static final Logger logger = Logger.getLogger(Seat.class); - private String playerType; private Player player; diff --git a/Mage/src/main/java/mage/game/Table.java b/Mage/src/main/java/mage/game/Table.java index f5c714f95fe..b6669a428e7 100644 --- a/Mage/src/main/java/mage/game/Table.java +++ b/Mage/src/main/java/mage/game/Table.java @@ -38,6 +38,7 @@ import mage.game.events.Listener; import mage.game.events.TableEvent; import mage.game.events.TableEventSource; import mage.game.match.Match; +import mage.game.result.ResultProtos.TableProto; import mage.game.tournament.Tournament; import mage.players.Player; @@ -61,24 +62,29 @@ public class Table implements Serializable { private TableState state; private Match match; private Tournament tournament; + private TableRecorder recorder; + + public interface TableRecorder { + void record(Table table); + }; protected TableEventSource tableEventSource = new TableEventSource(); - public Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List playerTypes, Tournament tournament) { - this(roomId, gameType, name, controllerName, validator, playerTypes); + public Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List playerTypes, TableRecorder recorder, Tournament tournament) { + this(roomId, gameType, name, controllerName, validator, playerTypes, recorder); this.tournament = tournament; this.isTournament = true; setState(TableState.WAITING); } - public Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List playerTypes, Match match) { - this(roomId, gameType, name, controllerName, validator, playerTypes); + public Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List playerTypes, TableRecorder recorder, Match match) { + this(roomId, gameType, name, controllerName, validator, playerTypes, recorder); this.match = match; this.isTournament = false; setState(TableState.WAITING); } - protected Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List playerTypes) { + protected Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List playerTypes, TableRecorder recorder) { tableId = UUID.randomUUID(); this.roomId = roomId; this.numSeats = playerTypes.size(); @@ -88,6 +94,7 @@ public class Table implements Serializable { this.createTime = new Date(); createSeats(playerTypes); this.validator = validator; + this.recorder = recorder; } private void createSeats(List playerTypes) { @@ -235,6 +242,9 @@ public class Table implements Serializable { if (isTournament()) { getTournament().setTournamentState(state.toString()); } + if (state == TableState.FINISHED) { + this.recorder.record(this); + } } public TableState getState() { @@ -296,5 +306,21 @@ public class Table implements Serializable { return match.getEndTime(); } } - + + public TableProto toProto() { + TableProto.Builder builder = TableProto.newBuilder(); + if (this.isTournament()) { + builder.getTourneyBuilder().mergeFrom(this.getTournament().toProto()); + } else { + builder.getMatchBuilder().mergeFrom(this.getMatch().toProto()); + } + return builder.setGameType(this.getGameType()) + .setName(this.getName()) + .setGameType(this.getGameType()) + .setDeckType(this.getDeckType()) + .setControllerName(this.getControllerName()) + .setStartTimeMs(this.getStartTime().getTime()) + .setEndTimeMs(this.getEndTime().getTime()) + .build(); + } } diff --git a/Mage/src/main/java/mage/game/combat/Combat.java b/Mage/src/main/java/mage/game/combat/Combat.java index aa6c20c20ff..353c9854caf 100644 --- a/Mage/src/main/java/mage/game/combat/Combat.java +++ b/Mage/src/main/java/mage/game/combat/Combat.java @@ -86,6 +86,8 @@ public class Combat implements Serializable, Copyable { private final Map> creaturesForcedToAttack = new HashMap<>(); private int maxAttackers = Integer.MIN_VALUE; + private final HashSet attackersTappedByAttack = new HashSet<>(); + public Combat() { this.useToughnessForDamage = false; } @@ -111,6 +113,7 @@ public class Combat implements Serializable, Copyable { this.creaturesForcedToAttack.put(group.getKey(), group.getValue()); } this.maxAttackers = combat.maxAttackers; + this.attackersTappedByAttack.addAll(combat.attackersTappedByAttack); } public List getGroups() { @@ -230,7 +233,7 @@ public class Combat implements Serializable, Copyable { } } } else { - possibleDefenders = new HashSet(defenders); + possibleDefenders = new HashSet<>(defenders); } Player player = game.getPlayer(attackerId); if (possibleDefenders.size() == 1) { @@ -270,12 +273,21 @@ public class Combat implements Serializable, Copyable { } } + @SuppressWarnings("deprecation") public void resumeSelectAttackers(Game game) { for (CombatGroup group : groups) { for (UUID attacker : group.getAttackers()) { + if (attackersTappedByAttack.contains(attacker)) { + Permanent attackingPermanent = game.getPermanent(attacker); + if (attackingPermanent != null) { + attackingPermanent.setTapped(false); + attackingPermanent.tap(game); // to tap with event finally here is needed to prevent abusing of Vampire Envoy like cards + } + } game.fireEvent(GameEvent.getEvent(GameEvent.EventType.ATTACKER_DECLARED, group.defenderId, attacker, attackerId)); } } + attackersTappedByAttack.clear(); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_ATTACKERS, attackerId, attackerId)); if (!game.isSimulation()) { Player player = game.getPlayer(attackerId); @@ -740,7 +752,8 @@ public class Combat implements Serializable, Copyable { for (UUID possibleBlockerId : mustBeBlockedByAtLeastOne.get(toBeBlockedCreatureId)) { String blockRequiredMessage = isCreatureDoingARequiredBlock(possibleBlockerId, mustBeBlockedByAtLeastOne, game); if (blockRequiredMessage != null) { // message means not required - game.informPlayer(controller, blockRequiredMessage + "It's a requirement to block " + toBeBlockedCreature.getIdName()); + removeBlocker(possibleBlockerId, game); + game.informPlayer(controller, blockRequiredMessage + " Existing block removed. It's a requirement to block " + toBeBlockedCreature.getIdName() + "."); return false; } } @@ -755,6 +768,9 @@ public class Combat implements Serializable, Copyable { Permanent possibleBlocker = game.getPermanent(possibleBlockerId); Player defender = game.getPlayer(possibleBlocker.getControllerId()); if (defender != null) { + if (possibleBlocker.getBlocking() > 0) { + removeBlocker(possibleBlockerId, game); + } defender.declareBlocker(defender.getId(), possibleBlockerId, toBeBlockedCreatureId, game); } break; @@ -873,6 +889,9 @@ public class Combat implements Serializable, Copyable { Permanent blockedAttacker = game.getPermanent(blockedAttackerId); return possibleBlocker.getIdName() + " blocks with other creatures " + blockedAttacker.getIdName() + ", which has to be blocked by only one creature. "; } + // The possible blocker blocks an attacker for that is no attack forced + Permanent blockedAttacker = game.getPermanent(blockedAttackerId); + return possibleBlocker.getIdName() + " blocks " + blockedAttacker.getIdName() + ", which not has to be blocked as a requirement."; } } } @@ -975,11 +994,13 @@ public class Combat implements Serializable, Copyable { } } + @SuppressWarnings("deprecation") public boolean declareAttacker(UUID creatureId, UUID defenderId, UUID playerId, Game game) { Permanent attacker = game.getPermanent(creatureId); if (!attacker.getAbilities().containsKey(VigilanceAbility.getInstance().getId())) { if (!attacker.isTapped()) { - attacker.tap(game); + attacker.setTapped(true); + attackersTappedByAttack.add(attacker.getId()); } } if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_ATTACKER, defenderId, creatureId, playerId))) { @@ -1227,6 +1248,7 @@ public class Combat implements Serializable, Copyable { } } + @SuppressWarnings("deprecation") public void removeAttacker(UUID attackerId, Game game) { for (CombatGroup group : groups) { if (group.attackers.contains(attackerId)) { @@ -1238,7 +1260,10 @@ public class Combat implements Serializable, Copyable { Permanent creature = game.getPermanent(attackerId); if (creature != null) { creature.setAttacking(false); - creature.setTapped(false); + if (attackersTappedByAttack.contains(creature.getId())) { + creature.setTapped(false); + attackersTappedByAttack.remove(creature.getId()); + } } if (group.attackers.isEmpty()) { groups.remove(group); diff --git a/Mage/src/main/java/mage/game/events/GameEvent.java b/Mage/src/main/java/mage/game/events/GameEvent.java index 95b1a318e67..46cce3480e9 100644 --- a/Mage/src/main/java/mage/game/events/GameEvent.java +++ b/Mage/src/main/java/mage/game/events/GameEvent.java @@ -91,6 +91,7 @@ public class GameEvent implements Serializable { DRAW_CARD, DREW_CARD, MIRACLE_CARD_REVEALED, MADNESS_CARD_EXILED, + DISCARD_CARD, DISCARDED_CARD, CYCLE_CARD, CYCLED_CARD, CLASH, CLASHED, diff --git a/Mage/src/main/java/mage/game/match/Match.java b/Mage/src/main/java/mage/game/match/Match.java index f695949c87e..6fc81ef884f 100644 --- a/Mage/src/main/java/mage/game/match/Match.java +++ b/Mage/src/main/java/mage/game/match/Match.java @@ -39,6 +39,7 @@ import java.util.Date; import java.util.List; import java.util.UUID; import mage.game.GameInfo; +import mage.game.result.ResultProtos.MatchProto; /** * @@ -111,4 +112,6 @@ public interface Match { void setTableId(UUID tableId); void setTournamentRound(int round); + + MatchProto toProto(); } diff --git a/Mage/src/main/java/mage/game/match/MatchImpl.java b/Mage/src/main/java/mage/game/match/MatchImpl.java index 9bc0db8ca2f..30f7cd53ee0 100644 --- a/Mage/src/main/java/mage/game/match/MatchImpl.java +++ b/Mage/src/main/java/mage/game/match/MatchImpl.java @@ -41,6 +41,8 @@ import mage.game.events.Listener; import mage.game.events.TableEvent; import mage.game.events.TableEvent.EventType; import mage.game.events.TableEventSource; +import mage.game.result.ResultProtos.MatchProto; +import mage.game.result.ResultProtos.MatchQuitStatus; import mage.players.Player; import mage.util.DateFormat; import org.apache.log4j.Logger; @@ -488,4 +490,25 @@ public abstract class MatchImpl implements Match { this.getGames().clear(); } + @Override + public MatchProto toProto() { + MatchProto.Builder builder = MatchProto.newBuilder() + .setName(this.getName()) + .setGameType(this.getOptions().getGameType()) + .setDeckType(this.getOptions().getDeckType()) + .setGames(this.getNumGames()) + .setDraws(this.getDraws()); + for (MatchPlayer matchPlayer : this.getPlayers()) { + MatchQuitStatus status = !matchPlayer.hasQuit() ? MatchQuitStatus.NO_MATCH_QUIT : + matchPlayer.getPlayer().hasTimerTimeout() ? MatchQuitStatus.TIMER_TIMEOUT : + matchPlayer.getPlayer().hasIdleTimeout() ? MatchQuitStatus.IDLE_TIMEOUT : + MatchQuitStatus.QUIT; + builder.addPlayersBuilder() + .setName(matchPlayer.getName()) + .setQuit(status) + .setWins(matchPlayer.getWins()); + } + return builder.build(); + } + } diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index 87c5abbdff9..c725fa67f9f 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -815,6 +815,11 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } dealtDamageByThisTurn.add(new MageObjectReference(source, game)); } + if (source == null) { + game.informPlayers(getLogName() + " gets " + damageDone + " damage"); + } else { + game.informPlayers(source.getLogName() + " deals " + damageDone + " damage to " + getLogName()); + } } } return damageDone; diff --git a/Mage/src/main/java/mage/game/permanent/token/EldraziScionToken.java b/Mage/src/main/java/mage/game/permanent/token/EldraziScionToken.java index cc11cf02d57..7b347d7de52 100644 --- a/Mage/src/main/java/mage/game/permanent/token/EldraziScionToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/EldraziScionToken.java @@ -27,6 +27,9 @@ */ package mage.game.permanent.token; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Random; import mage.MageInt; import mage.Mana; @@ -41,6 +44,12 @@ import mage.constants.Zone; */ public class EldraziScionToken extends Token { + final static private List tokenImageSets = new ArrayList<>(); + + static { + tokenImageSets.addAll(Arrays.asList("BFZ", "OGW")); + } + public EldraziScionToken() { super("Eldrazi Scion", "1/1 colorless Eldrazi Scion creature token with \"Sacrifice this creature: Add {C} to your mana pool.\""); cardType.add(CardType.CREATURE); @@ -48,9 +57,8 @@ public class EldraziScionToken extends Token { subtype.add("Scion"); power = new MageInt(1); toughness = new MageInt(1); - addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.ColorlessMana(1), new SacrificeSourceCost())); - setOriginalExpansionSetCode("BFZ"); - + addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.GenericMana(1), new SacrificeSourceCost())); + availableImageSetCodes = tokenImageSets; } @Override @@ -59,6 +67,9 @@ public class EldraziScionToken extends Token { if (getOriginalExpansionSetCode().equals("BFZ")) { this.setTokenType(new Random().nextInt(3) + 1); // 3 different images } + if (getOriginalExpansionSetCode().equals("OGW")) { + this.setTokenType(new Random().nextInt(6) + 1); // 6 different images + } } public EldraziScionToken(final EldraziScionToken token) { 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 f4d440942ed..c063ed0ac15 100644 --- a/Mage/src/main/java/mage/game/permanent/token/EldraziSpawnToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/EldraziSpawnToken.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,24 +20,23 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.game.permanent.token; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Random; -import mage.constants.CardType; -import mage.constants.Zone; import mage.MageInt; import mage.Mana; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.mana.SimpleManaAbility; +import mage.constants.CardType; +import mage.constants.Zone; /** * diff --git a/Mage/src/main/java/mage/game/permanent/token/ElephantToken.java b/Mage/src/main/java/mage/game/permanent/token/ElephantToken.java index a95182b2b1a..a53476916b2 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ElephantToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ElephantToken.java @@ -31,9 +31,7 @@ package mage.game.permanent.token; import java.util.ArrayList; import java.util.Arrays; import java.util.List; - import mage.MageInt; -import mage.ObjectColor; import mage.constants.CardType; /** @@ -45,7 +43,7 @@ public class ElephantToken extends Token { final static private List tokenImageSets = new ArrayList<>(); static { - tokenImageSets.addAll(Arrays.asList("C14", "CNS", "DDD", "MM2", "WWK")); + tokenImageSets.addAll(Arrays.asList("C14", "CNS", "DDD", "MM2", "WWK", "OGW")); } public ElephantToken() { diff --git a/Mage/src/main/java/mage/game/permanent/token/ZombieToken.java b/Mage/src/main/java/mage/game/permanent/token/ZombieToken.java index 28d1e5b4ce7..e2d7dc4f553 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ZombieToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ZombieToken.java @@ -43,7 +43,7 @@ public class ZombieToken extends Token { final static private List tokenImageSets = new ArrayList<>(); static { - tokenImageSets.addAll(Arrays.asList("10E", "M10", "M11", "M12", "M13", "M14", "M15", "MBS", "ALA", "ISD", "C14", "C15", "CNS", "MMA", "BNG", "KTK", "DTK", "ORI")); + tokenImageSets.addAll(Arrays.asList("10E", "M10", "M11", "M12", "M13", "M14", "M15", "MBS", "ALA", "ISD", "C14", "C15", "CNS", "MMA", "BNG", "KTK", "DTK", "ORI", "OGW")); } public ZombieToken() { diff --git a/Mage/src/main/java/mage/game/tournament/Tournament.java b/Mage/src/main/java/mage/game/tournament/Tournament.java index 7aba2501053..97c3d7f1d43 100644 --- a/Mage/src/main/java/mage/game/tournament/Tournament.java +++ b/Mage/src/main/java/mage/game/tournament/Tournament.java @@ -38,6 +38,7 @@ import mage.game.draft.Draft; import mage.game.events.Listener; import mage.game.events.PlayerQueryEvent; import mage.game.events.TableEvent; +import mage.game.result.ResultProtos.TourneyProto; import mage.players.Player; /** @@ -98,4 +99,6 @@ public interface Tournament { void clearDraft(); Draft getDraft(); + + TourneyProto toProto(); } diff --git a/Mage/src/main/java/mage/game/tournament/TournamentImpl.java b/Mage/src/main/java/mage/game/tournament/TournamentImpl.java index a578a681107..177c299e9e6 100644 --- a/Mage/src/main/java/mage/game/tournament/TournamentImpl.java +++ b/Mage/src/main/java/mage/game/tournament/TournamentImpl.java @@ -51,6 +51,11 @@ import mage.game.events.TableEvent.EventType; import mage.game.events.TableEventSource; import mage.game.match.Match; import mage.game.match.MatchPlayer; +import mage.game.result.ResultProtos.MatchPlayerProto; +import mage.game.result.ResultProtos.MatchProto; +import mage.game.result.ResultProtos.MatchQuitStatus; +import mage.game.result.ResultProtos.TourneyProto; +import mage.game.result.ResultProtos.TourneyRoundProto; import mage.players.Player; import org.apache.log4j.Logger; @@ -555,4 +560,51 @@ public abstract class TournamentImpl implements Tournament { return draft; } + @Override + public TourneyProto toProto() { + TourneyProto.Builder tourneyBuilder = TourneyProto.newBuilder() + .setBoosterInfo(this.getBoosterInfo()); + for (TournamentPlayer player : players.values()) { + TournamentPlayer replacedPlayer = player.getReplacedTournamentPlayer(); + if (replacedPlayer != null) { + player = replacedPlayer; + } + tourneyBuilder.addPlayersBuilder().mergeFrom(player.toProto()); + } + for (Round round : rounds) { + TourneyRoundProto.Builder roundBuilder = tourneyBuilder.addRoundsBuilder() + .setRound(round.getRoundNumber()); + for (TournamentPairing pair : round.getPairs()) { + Match match = pair.getMatch(); + if (match != null && match.hasEnded()) { + MatchProto.Builder matchBuilder = roundBuilder.addMatchesBuilder() + .setName(match.getName()) + .setGameType(match.getOptions().getGameType()) + .setDeckType(match.getOptions().getDeckType()) + .setGames(match.getNumGames()) + .setDraws(match.getDraws()) + .addPlayers(matchToProto(match, pair.getPlayer1())) + .addPlayers(matchToProto(match, pair.getPlayer2())); + } + } + for (TournamentPlayer tp : round.getPlayerByes()) { + roundBuilder.addByes(tp.getPlayer().getName()); + } + } + return tourneyBuilder.build(); + } + + private MatchPlayerProto matchToProto(Match match, TournamentPlayer player) { + MatchPlayer matchPlayer = match.getPlayer(player.getPlayer().getId()); + MatchQuitStatus quit = !matchPlayer.hasQuit() ? MatchQuitStatus.NO_MATCH_QUIT : + matchPlayer.getPlayer().hasIdleTimeout() ? MatchQuitStatus.IDLE_TIMEOUT : + matchPlayer.getPlayer().hasTimerTimeout() ? MatchQuitStatus.TIMER_TIMEOUT : + MatchQuitStatus.QUIT; + return MatchPlayerProto.newBuilder() + .setName(player.getPlayer().getName()) + .setWins(matchPlayer.getWins()) + .setQuit(quit) + .build(); + } + } diff --git a/Mage/src/main/java/mage/game/tournament/TournamentPlayer.java b/Mage/src/main/java/mage/game/tournament/TournamentPlayer.java index 3d85eef6bf0..5b4042155a5 100644 --- a/Mage/src/main/java/mage/game/tournament/TournamentPlayer.java +++ b/Mage/src/main/java/mage/game/tournament/TournamentPlayer.java @@ -31,6 +31,8 @@ package mage.game.tournament; import java.util.Set; import mage.cards.decks.Deck; import mage.constants.TournamentPlayerState; +import mage.game.result.ResultProtos.TourneyPlayerProto; +import mage.game.result.ResultProtos.TourneyQuitStatus; import mage.players.Player; import mage.util.TournamentUtil; @@ -52,6 +54,8 @@ public class TournamentPlayer { protected boolean quit = false; protected boolean doneConstructing; protected boolean joined = false; + protected TourneyQuitStatus quitStatus = TourneyQuitStatus.NO_TOURNEY_QUIT; + protected TournamentPlayer replacedTournamentPlayer; public TournamentPlayer(Player player, String playerType) { this.player = player; @@ -60,7 +64,6 @@ public class TournamentPlayer { this.stateInfo = ""; this.disconnectInfo = ""; this.results = ""; - } public Player getPlayer() { @@ -185,12 +188,13 @@ public class TournamentPlayer { return quit; } - public void setQuit(String info) { + public void setQuit(String info, TourneyQuitStatus status) { setEliminated(); this.setState(TournamentPlayerState.CANCELED); this.setStateInfo(info); this.quit = true; this.doneConstructing = true; + this.quitStatus = status; } /** @@ -216,5 +220,21 @@ public class TournamentPlayer { && !this.getState().equals(TournamentPlayerState.ELIMINATED) && !this.getState().equals(TournamentPlayerState.FINISHED); } + + public TournamentPlayer getReplacedTournamentPlayer() { + return this.replacedTournamentPlayer; + } + + public void setReplacedTournamentPlayer(TournamentPlayer player) { + this.replacedTournamentPlayer = player; + } + + public TourneyPlayerProto toProto() { + return TourneyPlayerProto.newBuilder() + .setName(this.player.getName()) + .setPlayerType(this.playerType) + .setQuit(this.quitStatus) + .build(); + } } diff --git a/Mage/src/main/java/mage/players/ManaPool.java b/Mage/src/main/java/mage/players/ManaPool.java index 04aec4fa846..65c2cfa68d0 100644 --- a/Mage/src/main/java/mage/players/ManaPool.java +++ b/Mage/src/main/java/mage/players/ManaPool.java @@ -38,6 +38,7 @@ import mage.ConditionalMana; import mage.MageObject; import mage.Mana; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.constants.Duration; import mage.constants.ManaType; import mage.constants.TurnPhase; @@ -108,9 +109,10 @@ public class ManaPool implements Serializable { * @param ability * @param filter * @param game + * @param costToPay complete costs to pay (needed to check conditional mana) * @return */ - public boolean pay(ManaType manaType, Ability ability, Filter filter, Game game) { + public boolean pay(ManaType manaType, Ability ability, Filter filter, Game game, Cost costToPay) { if (!autoPayment && !manaType.equals(unlockedManaType)) { // if manual payment and the needed mana type was not unlocked, nothing will be paid return false; @@ -121,8 +123,8 @@ public class ManaPool implements Serializable { return false; } - if (getConditional(manaType, ability, filter, game) > 0) { - removeConditional(manaType, ability, game); + if (getConditional(manaType, ability, filter, game, costToPay) > 0) { + removeConditional(manaType, ability, game, costToPay); lockManaType(); // pay only one mana if mana payment is set to manually return true; } @@ -160,12 +162,14 @@ public class ManaPool implements Serializable { return getMana().get(manaType); } - private int getConditional(ManaType manaType, Ability ability, Filter filter, Game game) { + private int getConditional(ManaType manaType, Ability ability, Filter filter, Game game, Cost costToPay) { if (ability == null || getConditionalMana().isEmpty()) { return 0; } for (ManaPoolItem mana : manaItems) { - if (mana.isConditional() && mana.getConditionalMana().get(manaType) > 0 && mana.getConditionalMana().apply(ability, game, mana.getSourceId())) { + if (mana.isConditional() + && mana.getConditionalMana().get(manaType) > 0 + && mana.getConditionalMana().apply(ability, game, mana.getSourceId(), costToPay)) { if (filter == null || filter.match(game.getObject(mana.getSourceId()), game)) { return mana.getConditionalMana().get(manaType); } @@ -174,13 +178,13 @@ public class ManaPool implements Serializable { return 0; } - public int getConditionalCount(Ability ability, Game game, FilterMana filter) { + public int getConditionalCount(Ability ability, Game game, FilterMana filter, Cost costToPay) { if (ability == null || getConditionalMana().isEmpty()) { return 0; } int count = 0; for (ConditionalMana mana : getConditionalMana()) { - if (mana.apply(ability, game, mana.getManaProducerId())) { + if (mana.apply(ability, game, mana.getManaProducerId(), costToPay)) { count += mana.count(filter); } } @@ -249,7 +253,7 @@ public class ManaPool implements Serializable { ManaPoolItem item = it.next(); if (item.isConditional()) { ConditionalMana cm = item.getConditionalMana(); - if (cm.apply(ability, game, cm.getManaProducerId())) { + if (cm.apply(ability, game, cm.getManaProducerId(), null)) { total += item.count(); it.remove(); } @@ -279,7 +283,7 @@ public class ManaPool implements Serializable { ManaPoolItem item = it.next(); if (item.isConditional()) { ConditionalMana c = item.getConditionalMana(); - if (c.apply(ability, game, c.getManaProducerId())) { + if (c.apply(ability, game, c.getManaProducerId(), null)) { int count = c.count(filter); if (count > 0) { total += count; @@ -310,7 +314,7 @@ public class ManaPool implements Serializable { total += item.getGreen(); item.removeGreen(); } - if (filter.isColorless()) { + if (filter.isGeneric()) { total += item.getColorless(); item.removeColorless(); } @@ -342,9 +346,6 @@ public class ManaPool implements Serializable { if (filter.isBlue()) { m.setBlue(test.getBlue()); } - if (filter.isColorless()) { - m.setColorless(test.getColorless()); - } if (filter.isGreen()) { m.setGreen(test.getGreen()); } @@ -354,12 +355,18 @@ public class ManaPool implements Serializable { if (filter.isWhite()) { m.setWhite(test.getWhite()); } + if (filter.isColorless()) { + m.setColorless(test.getColorless()); + } + if (filter.isGeneric()) { + m.setGeneric(test.getGeneric()); + } return m; } public Mana getAllConditionalMana(Ability ability, Game game, FilterMana filter) { Mana m = new Mana(); - m.setColorless(getConditionalCount(ability, game, filter)); + m.setGeneric(getConditionalCount(ability, game, filter, null)); return m; } @@ -377,7 +384,7 @@ public class ManaPool implements Serializable { } this.manaItems.add(item); } else { - ManaPoolItem item = new ManaPoolItem(mana.getRed(), mana.getGreen(), mana.getBlue(), mana.getWhite(), mana.getBlack(), mana.getColorless(), source.getSourceId(), source.getOriginalId(), mana.getFlag()); + ManaPoolItem item = new ManaPoolItem(mana.getRed(), mana.getGreen(), mana.getBlue(), mana.getWhite(), mana.getBlack(), mana.getGeneric() + mana.getColorless(), source.getSourceId(), source.getOriginalId(), mana.getFlag()); if (emptyOnTurnsEnd) { item.setDuration(Duration.EndOfTurn); } @@ -411,9 +418,9 @@ public class ManaPool implements Serializable { return new ManaPool(this); } - private void removeConditional(ManaType manaType, Ability ability, Game game) { + private void removeConditional(ManaType manaType, Ability ability, Game game, Cost costToPay) { for (ConditionalMana mana : getConditionalMana()) { - if (mana.get(manaType) > 0 && mana.apply(ability, game, mana.getManaProducerId())) { + if (mana.get(manaType) > 0 && mana.apply(ability, game, mana.getManaProducerId(), costToPay)) { mana.set(manaType, mana.get(manaType) - 1); GameEvent event = new GameEvent(GameEvent.EventType.MANA_PAYED, ability.getId(), mana.getManaProducerId(), ability.getControllerId(), 0, mana.getFlag()); event.setData(mana.getManaProducerOriginalId().toString()); diff --git a/Mage/src/main/java/mage/players/ManaPoolItem.java b/Mage/src/main/java/mage/players/ManaPoolItem.java index 9c380389a3d..2dcb9a92f51 100644 --- a/Mage/src/main/java/mage/players/ManaPoolItem.java +++ b/Mage/src/main/java/mage/players/ManaPoolItem.java @@ -181,7 +181,7 @@ public class ManaPoolItem implements Serializable { } public Mana getMana() { - return new Mana(red, green, blue, white, black, colorless, 0); + return new Mana(red, green, blue, white, black, 0, 0, colorless); } public int count() { diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index d2565bd84a1..9bad10ada90 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -678,7 +678,7 @@ public interface Player extends MageItem, Copyable { * @param toZone * @param source * @param game - * @param tapped tha cards are tapped on the battlefield + * @param tapped the cards are tapped on the battlefield * @param faceDown the cards are face down in the to zone * @param byOwner the card is moved (or put onto battlefield) by the owner * of the card and if target zone is battlefield controls the permanent @@ -824,4 +824,6 @@ public interface Player extends MageItem, Copyable { * @return */ boolean addTargets(Ability ability, Game game); + + String getHistory(); } diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 31bcdbb769e..301900b70cf 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -42,6 +42,7 @@ import java.util.Map.Entry; import java.util.Random; import java.util.Set; import java.util.UUID; +import mage.ConditionalMana; import mage.MageObject; import mage.Mana; import mage.abilities.Abilities; @@ -91,6 +92,14 @@ import mage.constants.ManaType; import mage.constants.Outcome; import mage.constants.PhaseStep; import mage.constants.PlayerAction; +import static mage.constants.PlayerAction.PASS_PRIORITY_CANCEL_ALL_ACTIONS; +import static mage.constants.PlayerAction.PASS_PRIORITY_UNTIL_MY_NEXT_TURN; +import static mage.constants.PlayerAction.PASS_PRIORITY_UNTIL_NEXT_MAIN_PHASE; +import static mage.constants.PlayerAction.PASS_PRIORITY_UNTIL_NEXT_TURN; +import static mage.constants.PlayerAction.PASS_PRIORITY_UNTIL_STACK_RESOLVED; +import static mage.constants.PlayerAction.PASS_PRIORITY_UNTIL_TURN_END_STEP; +import static mage.constants.PlayerAction.PERMISSION_REQUESTS_ALLOWED_OFF; +import static mage.constants.PlayerAction.PERMISSION_REQUESTS_ALLOWED_ON; import mage.constants.RangeOfInfluence; import mage.constants.SpellAbilityType; import mage.constants.TimingRule; @@ -515,31 +524,29 @@ public abstract class PlayerImpl implements Player, Serializable { inRange.add(player.getId()); } } + } else if ((range.getRange() * 2) + 1 >= game.getPlayers().size()) { + for (Player player : game.getPlayers().values()) { + if (!player.hasLeft()) { + inRange.add(player.getId()); + } + } } else { - if ((range.getRange() * 2) + 1 >= game.getPlayers().size()) { - for (Player player : game.getPlayers().values()) { - if (!player.hasLeft()) { - inRange.add(player.getId()); - } + inRange.add(playerId); + PlayerList players = game.getState().getPlayerList(playerId); + for (int i = 0; i < range.getRange(); i++) { + Player player = players.getNext(game); + while (player.hasLeft()) { + player = players.getNext(game); } - } else { - inRange.add(playerId); - PlayerList players = game.getState().getPlayerList(playerId); - for (int i = 0; i < range.getRange(); i++) { - Player player = players.getNext(game); - while (player.hasLeft()) { - player = players.getNext(game); - } - inRange.add(player.getId()); - } - players = game.getState().getPlayerList(playerId); - for (int i = 0; i < range.getRange(); i++) { - Player player = players.getPrevious(game); - while (player.hasLeft()) { - player = players.getPrevious(game); - } - inRange.add(player.getId()); + inRange.add(player.getId()); + } + players = game.getState().getPlayerList(playerId); + for (int i = 0; i < range.getRange(); i++) { + Player player = players.getPrevious(game); + while (player.hasLeft()) { + player = players.getPrevious(game); } + inRange.add(player.getId()); } } } @@ -759,7 +766,8 @@ public abstract class PlayerImpl implements Player, Serializable { about the discarded card, that cost payment is illegal; the game returns to the moment before the cost was paid (see rule 717, "Handling Illegal Actions"). */ - if (card != null) { + if (card != null + && !game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DISCARD_CARD, card.getId(), source == null ? null : source.getSourceId(), playerId), source)) { // write info to game log first so game log infos from triggered or replacement effects follow in the game log if (!game.isSimulation()) { game.informPlayers(getLogName() + " discards " + card.getLogName()); @@ -2088,7 +2096,8 @@ public abstract class PlayerImpl implements Player, Serializable { break; } } - if (!opponentInGame || // if no more opponent is in game the wins event may no longer be replaced + if (!opponentInGame + || // if no more opponent is in game the wins event may no longer be replaced !game.replaceEvent(new GameEvent(GameEvent.EventType.WINS, null, null, playerId))) { logger.debug("player won -> start: " + this.getName()); if (!this.loses) { @@ -2168,10 +2177,8 @@ public abstract class PlayerImpl implements Player, Serializable { if (blocker != null && group != null && group.canBlock(blocker, game)) { group.addBlocker(blockerId, playerId, game); game.getCombat().addBlockingGroup(blockerId, attackerId, playerId, game); - } else { - if (this.isHuman() && !game.isSimulation()) { - game.informPlayer(this, "You can't block this creature."); - } + } else if (this.isHuman() && !game.isSimulation()) { + game.informPlayer(this, "You can't block this creature."); } } @@ -2532,7 +2539,9 @@ public abstract class PlayerImpl implements Player, Serializable { ManaOptions availableMana = getManaAvailable(game); availableMana.addMana(manaPool.getMana()); - + for (ConditionalMana conditionalMana : manaPool.getConditionalMana()) { + availableMana.addMana(conditionalMana); + } if (hidden) { for (Card card : hand.getUniqueCards(game)) { for (Ability ability : card.getAbilities(game)) { // gets this activated ability from hand? (Morph?) @@ -2790,14 +2799,12 @@ public abstract class PlayerImpl implements Player, Serializable { } if (targetNum < option.getTargets().size() - 2) { addTargetOptions(options, newOption, targetNum + 1, game); + } else if (option.getChoices().size() > 0) { + addChoiceOptions(options, newOption, 0, game); + } else if (option.getCosts().getTargets().size() > 0) { + addCostTargetOptions(options, newOption, 0, game); } else { - if (option.getChoices().size() > 0) { - addChoiceOptions(options, newOption, 0, game); - } else if (option.getCosts().getTargets().size() > 0) { - addCostTargetOptions(options, newOption, 0, game); - } else { - options.add(newOption); - } + options.add(newOption); } } } @@ -2808,12 +2815,10 @@ public abstract class PlayerImpl implements Player, Serializable { newOption.getChoices().get(choiceNum).setChoice(choice); if (choiceNum < option.getChoices().size() - 1) { addChoiceOptions(options, newOption, choiceNum + 1, game); + } else if (option.getCosts().getTargets().size() > 0) { + addCostTargetOptions(options, newOption, 0, game); } else { - if (option.getCosts().getTargets().size() > 0) { - addCostTargetOptions(options, newOption, 0, game); - } else { - options.add(newOption); - } + options.add(newOption); } } } @@ -3500,4 +3505,9 @@ public abstract class PlayerImpl implements Player, Serializable { return true; } + @Override + public String getHistory() { + return "no available"; + } + } diff --git a/Mage/src/main/java/mage/players/net/UserData.java b/Mage/src/main/java/mage/players/net/UserData.java index c2c3b2a3bb4..bca9f231700 100644 --- a/Mage/src/main/java/mage/players/net/UserData.java +++ b/Mage/src/main/java/mage/players/net/UserData.java @@ -23,6 +23,8 @@ public class UserData implements Serializable { protected boolean passPriorityActivation; protected boolean autoOrderTrigger; + protected String history; + public UserData(UserGroup userGroup, int avatarId, boolean showAbilityPickerForced, boolean allowRequestShowHandCards, boolean confirmEmptyManaPool, UserSkipPrioritySteps userSkipPrioritySteps, String flagName, boolean askMoveToGraveOrder, boolean manaPoolAutomatic, boolean manaPoolAutomaticRestricted, @@ -40,6 +42,7 @@ public class UserData implements Serializable { this.passPriorityCast = passPriorityCast; this.passPriorityActivation = passPriorityActivation; this.autoOrderTrigger = autoOrderTrigger; + this.history = ""; } public void update(UserData userData) { @@ -166,7 +169,16 @@ public class UserData implements Serializable { this.autoOrderTrigger = autoOrderTrigger; } + public void setHistory(String history) { + this.history = history; + } + + public String getHistory() { + return history; + } + public static String getDefaultFlagName() { return "world.png"; } + } diff --git a/Mage/src/main/java/mage/target/targetpointer/FixedTargets.java b/Mage/src/main/java/mage/target/targetpointer/FixedTargets.java new file mode 100644 index 00000000000..224433f396a --- /dev/null +++ b/Mage/src/main/java/mage/target/targetpointer/FixedTargets.java @@ -0,0 +1,90 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.target.targetpointer; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.cards.Cards; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author LevelX2 + */ +public class FixedTargets implements TargetPointer { + + final ArrayList targets = new ArrayList<>(); + private boolean initialized; + + public FixedTargets(UUID targetId) { + targets.add(new MageObjectReference(targetId)); + this.initialized = false; + } + + public FixedTargets(Cards cards, Game game) { + for (UUID targetId : cards) { + MageObjectReference mor = new MageObjectReference(targetId, game); + targets.add(mor); + } + this.initialized = true; + } + + public FixedTargets(List permanents, Game game) { + for (Permanent permanent : permanents) { + MageObjectReference mor = new MageObjectReference(permanent.getId(), permanent.getZoneChangeCounter(game), game); + targets.add(mor); + } + this.initialized = true; + } + + private FixedTargets(final FixedTargets fixedTargets) { + this.targets.addAll(fixedTargets.targets); + this.initialized = fixedTargets.initialized; + } + + @Override + public void init(Game game, Ability source) { + if (!initialized) { + initialized = true; + for (MageObjectReference mor : targets) { + mor.setZoneChangeCounter(game.getState().getZoneChangeCounter(mor.getSourceId())); + } + } + } + + @Override + public List getTargets(Game game, Ability source) { + // check target not changed zone + ArrayList list = new ArrayList<>(1); + for (MageObjectReference mor : targets) { + if (game.getState().getZoneChangeCounter(mor.getSourceId()) == mor.getZoneChangeCounter()) { + list.add(mor.getSourceId()); + } + } + return list; + } + + @Override + public UUID getFirst(Game game, Ability source) { + // check target not changed zone + for (MageObjectReference mor : targets) { + if (game.getState().getZoneChangeCounter(mor.getSourceId()) == mor.getZoneChangeCounter()) { + return mor.getSourceId(); + } + } + return null; + } + + @Override + public TargetPointer copy() { + return new FixedTargets(this); + } + +} diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index 1b4c5e9d269..e03b1f1bde4 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -74,9 +74,20 @@ public class CardUtil { static String numberStrings[] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "ninteen", "twenty"}; - public static final String[] NON_CHANGELING_SUBTYPES_VALUES = new String[]{"Mountain", "Forest", "Plains", "Swamp", "Island", + public static final String[] NON_CHANGELING_SUBTYPES_VALUES = new String[]{ + // basic lands subtypes + "Mountain", "Forest", "Plains", "Swamp", "Island", + // Enchantment subtypes "Aura", "Curse", "Shrine", + // Artifact subtypes "Equipment", "Fortification", "Contraption", + // Land subtypes + "Desert", "Gate", "Lair", "Locus", "Urza's", "Mine", "Power-Plant", "Tower", + // Planeswalker subtypes + "Ajani", "Ashiok", "Bolas", "Chandra", "Dack", "Daretti", "Domri", "Elspeth", "Freyalise", "Garruk", "Gideon", "Jace", + "Karn", "Kiora", "Koth", "Liliana", "Nahiri", "Nissa", "Narset", "Nixilis", "Ral", "Sarkhan", "Sorin", "Tamiyo", "Teferi", + "Tezzeret", "Tibalt", "Ugin", "Venser", "Vraska", "Xenagos", + // Instant sorcery subtypes "Trap", "Arcane"}; public static final Set NON_CREATURE_SUBTYPES = new HashSet<>(Arrays.asList(NON_CHANGELING_SUBTYPES_VALUES)); @@ -187,7 +198,7 @@ public class CardUtil { if (object instanceof ManaCost) { ManaCost manaCost = (ManaCost) object; Mana mana = manaCost.getOptions().get(0); - int colorless = mana != null ? mana.getColorless() : 0; + int colorless = mana != null ? mana.getGeneric() : 0; if (!updated && colorless > 0) { if ((colorless - reduceCount) > 0) { int newColorless = colorless - reduceCount; @@ -225,7 +236,7 @@ public class CardUtil { boolean updated = false; for (ManaCost manaCost : manaCosts) { Mana mana = manaCost.getOptions().get(0); - int colorless = mana != null ? mana.getColorless() : 0; + int colorless = mana != null ? mana.getGeneric() : 0; if (restToReduce != 0 && colorless > 0) { if ((colorless - restToReduce) > 0) { int newColorless = colorless - restToReduce; @@ -294,7 +305,7 @@ public class CardUtil { Mana reduceMana = new Mana(); for (ManaCost manaCost : manaCostsToReduce) { if (manaCost instanceof MonoHybridManaCost) { - reduceMana.add(Mana.ColorlessMana(2)); + reduceMana.add(Mana.GenericMana(2)); } else { reduceMana.add(manaCost.getMana()); } @@ -303,7 +314,7 @@ public class CardUtil { // subtract colored mana for (ManaCost newManaCost : previousCost) { Mana mana = newManaCost.getMana(); - if (!(newManaCost instanceof MonoHybridManaCost) && mana.getColorless() > 0) { + if (!(newManaCost instanceof MonoHybridManaCost) && mana.getGeneric() > 0) { manaCostToCheckForColorless.add(newManaCost); continue; } @@ -371,7 +382,7 @@ public class CardUtil { if (mana.count() > 0) { if (newManaCost instanceof MonoHybridManaCost) { if (mana.count() == 2) { - reduceMana.setColorless(reduceMana.getColorless() - 2); + reduceMana.setGeneric(reduceMana.getGeneric() - 2); continue; } } @@ -385,12 +396,12 @@ public class CardUtil { if (convertToGeneric) { reduceAmount = reduceMana.count(); } else { - reduceAmount = reduceMana.getColorless(); + reduceAmount = reduceMana.getGeneric(); } if (reduceAmount > 0) { for (ManaCost newManaCost : manaCostToCheckForColorless) { Mana mana = newManaCost.getMana(); - if (mana.getColorless() == 0 || reduceAmount == 0) { + if (mana.getGeneric() == 0 || reduceAmount == 0) { adjustedCost.add(newManaCost); continue; } @@ -401,12 +412,12 @@ public class CardUtil { } continue; } - if (mana.getColorless() > 0) { - if (reduceAmount > mana.getColorless()) { - reduceAmount -= mana.getColorless(); - mana.setColorless(0); + if (mana.getGeneric() > 0) { + if (reduceAmount > mana.getGeneric()) { + reduceAmount -= mana.getGeneric(); + mana.setGeneric(0); } else { - mana.setColorless(mana.getColorless() - reduceAmount); + mana.setGeneric(mana.getGeneric() - reduceAmount); reduceAmount = 0; } } diff --git a/Mage/src/main/java/mage/util/ManaUtil.java b/Mage/src/main/java/mage/util/ManaUtil.java index b3d3f3a1b13..0f753f6c7d7 100644 --- a/Mage/src/main/java/mage/util/ManaUtil.java +++ b/Mage/src/main/java/mage/util/ManaUtil.java @@ -152,7 +152,7 @@ public class ManaUtil { if (countColored.isEmpty()) { // seems there is no colorful mana we can pay for // try to pay {1} - if (unpaidMana.getColorless() > 0) { + if (unpaidMana.getGeneric() > 0) { // use any (lets choose first) return replace(useableAbilities, useableAbilities.values().iterator().next()); } @@ -375,7 +375,7 @@ public class ManaUtil { if (countColorfull == 0) { // seems there is no colorful mana we can use // try to pay {1} - if (mana.getColorless() > 0) { + if (mana.getGeneric() > 0) { // use any (lets choose first) return replace(useableAbilities, useableAbilities.values().iterator().next()); } diff --git a/Mage/src/main/java/mage/watchers/common/DamageDoneWatcher.java b/Mage/src/main/java/mage/watchers/common/DamageDoneWatcher.java index df94911ebc6..644be1cdf54 100644 --- a/Mage/src/main/java/mage/watchers/common/DamageDoneWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/DamageDoneWatcher.java @@ -11,7 +11,6 @@ import java.util.UUID; import mage.MageObjectReference; import mage.constants.WatcherScope; import mage.game.Game; -import mage.game.events.DamageEvent; import mage.game.events.GameEvent; import mage.watchers.Watcher; @@ -19,11 +18,10 @@ import mage.watchers.Watcher; * * @author LevelX2 */ - public class DamageDoneWatcher extends Watcher { - + // which object did how much damage during the turn - public Map damagingObjects = new HashMap<>(); + public Map damagingObjects = new HashMap<>(); public DamageDoneWatcher() { super("DamageDone", WatcherScope.GAME); @@ -41,15 +39,14 @@ public class DamageDoneWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { - switch(event.getType()) { + switch (event.getType()) { case DAMAGED_CREATURE: case DAMAGED_PLANESWALKER: - case DAMAGED_PLAYER: - { + case DAMAGED_PLAYER: { MageObjectReference mor = new MageObjectReference(event.getSourceId(), game); int count = damagingObjects.containsKey(mor) ? damagingObjects.get(mor) : 0; damagingObjects.put(mor, count + event.getAmount()); - } + } } } diff --git a/Mage/src/main/java/mage/watchers/common/DamagedByWatcher.java b/Mage/src/main/java/mage/watchers/common/DamagedByWatcher.java index e4b82c01c67..ed6bd2efdcb 100644 --- a/Mage/src/main/java/mage/watchers/common/DamagedByWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/DamagedByWatcher.java @@ -45,15 +45,23 @@ import mage.watchers.Watcher; */ public class DamagedByWatcher extends Watcher { - public Set damagedCreatures = new HashSet<>(); + public Set damagedBySource = new HashSet<>(); + + private final boolean watchPlaneswalkers; public DamagedByWatcher() { + this(false); + } + + public DamagedByWatcher(boolean watchPlaneswalkers) { super("DamagedByWatcher", WatcherScope.CARD); + this.watchPlaneswalkers = watchPlaneswalkers; } public DamagedByWatcher(final DamagedByWatcher watcher) { super(watcher); - this.damagedCreatures.addAll(watcher.damagedCreatures); + this.damagedBySource.addAll(watcher.damagedBySource); + this.watchPlaneswalkers = watcher.watchPlaneswalkers; } @Override @@ -63,10 +71,12 @@ public class DamagedByWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { - if (event.getType() == EventType.DAMAGED_CREATURE && sourceId.equals(event.getSourceId())) { + boolean eventHasAppropriateType = (event.getType() == EventType.DAMAGED_CREATURE) || + (watchPlaneswalkers && event.getType() == EventType.DAMAGED_PLANESWALKER); + if (eventHasAppropriateType && sourceId.equals(event.getSourceId())) { MageObjectReference mor = new MageObjectReference(event.getTargetId(), game); - if (!damagedCreatures.contains(mor)) { - damagedCreatures.add(mor); + if (!damagedBySource.contains(mor)) { + damagedBySource.add(mor); } } } @@ -74,7 +84,7 @@ public class DamagedByWatcher extends Watcher { @Override public void reset() { super.reset(); - damagedCreatures.clear(); + damagedBySource.clear(); } public boolean wasDamaged(UUID sourceId, Game game) { @@ -86,6 +96,6 @@ public class DamagedByWatcher extends Watcher { } public boolean wasDamaged(Permanent permanent, Game game) { - return damagedCreatures.contains(new MageObjectReference(permanent, game)); + return damagedBySource.contains(new MageObjectReference(permanent, game)); } } diff --git a/Mage/src/main/proto/result.proto b/Mage/src/main/proto/result.proto new file mode 100644 index 00000000000..b24d4714f5f --- /dev/null +++ b/Mage/src/main/proto/result.proto @@ -0,0 +1,77 @@ +package mage.game.result; + +option java_outer_classname = "ResultProtos"; + +message TableProto { + optional MatchProto match = 1; + optional TourneyProto tourney = 2; + optional string game_type = 3; + optional string deck_type = 4; + optional string name = 5; + optional string controller_name = 6; + optional int64 start_time_ms = 7; + optional int64 end_time_ms = 8; +} + +message MatchProto { + optional string name = 1; + optional string game_type = 2; + optional string deck_type = 3; + optional int32 games = 4; + optional int32 draws = 5; + repeated MatchPlayerProto players = 6; +} + +message MatchPlayerProto { + optional string name = 1; + optional int32 wins = 2; + optional MatchQuitStatus quit = 3; + optional bool bye = 4; +} + +enum MatchQuitStatus { + NO_MATCH_QUIT = 0; + IDLE_TIMEOUT = 1; // I + TIMER_TIMEOUT = 2; // T + QUIT = 3; // Q +} + +message TourneyProto { + optional string booster_info = 1; + repeated TourneyPlayerProto players = 2; + repeated TourneyRoundProto rounds = 3; +} + +message TourneyPlayerProto { + optional string name = 1; + optional string player_type = 2; + optional string replaced_player_name = 3; + optional TourneyQuitStatus quit = 4; +} + +enum TourneyQuitStatus { + NO_TOURNEY_QUIT = 0; + DURING_ROUND = 1; + DURING_DRAFTING = 2; + DURING_CONSTRUCTION = 3; +} + +message TourneyRoundProto { + optional int32 round = 1; + repeated MatchProto matches = 2; + repeated string byes = 3; +} + +message UserStatsProto { + optional string name = 1; + + optional int32 tourneys = 2; + optional int32 tourneys_quit_during_round = 3; + optional int32 tourneys_quit_during_drafting = 4; + optional int32 tourneys_quit_during_construction = 5; + + optional int32 matches = 6; + optional int32 matches_idle_timeout = 7; + optional int32 matches_timer_timeout = 8; + optional int32 matches_quit = 9; +} diff --git a/Mage/src/test/java/mage/ManaTest.java b/Mage/src/test/java/mage/ManaTest.java index 796c3c55d79..03034690520 100644 --- a/Mage/src/test/java/mage/ManaTest.java +++ b/Mage/src/test/java/mage/ManaTest.java @@ -144,7 +144,7 @@ public class ManaTest { public void shouldCreateManaFromIntegers() { // when - Mana mana = new Mana(1, 2, 3, 4, 5, 6, 7); + Mana mana = new Mana(1, 2, 3, 4, 5, 6, 7, 8); // then assertEquals(1, mana.getRed()); @@ -152,8 +152,9 @@ public class ManaTest { assertEquals(3, mana.getBlue()); assertEquals(4, mana.getWhite()); assertEquals(5, mana.getBlack()); - assertEquals(6, mana.getColorless()); + assertEquals(6, mana.getGeneric()); assertEquals(7, mana.getAny()); + assertEquals(8, mana.getColorless()); } @Test @@ -161,7 +162,7 @@ public class ManaTest { // given // when - Mana mana = new Mana(-1, 2, 3, 4, 5, 6, 7); + Mana mana = new Mana(-1, 2, 3, 4, 5, 6, 7, 0); // then assertEquals(0, mana.getRed()); @@ -217,6 +218,16 @@ public class ManaTest { assertEquals(1, mana.getBlack()); } + @Test + public void shouldCreateGenericMana() { + + // when + Mana mana = Mana.GenericMana(1); + + // then + assertEquals(1, mana.getGeneric()); + } + @Test public void shouldCreateColorlessMana() { @@ -287,17 +298,17 @@ public class ManaTest { // given // when - Mana mana = Mana.ColorlessMana(-1); + Mana mana = Mana.GenericMana(-1); //then - assertEquals(0, mana.getColorless()); + assertEquals(0, mana.getGeneric()); } @Test public void shouldAddMana() { // given - Mana thisMana = new Mana(1, 2, 3, 4, 5, 6, 7); - Mana thatMana = new Mana(1, 2, 3, 4, 5, 6, 7); + Mana thisMana = new Mana(1, 2, 3, 4, 5, 6, 7, 0); + Mana thatMana = new Mana(1, 2, 3, 4, 5, 6, 7, 0); // when thisMana.add(thatMana); @@ -308,7 +319,7 @@ public class ManaTest { assertEquals(6, thisMana.getBlue()); assertEquals(8, thisMana.getWhite()); assertEquals(10, thisMana.getBlack()); - assertEquals(12, thisMana.getColorless()); + assertEquals(12, thisMana.getGeneric()); assertEquals(14, thisMana.getAny()); } @@ -378,17 +389,17 @@ public class ManaTest { Mana mana = new Mana(); // when - mana.increaseColorless(); + mana.increaseGeneric(); // then - assertEquals(1, mana.getColorless()); + assertEquals(1, mana.getGeneric()); } @Test public void shouldSubtractMana() { // given - Mana thisMana = new Mana(2, 2, 2, 2, 2, 2, 2); - Mana thatMana = new Mana(1, 1, 1, 1, 1, 1, 1); + Mana thisMana = new Mana(2, 2, 2, 2, 2, 2, 2, 2); + Mana thatMana = new Mana(1, 1, 1, 1, 1, 1, 1, 1); // when thisMana.subtract(thatMana); @@ -399,15 +410,16 @@ public class ManaTest { assertEquals(1, thisMana.getBlue()); assertEquals(1, thisMana.getWhite()); assertEquals(1, thisMana.getBlack()); - assertEquals(1, thisMana.getColorless()); + assertEquals(1, thisMana.getGeneric()); assertEquals(1, thisMana.getAny()); + assertEquals(1, thisMana.getColorless()); } @Test public void shouldSubtractCost() { // given - Mana thisMana = new Mana(2, 2, 2, 2, 2, 2, 2); - Mana thatMana = new Mana(10, 1, 1, 1, 10, 1, 1); + Mana thisMana = new Mana(2, 2, 2, 2, 2, 2, 2, 0); + Mana thatMana = new Mana(10, 1, 1, 1, 10, 1, 1, 0); // when thisMana.subtractCost(thatMana); @@ -418,7 +430,7 @@ public class ManaTest { assertEquals(1, thisMana.getBlue()); assertEquals(1, thisMana.getWhite()); assertEquals(-8, thisMana.getBlack()); - assertEquals(1, thisMana.getColorless()); + assertEquals(1, thisMana.getGeneric()); assertEquals(1, thisMana.getAny()); } @@ -430,7 +442,7 @@ public class ManaTest { Mana cost = new Mana(); cost.setRed(4); - cost.setColorless(2); + cost.setGeneric(2); // when available.subtractCost(cost); @@ -449,7 +461,7 @@ public class ManaTest { Mana cost = new Mana(); cost.setRed(4); - cost.setColorless(2); + cost.setGeneric(2); // when available.subtractCost(cost); @@ -458,7 +470,7 @@ public class ManaTest { @Test public void shouldReturnCount() { // given - Mana mana = new Mana(1, 2, 3, 4, 5, 6, 7); + Mana mana = new Mana(1, 2, 3, 4, 5, 6, 7, 0); FilterMana filter = new FilterMana(); filter.setBlack(true); @@ -476,7 +488,7 @@ public class ManaTest { @Test public void shouldReturnString() { // given - Mana mana = new Mana(1, 2, 3, 0, 3, 6, 2); + Mana mana = new Mana(1, 2, 3, 0, 3, 6, 2, 0); // when String ret = mana.toString(); @@ -488,7 +500,7 @@ public class ManaTest { @Test public void shouldClearMana() { // given - Mana mana = new Mana(1, 2, 3, 4, 5, 6, 7); + Mana mana = new Mana(1, 2, 3, 4, 5, 6, 7, 0); // when mana.clear(); @@ -499,14 +511,14 @@ public class ManaTest { assertEquals(0, mana.getBlue()); assertEquals(0, mana.getWhite()); assertEquals(0, mana.getBlack()); - assertEquals(0, mana.getColorless()); + assertEquals(0, mana.getGeneric()); assertEquals(0, mana.getAny()); } @Test public void shouldReturnCopy() { // given - Mana mana = new Mana(1, 2, 3, 4, 5, 6, 7); + Mana mana = new Mana(1, 2, 3, 4, 5, 6, 7, 0); // when Mana copy = mana.copy(); @@ -519,7 +531,7 @@ public class ManaTest { @Test public void shouldGetColorByColoredManaSymbol() { // given - Mana mana = new Mana(1, 1, 1, 1, 1, 1, 1); + Mana mana = new Mana(1, 1, 1, 1, 1, 1, 1, 0); // when int redMana = mana.getColor(ColoredManaSymbol.R); @@ -539,7 +551,7 @@ public class ManaTest { @Test public void shouldGetColorByManaType() { // given - Mana mana = new Mana(1, 1, 1, 1, 1, 1, 1); + Mana mana = new Mana(1, 1, 1, 1, 1, 1, 1, 0); // when int redMana = mana.get(ManaType.RED); @@ -584,7 +596,7 @@ public class ManaTest { public void shouldSetToMana() { // given Mana mana = new Mana(); - Mana newMana = new Mana(1, 2, 3, 4, 5, 6, 7); + Mana newMana = new Mana(1, 2, 3, 4, 5, 6, 7, 0); // when mana.setToMana(newMana); @@ -597,8 +609,8 @@ public class ManaTest { @Test public void shouldHaveEqualManaValue() { // given - Mana mana = new Mana(1, 2, 3, 4, 5, 6, 7); - Mana newMana = new Mana(1, 2, 3, 4, 5, 6, 7); + Mana mana = new Mana(1, 2, 3, 4, 5, 6, 7, 0); + Mana newMana = new Mana(1, 2, 3, 4, 5, 6, 7, 0); // when boolean equalMana = mana.equalManaValue(newMana); @@ -632,7 +644,7 @@ public class ManaTest { mana.setBlue(-4); mana.setWhite(-4); mana.setBlack(-4); - mana.setColorless(-4); + mana.setGeneric(-4); mana.setAny(-4); // then @@ -641,7 +653,7 @@ public class ManaTest { assertEquals(0, mana.getBlue()); assertEquals(0, mana.getWhite()); assertEquals(0, mana.getBlack()); - assertEquals(0, mana.getColorless()); + assertEquals(0, mana.getGeneric()); assertEquals(0, mana.getAny()); } } diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index b80dee2423f..7ccb3ea3638 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -5894,9 +5894,10 @@ Serum Visions|Friday Night Magic|183|C|{U}|Sorcery|||Draw a card.$Scry 2. (To Orator of Ojutai|Friday Night Magic|184|U|{1}{W}|Creature - Bird Monk|0|4|Defneder, flying$As an additional cost to cast Orator of Ojutai, you may reveal a Dragon card from your hand.$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.| Ultimate Price|Friday Night Magic|185|U|{1}{B}|Instant|||Destroy target monocolored creature.| Roast|Friday Night Magic|186|U|{1}{R}|Sorcery|||Roast deals 5 damage to target creature without flying.| -Anticipate|Friday Night Magic|186|C|{1}{U}|Instant|||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.| -Nissa's Pilgrimage|Friday Night Magic|187|C|{2}{G}|Sorcery|||Search your library for up to two basic Forest cards, reveal those cards, and put one onto the battlefield tapped and the rest into your hand. Then shuffle your library.$Spell Mastery — If there are two or more instant and/or sorcery cards in your graveyard, search your library for up to three basic Forest cards instead of two.| -Clash of Wills|Friday Night Magic|188|U|{X}{U}|Instant|||Counter target spell unless its controller pays {X}.| +Anticipate|Friday Night Magic|187|C|{1}{U}|Instant|||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.| +Nissa's Pilgrimage|Friday Night Magic|188|C|{2}{G}|Sorcery|||Search your library for up to two basic Forest cards, reveal those cards, and put one onto the battlefield tapped and the rest into your hand. Then shuffle your library.$Spell Mastery — If there are two or more instant and/or sorcery cards in your graveyard, search your library for up to three basic Forest cards instead of two.| +Clash of Wills|Friday Night Magic|189|U|{X}{U}|Instant|||Counter target spell unless its controller pays {X}.| +Smash to Smithereens|Friday Night Magic|190|C|{1}{R}|Instant|||Destroy target artifact. Smash to Smithereens deals 3 damage to that artifact's controller.| Angel of Salvation|Future Sight|1|R|{6}{W}{W}|Creature - Angel|5|5|Flash; convoke (Each creature you tap while casting this spell reduces its cost by {1} or by one mana of that creature's color.)$Flying$When Angel of Salvation enters the battlefield, prevent the next 5 damage that would be dealt this turn to any number of target creatures and/or players, divided as you choose.| Knight of Sursi|Future Sight|10|C|{3}{W}|Creature - Human Knight|2|2|Flying; flanking (Whenever a creature without flanking blocks this creature, the blocking creature gets -1/-1 until end of turn.)$Suspend 3-{W} (Rather than cast this card from your hand, you may pay {W} and exile it with three time counters on it. At the beginning of your upkeep, remove a time counter. When the last is removed, cast it without paying its mana cost. It has haste.)| Haze of Rage|Future Sight|100|U|{1}{R}|Sorcery|||Buyback {2} (You may pay an additional {2} as you cast this spell. If you do, put this card into your hand as it resolves.)$Creatures you control get +1/+0 until end of turn.$Storm (When you cast this spell, copy it for each spell cast before it this turn.)| @@ -28207,7 +28208,7 @@ Hallowed Fountain|Zendikar Expeditions|6|M||Land - Plains Island|||({tap}: Ad Watery Grave|Zendikar Expeditions|7|M|Land - Island Swamp|||({tap}: Add {U} or {B} to your mana pool.)$As Watery Grave enters the battlefield, you may pay 2 life. If you don't, Watery Grave enters the battlefield tapped.| Blood Crypt|Zendikar Expeditions|8|M||Land - Swamp Mountain|||({tap}: Add {B} or {R} to your mana pool.)$As Blood Crypt enters the battlefield, you may pay 2 life. If you don't, Blood Crypt enters the battlefield tapped.| Stomping Ground|Zendikar Expeditions|9|M||Land - Mountain Forest|||({tap}: Add {R} or {G} to your mana pool.)$As Stomping Ground enters the battlefield, you may pay 2 life. If you don't, Stomping Ground enters the battlefield tapped.| -Temple Garden|Zendikar Expeditions|10|M||Land - Forest Plains|||({tap}: Add {G} or {W} to your mana pool.)$As Temple Garden enters the battlefield, you may pay 2 life. If you don't, Temple Garden enters the battlefield tapped.| +Temple Garden|Zendikar Expeditions|10|M||Land - Forest Plains|||({tap}: Add {G} or {W} to your mana pool.)$As Temple Garden enters the battlefield, you may pay 2 life. If you don't, Temple Garden enters the battlefield tapped.| Godless Shrine|Zendikar Expeditions|11|M||Land - Plains Swamp|||({tap}: Add {W} or {B} to your mana pool.)$As Godless Shrine enters the battlefield, you may pay 2 life. If you don't, Godless Shrine enters the battlefield tapped.| Steam Vents|Zendikar Expeditions|12|M||Land - Island Mountain|||({tap}: Add {U} or {R} to your mana pool.)$As Steam Vents enters the battlefield, you may pay 2 life. If you don't, Steam Vents enters the battlefield tapped.| Overgrown Tomb|Zendikar Expeditions|13|M||Land - Swamp Forest|||({tap}: Add {B} or {G} to your mana pool.)$As Overgrown Tomb enters the battlefield, you may pay 2 life. If you don't, Overgrown Tomb enters the battlefield tapped.| @@ -28247,57 +28248,184 @@ Deceiver of Form|Oath of the Gatewatch|1|R|{6}{C}|Creature - Eldrazi|8|8|At the Eldrazi Mimic|Oath of the Gatewatch|2|R|{2}|Creature - Eldrazi|2|1|Whenever another colorless creature enters the battlefield under your control, you may have the base power and toughness of Eldrazi Mimic become that creature's power and toughness until end of turn.| Endbringer|Oath of the Gatewatch|3|R|{5}{C}|Creature - Eldrazi|5|5|Untap Endbringer during each other player's untap step.${T}: Endbringer deals 1 damage to target creature or player.${C}, {T}: Target creature can't attack or block this turn.${C}{C}, {T}: Draw a card.| Kozilek, the Great Distortion|Oath of the Gatewatch|4|M|{8}{C}{C}|Legendary Creature - Eldrazi|12|12|When you cast Kozilek, the Great Distortion, if you have fewer than seven cards in hand, draw cards equal to the difference.$Menace$Discard a card with converted mana cost X: Counter target spell with converted mana cost X.| +Kozilek's Pathfinder|Oath of the Gatewatch|5|C|{6}|Creature - Eldrazi|5|5|{C}: Target creature can't block Kozilek's Pathfinder this turn.| +Matter Reshaper|Oath of the Gatewatch|6|R|{2}{C}|Creature - Eldrazi|3|2|When Matter Reshaper dies, reveal the top card of your library. You may put that card onto the battlefield if it's a permanent card with converted mana cost 3 or less. Otherwise, put that card into your hand.| +Reality Smasher|Oath of the Gatewatch|7|R|{4}{C}|Creature - Eldrazi|5|5|Trample, haste$Whenever Reality Smasher becomes the target of a spell an opponent controls, counter that spell unless its controller discards a card.| Spatial Contortion|Oath of the Gatewatch|8|U|{1}{C}|Instant|||Target creature gets +3/-3 until end of turn.| +Thought-Knot Seer|Oath of the Gatewatch|9|R|{3}{C}|Creature - Eldrazi|4|4|When Thought-Knot Seer enters the battlefield, target opponent reveals his or her hand. You choose a nonland card from it and exile that card.$When Thought-Knot Seer leaves the battlefield, target opponent draws a card.| Walker of the Wastes|Oath of the Gatewatch|10|U|{4}{C}|Creature - Eldrazi|4|4|Trample$Walker of the Wastes gets +1/+1 for each land you control named Wastes.| +Warden of Geometries|Oath of the Gatewatch|11|C|{4}|Creature - Eldrazi Drone|2|3|Vigilance${T}: Add {C} to your mana pool.| +Warping Wail|Oath of the Gatewatch|12|U|{1}{C}|Instant|||Choose one — Exile target creature with power or toughness 1 or less.; Counter target sorcery spell.; Put a 1/1 colorless Eldrazi Scion creature token onto the battlefield. It has "Sacrifice this creature: Add {C} to your mana pool."| +Eldrazi Displacer|Oath of the Gatewatch|13|R|{2}{W}|Creature - Eldrazi|3|3|Devoid (This card has no color.)${2}{C}: Exile another target creature, then return it to the battlefield tapped under its owner's control.| +Affa Protector|Oath of the Gatewatch|14|C|{2}{W}|Creature - Human Soldier Ally|1|4|Vigilance| +Allied Reinforcements|Oath of the Gatewatch|15|U|{3}{W}|Sorcery|||Put two 2/2 white Knight Ally creature tokens onto the battlefield.| Call the Gatewatch|Oath of the Gatewatch|16|R|{2}{W}|Sorcery|||Search your library for a planeswalker card, reveal it, and put it into your hand. Then shuffle your library.| +Dazzling Reflection|Oath of the Gatewatch|17|C|{1}{W}|Instant|||You gain life equal to target creature's power. The next time that creature would deal damage this turn, prevent that damage.| +Expedition Raptor|Oath of the Gatewatch|18|C|{3}{W}{W}|Creature - Bird|2|2|Flying$When Expedition Raptor enters the battlefield, support 2. (Put a +1/+1 counter on each of up to two other target creatures.)| General Tazri|Oath of the Gatewatch|19|M|{4}{W}|Legendary Creature - Human Ally|3|4|When General Tazri enters the battlefield, you may search your library for an Ally creature card, reveal it, put it into your hand, then shuffle your library.${W}{U}{B}{R}{G}: Ally creatures you control get +X/+X until end of turn, where X is the number of colors among those creatures.| Immolating Glare|Oath of the Gatewatch|20|U|{1}{W}|Instant|||Destroy target attacking creature.| +Iona's Blessing|Oath of the Gatewatch|21|U|{3}{W}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +2/+2, has vigilance, and can block an additional creature.| +Isolation Zone|Oath of the Gatewatch|22|C|{2}{W}{W}|Enchantment|||When Isolation Zone enters the battlefield, exile target creature or enchantment an opponent controls until Isolation Zone leaves the battlefield. (That permanent returns under its owner's control.)| +Kor Scythemaster|Oath of the Gatewatch|23|C|{2}{W}|Creature - Kor Soldier Ally|3|1|Kor Scythemaster has first strike as long as its attacking.| +Kor Sky Climber|Oath of the Gatewatch|24|C|{2}{W}|Creature - Kor Soldier Ally|3|2|{1}{W}: Kor Sky Climber gains flying until end of turn.| Linvala, the Preserver|Oath of the Gatewatch|25|M|{4}{W}{W}|Legendary Creature - Angel|5|5|Flying$When Linvala, the Preserver enters the battlefield, if an opponent has more life than you, you gain 5 life.$When Linvala enters the battlefield, if an opponent controls more creatures than you, put a 3/3 white Angel creature token with flying onto the battlefield.| +Make a Stand|Oath of the Gatewatch|26|U|{2}{W}|Instant|||Creature you control get +1/+0 and gain indestructible until end of turn. (Damage and effects that say "destroy" don't destroy them.)| +Makindi Aeronaut|Oath of the Gatewatch|27|C|{1}{W}|Creature - Kor Scout Ally|1|3|Flying| +Mighty Leap|Oath of the Gatewatch|28|C|{1}{W}|Instant|||Target creature gets +2/+2 and gain flying until end of turn.| Munda's Vanguard|Oath of the Gatewatch|29|R|{4}{W}|Creature - Kor Knight Ally|3|3|Cohort — {T}, Tap an untapped Ally you control: Put a +1/+1 counter on each creature you control.| +Oath of Gideon|Oath of the Gatewatch|30|R|{2}{W}|Legendary Enchantment|||When Oath of Gideon enters the battlefield, put two 1/1 Kor Ally creature tokens onto the battlefield.$Each planeswalker you control enters the battlefield with an additional loyalty counter on it.| +Ondu War Cleric|Oath of the Gatewatch|31|C|{1}{W}|Creature - Human Cleric Ally|2|2|Cohort — {T}, Tap an untapped Ally you control: You gain 2 life.| +Relief Captain|Oath of the Gatewatch|32|U|{2}{W}{W}|Creature - Kor Knight Ally|3|2|When Relief Captain enters the battlefield, support 3 (Put a +1/+1 counter on each of up to three other target creatures.)| +Searing Light|Oath of the Gatewatch|33|C|{W}|Instant|||Destroying target attacking or blocking creature with power 2 or less.| Shoulder to Shoulder|Oath of the Gatewatch|34|C|{2}{W}|Sorcery|||Support 2. (Put a +1/+1 counter on each of up to two target creatures.)$Draw a card.| +Spawnbinder Mage|Oath of the Gatewatch|35|C|{3}{W}|Creature - Human Wizard Ally|2|4|Cohort — {T}, Tap an untapped Ally you control: Tap target creature.| +Steppe Glider|Oath of the Gatewatch|36|U|{4}{W}|Creature - Elemental|2|4|Flying, vigilance${1}{W}: Target creature with a +1/+1 counter on it gains flying and vigilance until end of turn.| Stone Haven Outfitter|Oath of the Gatewatch|37|R|{1}{W}|Creature - Kor Artificer Ally|2|2|Equipped creatures you control get +1/+1.$Whenever an equipped creature you control dies, draw a card.| +Stoneforge Acolyte|Oath of the Gatewatch|38|U|{W}|Creature - Kor Artificer Ally|1|2|Cohort — {T}, Tap an untapped Ally you control: Look at the top four cards of your library. You may reveal an Equipment card from among them and put it into your hand. Put the rest on the bottom of your library in any order.| +Wall of Resurgence|Oath of the Gatewatch|39|U|{2}{W}|Creature - Wall|0|6|Defender$When Wall of Resurgence enters the battlefield, you may put three +1/+1 counters on target land you control. If you do, that land becomes a 0/0 Elemental creature with haste that's still a land.| +Abstruse Interference|Oath of the Gatewatch|40|C|{2}{U}|Instant|||Devoid (This card has no color.)$Counter target spell unless its controller pays {1}. You put a 1/1 colorless Eldrazi Scion creature token onto the battlefield. It has "Sacrifice this creature: Add {C} to your mana pool."| +Blinding Drone|Oath of the Gatewatch|41|C|{1}{U}|Creature - Eldrazi Drone|1|3|Devoid (This card has no color.)${C}, {T}: Tap target creature.| +Cultivator Drone|Oath of the Gatewatch|42|C|{2}{U}|Creature - Eldrazi Drone|2|3|Devoid (This card has no color.)${T}: Add {C} to your mana pool. Spend this mana only to cast a colorless spell, activate an ability of a colorless permanent, or pay a cost that contains {C}.| Deepfathom Skulker|Oath of the Gatewatch|43|R|{5}{U}|Creature - Eldrazi|4|4|Devoid (This card has no color.)$Whenever a creature you control deals combat damage to a player, you may draw a card.${3}{C}: Target creature can't be blocked this turn.| +Dimensional Infiltrator|Oath of the Gatewatch|44|R|{1}{U}|Creature - Eldrazi|2|1|Devoid (This card has no color.)$Flash$Flying${1}{C}: Target opponent exiles the top card of his or her library. If it's a land card, you may return Dimensional Infiltrator to its owner's hand.| +Gravity Negator|Oath of the Gatewatch|45|C|{3}{U}|Creature - Eldrazi Drone|2|3|Devoid (This card has no color.)$Flying$Whenenever Gravity Negator attacks, you may pay {C}. If you do, another target creature gains flying until end of turn.| Prophet of Distortion|Oath of the Gatewatch|46|U|{U}|Creature - Eldrazi Drone|1|2|Devoid (This card has no color.)${3}{C}: Draw a card.| +Slip Through Space|Oath of the Gatewatch|47|C|{U}|Sorcery|||Devoid (This card has no color.)$Target creature can't be blocked this turn.$Draw a card.| +Thought Harvester|Oath of the Gatewatch|48|U|{3}{U}|Creature - Eldrazi Drone|2|4|Devoid (This card has no color.)$Flying$Whenever you cast a colorless spell, target opponent exiles the top card of his or her library.| +Void Shatter|Oath of the Gatewatch|49|U|{1}{U}{U}|Instant|||Devoid (This card has no color.)$Counter target spell. If that spell is countered this way, exile it instead of putting it into its owner's graveyard.| +Ancient Crab|Oath of the Gatewatch|50|C|{1}{U}{U}|Creature - Crab|1|5|| Comparative Analysis|Oath of the Gatewatch|51|C|{3}{U}|Instant|||Surge {2}{U} $Target player draws two cards.| +Containment Membrane|Oath of the Gatewatch|52|C|{2}{U}|Enchantment - Aura|||Surge {U} (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn.)$Enchant creature$Enchanted creature doesn't untap during its controller's untap step.| Crush of Tentacles|Oath of the Gatewatch|53|M|{4}{U}{U}|Sorcery|||Surge {3}{U}{U} (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn.)$Return all nonland permanents to their owners' hands. If Crush of Tentacles surge cost was paid, put an 8/8 blue Octopus creature token onto the battlefield.| +Cyclone Sire|Oath of the Gatewatch|54|U|{4}{U}|Creature - Elemental|3|4|Flying$When Cyclone Sire dies, you may put three +1/+1 counters on target land you control. If you do, that land becomes a 0/0 Elemental creature with haste that's still a land.| +Gift of Tusks|Oath of the Gatewatch|55|U|{U}|Instant|||Until end of turn, target creature loses all abilities and becomes a green Elephant with base power and toughness 3/3.| +Grip of the Roil|Oath of the Gatewatch|56|U|{2}{U}|Instant|||Surge {1}{U} (You masy cast this spell for its surge cost if you or a teammate has cast another spell this turn.)$Tap target creature. It doesn't untap during its controller's next untap step.$Draw a card.| +Hedron Alignment|Oath of the Gatewatch|57|R|{2}{U}|Enchantment|||Hexproof$At the beginning of your upkeep, you may reveal your hand. If you do, you win the game if you own a card named Hedron Alignment in exile, in your hand, in your graveyard, and on the battlefield.${1}{U}: Scry 1.| +Jwar Isle Avenger|Oath of the Gatewatch|58|C|{4}{U}|Creature - Sphinx|3|3|Surge {2}{U} (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn.)$Flying| +Negate|Oath of the Gatewatch|59|C|{1}{U}|Instant|||Counter target noncreature spell.| Oath of Jace|Oath of the Gatewatch|60|R|{2}{U}|Legendary Enchantment|||When Oath of Jace enters the battlefield, draw three cards, then discard two cards.$At the beginning of your upkeep, scry X, where X is the number of planeswalkers you control.| +Overwhelming Denial|Oath of the Gatewatch|61|R|{2}{U}{U}|Instant|||Surge {U}{U} (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn.)$Overwhelming Denial can't be countered by spell or abilities.$Counter target spell.| +Roiling Waters|Oath of the Gatewatch|62|U|{5}{U}{U}|Sorcery|||Return up to two target creatures your opponents control to their owners' hands. Target player draws two cards.| Sphinx of the Final Word|Oath of the Gatewatch|63|M|{5}{U}{U}|Creature - Sphinx|5|5|Sphinx of the Final Word can't be countered.$Flying, hexproof$Instant and sorcery spells you control can't be countered by spells or abilities.| +Sweep Away|Oath of the Gatewatch|64|C|{2}{U}|Instant|||Return target creature to its owner's hand. If that creature is attacking, you may put it on top of its owner's library instead.| +Umara Entangler|Oath of the Gatewatch|65|C|{1}{U}|Creature - Merfolk Rogue Ally|2|1|Prowess (Whenever you cast a noncreature spell, this creature gets +1/+1 until end of turn.)| +Unity of Purpose|Oath of the Gatewatch|66|U|{3}{U}|Instant|||Support 2. (Put a +1/+1 counter on each of up to two target creatures.)$Untap each creature you control with a +1/+1 counter on it.| +Bearer of Silence|Oath of the Gatewatch|67|R|{1}{B}|Creature - Eldrazi|2|1|Devoid (This card has no color.)$When you cast Bearer of Silence, you may pay {1}{C}. If you do, target opponent sacrifices a creature.$Flying$Bearer of Silence can't block.| Dread Defiler|Oath of the Gatewatch|68|R|{6}{B}|Creature - Eldrazi|6|8|Devoid (This card has no color.)${3}{C}, Exile a creature card from your graveyard: Target opponent loses life equal to the exiled card's power.| -Skinning Tendrils|Oath of the Gatewatch|70|U|{1}{B}{B}|Sorcery|||Devoid (This card has no color.)$All creatures get -2/-2 until end of turn. If a creature would die this turn, exile it instead.| +Essence Depleter|Oath of the Gatewatch|69|U|{2}{B}|Creature - Eldrazi|2|3|Devoid (This card has no color.)${1}{C}: Target opponent loses 1 life and you gain 1 life.| +Flaying Tendrils|Oath of the Gatewatch|70|U|{1}{B}{B}|Sorcery|||Devoid (This card has no color.)$All creatures get -2/-2 until end of turn. If a creature would die this turn, exile it instead.| +Havoc Sower|Oath of the Gatewatch|71|U|{3}{B}|Creature - Eldrazi Drone|3|3|Devoid (This card has no colorl.)${1}{C}: Havoc Sower gets +2/+1 until end of turn.| +Inverter of Truth|Oath of the Gatewatch|72|M|{2}{B}{B}|Creature - Eldrazi|6|6|Devoid (This card has no color.)$Flying$When Inverter of Truth enters the battlefield, exile all cards from your library face down, then shuffle all cards from your graveyard into your library.| +Kozilek's Shrieker|Oath of the Gatewatch|73|C|{2}{B}|Creature - Eldrazi Drone|3|2|Devoid (This card has no color.)${C}: Kozilek's Shrieker gets +1/+0 and gains menace until end of turn. (It can't be blocked except by two or more creatures.)| +Kozilek's Translator|Oath of the Gatewatch|74|C|{4}{B}|Creature - Eldrazi Drone|3|5|Devoid (This card has no color.)$Pay 1 life: Add {C} to your mana pool. Activate this ability only once each turn.| +Oblivion Strike|Oath of the Gatewatch|75|C|{3}{B}|Sorcery|||Devoid (This card has no color.)$Exile target creature.| +Reaver Drone|Oath of the Gatewatch|76|U|{B}|Creature - Eldrazi Drone|2|1|Devoid (This card has no color.)$At the beginning of your upkeep, you lose 1 life unless you control another colorless creature.| +Sifter of Skulls|Oath of the Gatewatch|77|R|{3}{B}|Creature - Eldrazi|4|3|Devoid (This card has no color.)$Whenever another nontoken creature you control dies, put a 1/1 colorless Eldrazi Scion creature token onto the battlefield. It has "Sacrifice this creature: Add {C} to your mana pool."| +Sky Scourer|Oath of the Gatewatch|78|C|{1}{B}|Creature - Eldrazi Drone|1|2|Devoid (This card has no color.)$Flying$Whenever you cast a colorless spell, Sky Scourer gets +1/+0 until end of turn.| +Slaughter Drone|Oath of the Gatewatch|79|C|{1}{B}|Creature - Eldrazi Drone|2|2|Devoid (This card has no color.)${C}: Slaughter Drone gains deathtouch until end of turn. (Any amount of damage to a creature is enough to destroy it. {C} represents colorless mana.)| +Unnatural Endurance|Oath of the Gatewatch|80|C|{B}|Instant|||Devoid (This card has no color.)$Target creature gets +2/+0 until end of turn. Regenerate it.| +Visions of Brutality|Oath of the Gatewatch|81|U|{1}{B}|Enchantment - Aura|||Devoid (This card has no color.)$Enchant creature$Enchanted creature can't block.$Whenever enchanted creature deals damage, its controller loses that much life.| +Witness the End|Oath of the Gatewatch|82|C|{3}{B}|Sorcery|||Devoid (This card has no color.)$Target opponent exiles two cards from his or her hand and loses 2 life.| +Corpse Churn|Oath of the Gatewatch|83|C|{1}{B}|Instant|||Put the top three cards of your library into your graveyard, then you may return a creature card from your graveyard to your hand.| +Drana's Chosen|Oath of the Gatewatch|84|R|{3}{B}|Creature - Vampire Shaman Ally|2|2|Cohort — {T}, Tap an untapped Ally you control: Put a 2/2 black Zombie creature token onto the battlefield tapped.| +Grasp of Darkness|Oath of the Gatewatch|85|U|{B}{B}|Instant|||Target creature gets -4/-4 until end of turn.| Kalitas, Traitor of Ghet|Oath of the Gatewatch|86|M|{2}{B}{B}|Legendary Creature - Vampire Warrior|3|4|Lifelink$If a nontoken creature an opponent controls would die, instead exile that card and put a 2/2 black Zombie creature token onto the battlefield.${2}{B}, Sacrifice another Vampire or Zombie: Put two +1/+1 counters on Kalitas, Traitor of Ghet.| +Malakir Soothsayer|Oath of the Gatewatch|87|U|{4}{B}|Creature - Vampire Shaman Ally|4|4|Cohort — {T}, Tap an untapped Ally you control: You draw a card and you lose a life.| +Null Caller|Oath of the Gatewatch|88|U|{3}{B}|Creature - Vampire Shaman|2|4|{3}{B}, Exile a creature card from your graveyard: Put a 2/2 black Zombie creature token onto the battlefield tapped.| Remorseless Punishment|Oath of the Gatewatch|89|R|{3}{B}{B}|Sorcery|||Target opponent loses 5 life unless that player discards two cards or sacrifices a creature or planeswalker. Repeat this process once.| +Tar Snare|Oath of the Gatewatch|90|C|{2}{B}|Instant|||Target creature gets -3/-2 until end of turn.| +Untamed Hunger|Oath of the Gatewatch|91|C|{2}{B}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +2/+1 and has menace. (It can't be blocked except by two or more creatures.(| +Vampire Envoy|Oath of the Gatewatch|92|C|{2}{B}|Creature - Vampire Cleric Ally|1|4|Flying$Whenever Vampire Envoy becomes tapped, you gain 1 life.| +Zulaport Chainmage|Oath of the Gatewatch|93|C|{3}{B}|Creature - Human Shaman Ally|4|2|Cohort — {T}, Tap an untapped Ally you control: Target opponent loses 2 life.| +Consuming Sinkhole|Oath of the Gatewatch|94|C|{3}{R}|Instant|||Devoid (This card has no color.)$Choose one — Exile target land creature. Consuming Sinkhole deals 4 damage to target player.| +Eldrazi Aggressor|Oath of the Gatewatch|95|C|{2}{R}|Creature - Eldrazi Drone|2|3|Devoid (This card has no color.)$Eldrazi Aggressor has haste as long as you control another colorless creature.| Eldrazi Obligator|Oath of the Gatewatch|96|R|{2}{R}|Creature - Eldrazi Drone|3|1|Devoid (This card has no color.)$Haste$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.| +Immobilizer Eldrazi|Oath of the Gatewatch|97|U|{1}{R}|Creature - Eldrazi Drone|2|1|Devoid (This card has no color.)${2}{C}: Each creature with toughness greater than its power can't block this turn.| Kozilek's Return|Oath of the Gatewatch|98|M|{2}{R}|Instant|||Devoid (This card has no color.)$Kozilek's Return deals 2 damage to each creature.$Whenever you cast an Eldrazi creature spell with converted mana cost 7 or greater, you may exile Kozilek's Return from your graveyard. If you do, Kozilek's Return deals 5 damage to each creature.| +Maw of Kozilek|Oath of the Gatewatch|99|C|{3}{R}|Creature - Eldrazi Drone|2|5|Devoid (This card has no color.)${C}: Maw of Kozilek gets +2/-2 until end of turn.| +Reality Hemorrhage|Oath of the Gatewatch|100|C|{1}{R}|Instant|||Devoid (This card has no color.)$Reality Hemorrhage deals 2 damage to target creature or player.| +Akoum Flameseeker|Oath of the Gatewatch|101|C|{2}{R}|Creature - Human Shaman Ally|3|2|Cohort — {T}, Tap an untapped Ally you control: Discard a card. If you do, draw a card.| +Boulder Salvo|Oath of the Gatewatch|102|C|{4}{R}|Sorcery|||Surge {1}{R} (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn.)$Boulder Salvo deals 4 damage to target creature.| +Brute Strength|Oath of the Gatewatch|103|C|{1}{R}|Instant|||Target creature gets +3/+1 and gain trample until end of turn.| Chandra, Flamecaller|Oath of the Gatewatch|104|M|{4}{R}{R}|Planeswalker - Chandra|||+1: Put two 3/1 red Elemental creature tokens with haste onto the battlefield. Exile them at the beginning of the next end step.$0: Discard all the cards in your hand, then draw that many cards plus one.$-X: Chandra, Flamecaller deals X damage to each creature.| +Cinder Hellion|Oath of the Gatewatch|105|C|{4}{R}|Creature - Hellion|4|4|Trample$When Cinder Hellion enters the battlefield, it deals 2 damage to target opponent.| +Devour in Flames|Oath of the Gatewatch|106|U|{2}{R}|Sorcery|||As an additional cost to cast Devour in Flames, return a land you control to its owner's hand.$Devour in Flames deals 5 damage to target creature or planeswalker.| Embodiment of Fury|Oath of the Gatewatch|107|U|{3}{R}|Creature - Elemental|4|3|Trample$Land creatures you control have trample.$Landfall - Whenever a land enters the battlefield under your control, you may have target land you control become a 3/3 Elemental creature with haste until end of turn. It's still a land.| +Expedite|Oath of the Gatewatch|108|C|{R}|Instant|||Target creature gains haste until end of turn.$Draw a card.| +Fall of the Titans|Oath of the Gatewatch|109|R|{X}{X}{R}|Instant|||Surge {X}{R} (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn.)$Fall of the Titans deals X damage to each of up to two target creatures and/or players.| Goblin Dark-Dwellers|Oath of the Gatewatch|110|R|{3}{R}{R}|Creature - Goblin|4|4|Menace$When Goblin Dark-Dwellers enters the battlefield, you may cast target instant or sorcery card with converted mana cost 3 or less from your graveyard without paying its mana cost. If that card would be put into your graveyard this turn, exile it instead.| +Goblin Freerunner|Oath of the Gatewatch|111|C|{3}{R}|Creature - Goblin Warrior Ally|3|2|Surge {1}{R} (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn.)$Menace (This creature can't be blocked expect by two or more creatures.) +Kazuul's Toll Collector|Oath of the Gatewatch|112|U|{2}{R}|Creature - Ogre Warrior|3|2|{0}: Attach target Equipment you control to Kazuul's Toll Collector. Activate this ability only any time you could cast a sorcery.| +Oath of Chandra|Oath of the Gatewatch|113|R|{1}{R}|Legendary Enchantment|||When Oath of Chandra enters the battlefield, it deals 3 damage to target creature an opponent controls.$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.| +Press into Service|Oath of the Gatewatch|114|U|{4}{R}|Sorcery|||Support 2. (Put a +1/+1 counter on each of up to two target creatures.)$Gain control of target creature until end of turn. Untap that creature. It gains haste until end of turn.| +Pyromancer's Assault|Oath of the Gatewatch|115|U|{3}{R}|Enchantment|||Whenever you cast your second spell each turn, Pyromancer's Assault deals 2 damage to target creature or player.| Reckless Bushwhacker|Oath of the Gatewatch|116|U|{2}{R}|Creature - Goblin Warrior Ally|2|1|Surge {1}{R} (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn.)$Haste$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.| +Sparkmage's Gambit|Oath of the Gatewatch|117|C|{1}{R}|Sorcery|||Sparkmage's Gambit deals 1 damage to each of up to two target creatures. Those creatures can't block this turn.| +Tears of Valakut|Oath of the Gatewatch|118|U|{1}{R}|Instant|||Tears of Valakut can't be countered by spells or abilities.$Tears of Valakut deals 5 damage to target creature with flying.| Tyrant of Valakut|Oath of the Gatewatch|119|R|{5}{R}{R}|Creature - Dragon|5|4|Surge {3}{R}{R} (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn.)$Flying$When Tyrant of Valakut enters the battlefield, if its surge cost was paid, it deals 3 damage to target creature or player.| +Zada's Commando|Oath of the Gatewatch|120|C|{1}{R}|Creature - Goblin Archer Ally|2|1|First Strike$Cohort — {T}, Tap an untapped Ally you control: Zada's Commando deals 1 damage to target opponent.| +Birthing Hulk|Oath of the Gatewatch|121|U|{6}{G}|Creature - Eldrazi Drone|5|4|Devoid (This card has no color.)When Birthing Hulk enters the battlefield, put two 1/1 colorless Eldrazi Scion creature tokens onto the battlefield. They have "Sacrifice this creature: Add {C} to your mana pool."${1}{C}: Regenerate Birthing Hulk.| +Ruin in Their Wake|Oath of the Gatewatch|122|U|{1}{G}|Sorcery|||Devoid (This card has no color.)$Search your library for a basic land card and reveal it. You may put that card onto the battlefield tapped if you control a land named Wastes. Otherwise, put that card into your hand. Then shuffle your library.| Scion Summoner|Oath of the Gatewatch|123|C|{2}{G}|Creature - Eldrazi Drone|2|2|Devoid (This card has no color.)$When Scion Summoner enters the battlefield, put a 1/1 colorless Eldrazi Scion creature token onto the battlefield. It has "Sacrifice this creature: Add {C} to your mana pool."| +Stalking Drone|Oath of the Gatewatch|126|C|{1}{G}|Creature - Eldrazi Drone|2|2|Devoid (This card has no colorl.)${C}: Stalking Drone gets +1/+2 until end of turn. Activate this ability only once each turn.| Vile Redeemer|Oath of the Gatewatch|125|R|{2}{G}|Creature - Eldrazi|3|3|Devoid (This card has no color.)$Flash$When you cast Vile Redeemer, you may pay {C}. If you do put a 1/1 colorless Eldrazi Scion creature token onto the battlefield for each nontoken creature that died under your control this turn. They have "Sacrifice this creature: Add {C} to your mana pool."| World Breaker|Oath of the Gatewatch|126|M|{6}{G}|Creature - Eldrazi|5|7|Devoid (This card has no color.)$When you cast World Breaker, exile target artifact, enchantment, or land.$Reach${2}{C}, Sacrifice a land: Return World Breaker from your graveyard to your hand. ({C} represents colorless mana.)| +Baloth Pup|Oath of the Gatewatch|127|U|{1}{G}|Creature - Beast|3|1|Baloth Pup has trample as long as it has a +1/+1 counter on it.| +Bonds of Mortality|Oath of the Gatewatch|128|U|{1}{G}|Enchantment|||When Bonds of Mortality enters the battlefield, draw a card.${G}: Creatures your opponents control lose hexproof and indestructible until end of turn.| +Canopy Gorger|Oath of the Gatewatch|129|C|{4}{G}{G}|Creature - Wurm|6|5|| +Elemental Uprising|Oath of the Gatewatch|130|C|{1}{G}|Instant|||Target land you control becomes a 4/4 Elemental creature with haste until end of turn. It's still a land. It must be blocked this turn if able.| +Embodiment of Insight|Oath of the Gatewatch|131|U|{4}{G}|Creature - Elemental|4|4|Vigilance$Land creatures you control have vigilance.$Landfall - Whenever a land enters the battlefield under you control, you may have target land you control become a 3/3 Elemental creature with haste until end of turn. It's still a land.| Gladehart Cavalry|Oath of the Gatewatch|132|R|{5}{G}{G}|Creature - Elf Knight|6|6|When Gladehart Cavalry enters the battlefield, support 6. (Put a +1/+1 counter on each of up to six other target creatures.)$Whenever a creature you control with a +1/+1 counter on it dies, you gain 2 life.| +Harvester Troll|Oath of the Gatewatch|133|U|{3}{G}|Creature - Troll|2|3|When Harvester Troll enters the battlefield, you may sacrifice a creature or land. If you do, put two +1/+1 counters on Harvester Troll.| +Lead by Example|Oath of the Gatewatch|134|C|{1}{G}|Instant|||Support 2. (Put a +1/+1 counter on each of up to two target creatures.)| +Loam Larva|Oath of the Gatewatch|135|C|{1}{G}|Creature - Insect|1|3|When Loam Larva enters the battlefield, you may search your library for a basic land card, reveal it, then shuffle your library and put that card on top of it.| +Natural State|Oath of the Gatewatch|136|C|{G}|Instant|||Destroy target artifact or enchantment with converted mana cost 3 or less.| +Netcaster Spider|Oath of the Gatewatch|137|C|{2}{G}|Creature - Spider|2|3|Reach (This creature can block creatures with flying.)$Whenever Netcaster Spider blocks a creature with flying, Netcaster Spider gets +2/+0 until end of turn.| Nissa, Voice of Zendikar|Oath of the Gatewatch|138|M|{1}{G}{G}|Planeswalker - Nissa|||+1: Put a 0/1 green Plant creature token onto the battlefield.$-2: Put a +1/+1 counter on each creature you control.$-7: You gain X life and draw X cards, where X is the number of lands you control.| +Nissa's Judgment|Oath of the Gatewatch|139|U|{4}{G}|Sorcery|||Support 2. (Put a +1/+1 counter on each of up to two target creatures.)$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.| +Oath of Nissa|Oath of the Gatewatch|140|R|{G}|Legendary Enchantment|||When Oath of Nissa enters the battlefield, look at the top three cards of your library. You may reveal a creature, land, or planeswalker card from among them and put it into your hand. Put the rest on the bottom of your library in any order.$You may spend mana as though it were mana of any color to cast planeswalker spells.| +Pulse of Murasa|Oath of the Gatewatch|141|C|{2}{G}|Instant|||Return target creature or land card from a graveyard to its owner's hand. You gain 6 life.| +Saddleback Lagac|Oath of the Gatewatch|142|C|{3}{G}|Creature - Lizard|3|1|When Saddleback Lagac enters the battlefield, support 2. (Put a +1/+1 counter on each of up to two other target creatures.) +Seed Guardian|Oath of the Gatewatch|143|U|{2}{G}{G}|Creature - Elemental|3|4|Reach$When Seed Guardian dies, put an X/X green Elemental creature token onto the battlefield, where X is the number of creature cards your graveyard.| +Sylvan Advocate|Oath of the Gatewatch|144|R|{1}{G}|Creature - Elf Druid Ally|2|3|Vigilance$As long as you control six or more lands, Sylvan Advocate and land creatures you control get +2/+2.| +Tajuru Pathwarden|Oath of the Gatewatch|145|C|{4}{G}|Creature - Elf Warrior Ally|5|4|Vigilance, trample| +Vines of the Recluse|Oath of the Gatewatch|146|C|{G}|Instant|||Target creature gets +1/+2 and gains reach until end of turn. (A creature with reach can block creatures with flying.)| +Zendikar Resurgent|Oath of the Gatewatch|147|R|{5}{G}{G}|Enchantment|||Whenever you tap a land for mana, add one mana to your mana pool of any type that land produced. (The types of mana are white, blue, black, red, green, and colorless.)$Whenever you cast a creature spell, draw a card.| Flayer Drone|Oath of the Gatewatch|148|U|{1}{B}{R}|Creature - Eldrazi Drone|3|1|Devoid (This card has no color.)$First strike$Whenever another colorless creature enters the battlefield under your control, target opponent loses 1 life.| Mindmelter|Oath of the Gatewatch|149|U|{1}{U}{B}|Creature - Eldrazi Drone|2|2|Devoid (This card has no color.)$Mindmelter can't be blocked.${3}{C}: Target opponent exiles a card from his or her hand. Activate this ability only any time you could cast a sorcery. ({C} represents colorless mana.)| +Void Grafter|Oath of the Gatewatch|150|U|{1}{G}{U}|Creature - Eldrazi Drone|2|4|Devoid (This card has no color.)$Flash (You may cast this spell any time you could cast an instant.)$When Void Grafter enters the battlefield, another target creature you control gain hexproof until end of turn.| Ayli, Eternal Pilgrim|Oath of the Gatewatch|151|R|{W}{B}|Legendary Creature - Kor Cleric|2|3|Deathtouch${1}, Sacrifice another creature: You gain life equal to the sacrificed creature's toughness.${1}{W}{B}, Sacrifice another creature: Exile target nonland permanent. Activate this ability only if you have at least 10 life more than your starting life total.| +Baloth Null|Oath of the Gatewatch|152|U|{4}{B}{G}|Creature - Zombie Beast|4|5|When Baloth Null enters the battlefield, return up to two target creature cards from your graveyard to your hand.| +Cliffhaven Vampire|Oath of the Gatewatch|153|U|{2}{W}{B}|Creature - Vampire Warrior Ally|2|4|Flying$Whenever you gain life, each opponent loses 1 life.| Joraga Auxiliary|Oath of the Gatewatch|154|U|{1}{G}{W}|Creature - Elf Soldier Ally|2|3|{4}{G}{W}: Support 2. (Put a +1/+1 counter on each of up to two other target creatures.)| Jori En, Ruin Diver|Oath of the Gatewatch|155|R|{1}{U}{R}|Legendary Creature - Merfolk Wizard|2|3|Whenever you cast your second spell each turn, draw a card.| Mina and Denn, Wildborn|Oath of the Gatewatch|156|R|{2}{R}{G}|Legendary Creature - Elf Ally|4|4|You may play an additional land on each of your turns.${R}{G}, Return a land you control to its owner's hand: Target creature gains trample until end of turn.| Reflector Mage|Oath of the Gatewatch|157|U|{1}{W}{U}|Creature - Human Wizard|2|3|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.| Relentless Hunter|Oath of the Gatewatch|158|U|{1}{R}{G}|Creature - Human Warrior|3|3|{1}{R}{G}: Relentless Hunter gets +1/+1 and gains trample until end of turn.| -Ashen Moor|Oath of the Gatewatch|168|U||Land|||Ashen Moor enters the battlefield tapped.${T}: Add {B} or {R} to your mana pool.| -Blighted Crossroads|Oath of the Gatewatch|169|R||Land|||{T}: Add {C} to your mana pool. ({C} represents colorless mana.)${T}, Pay 1 life: Add one mana of any color to your mana pool. Spend this mana only to cast spells with devoid.| +Stormchaser Mage|Oath of the Gatewatch|159|U|{U}{R}|Creature - Human Wizard|1|3|Flying, haste$Prowess (Whenever you cast a noncreature spell, this creature gets +1/+1 until end of turn.)| +Weapons Trainer|Oath of the Gatewatch|160|U|{R}{W}|Creature - Human Soldier Ally|3|2|Other creatures you control get +1/+0 as long as you control an Equipment.| +Bone Saw|Oath of the Gatewatch|161|C|{0}|Artifact - Equipment|||Equipped creature gets +1/+0.$Equip {1}| +Captain's Claws|Oath of the Gatewatch|162|R|{2}|Artifact - Equipment|||Equipped creature gets +1/+0.$Whenever equipped creature attacks, put a 1/1 white Kor Ally creature token onto the battlefield tapped and attacking.$Equip {1}| +Chitinous Cloak|Oath of the Gatewatch|163|U|{3}|Artifact - Equipment|||Equipped creature gets +2/+2 and has menace. (It can't be blocked except by two or more creatures.)$Equip {3}| +Hedron Crawler|Oath of the Gatewatch|164|C|{2}|Artifact Creature - Construct|0|1|{T}: Add {C} to your mana pool.| +Seer's Lantern|Oath of the Gatewatch|165|C|{3}|Artifact|||{T}: Add {C} to your mana pool.${2}, {T}: Scry 1.| +Stoneforge Masterwork|Oath of the Gatewatch|166|R|{1}|Artifact - Equipment|||Equipped creature gets +1/+1 for each other creature you control that shares a creature type with it.$Equip {2}| +Strider Harness|Oath of the Gatewatch|167|U|{3}|Artifact - Equipment|||Equipped creature gets +1/+1 and has haste.$Equip {1}| +Cinder Barrens|Oath of the Gatewatch|168|U||Land|||Cinder Barrens enters the battlefield tapped.${T}: Add {B} or {R} to your mana pool.| +Corrupted Crossroads|Oath of the Gatewatch|169|R||Land|||{T}: Add {C} to your mana pool. ({C} represents colorless mana.)${T}, Pay 1 life: Add one mana of any color to your mana pool. Spend this mana only to cast a spell with devoid.| Crumbling Vestige|Oath of the Gatewatch|170|C||Land|||Crumbling Vestige enters the battlefield tapped.$When Crumbling Vestige enters the battlefield, add one mana of any color to your mana pool.${T}: Add {C} to you mana pool. ({C} represents colorless mana.)| Hissing Quagmire|Oath of the Gatewatch|171|R||Land|||Hissing Quagmire enters the battlefield tapped.${T}: Add {B} or {G} to your mana pool.${1}{B}{G}: Hissing Quagmire becomes a 2/2 black and green Elemental creature with deathtouch until end of turn. It's still a land.| Holdout Settlement|Oath of the Gatewatch|172|C||Land|||{T}: Add {C} to your mana pool. ({C} represents colorless mana.)${T}, Tap an untapped creature you control: Add one mana of any color to your mana pool.| -Meandering Stream|Oath of the Gatewatch|173|U||Land|||Meandering Stream enters the battlefield tapped.${T}: Add {W} or {U} to your mana pool.| +Meandering River|Oath of the Gatewatch|173|U||Land|||Meandering River enters the battlefield tapped.${T}: Add {W} or {U} to your mana pool.| Mirrorpool|Oath of the Gatewatch|174|M||Land|||Mirrorpool enters the battlefield tapped.${T}: Add {C} to your mana pool.${2}{C}, {T}, Sacrifice Mirrorpool: Copy target instant or sorcery spell you control. You may choose new targets for the copy.${4}{C}, {T}, Sacrifice Mirrorpool: Put a token onto the battlefield that's a copy of target creature you control.| Needle Spires|Oath of the Gatewatch|175|R||Land|||Needle Spires enters the battlefield tapped.${T}: Add {R} or {W} to your mana pool.${2}{R}{W}: Needle Spires becomes a 2/1 red and white Elemental creature with double strike until end of turn. It's still a land.| Ruins of Oran-Rief|Oath of the Gatewatch|176|R||Land|||Ruins of Oran-Rief enters the battlefield tapped.${T}: Add {C} to your mana pool.${T}: Put a +1/+1 counter on target colorless creature that entered the battlefield this turn.| Sea Gate Wreckage|Oath of the Gatewatch|177|R||Land|||{T}: Add {C} to your mana pool. ({C} represents colorless mana.)${2}{C}, {T}: Draw a card. Activate this ability only if you have no cards in hand.| +Submerged Boneyard|Oath of the Gatewatch|178|U||Land|||Submerged Boneyard enters the battlefield tapped.${T}: Add {U} or {B} to your mana pool.| +Timber Gorge|Oath of the Gatewatch|179|U||Land|||Timber Gorge enters the battlefield tapped.${T}: Add {R} or {G} to your mana pool.| Tranquil Expanse|Oath of the Gatewatch|180|U||Land|||Tranquil Expanse enters the battlefield tapped.${T}: Add {G} or {W} to your mana pool.| Unknown Shores|Oath of the Gatewatch|181|C||Land|||{T}: Add {C} to your mana pool. ({C} represents colorless mana.)${1}, {T}: Add one mana of any color to your mana pool.| +Wandering Fumarole|Oath of the Gatewatch|182|R||Land|||Wandering Fumarole enters the battlefield tapped.${T}: Add {U} or {R} to your mana pool.${2}{U}{R}: Until end of turn, Wandering Fumarole becomes a 1/4 blue and red Elemental creature with "0: Switch this creature's power and toughness until end of turn." It's still a land.| Wastes|Oath of the Gatewatch|183|C||Basic Land|||{T}: Add {C} to your mana pool.| Wastes|Oath of the Gatewatch|184|C||Basic Land|||{T}: Add {C} to your mana pool.| Geist of Saint Traft|Duel Decks: Blessed vs. Cursed|1|M|{1}{W}{U{|Legendary Creature - Spirit Cleric|2|2|Hexproof (This creature can't be the target of spells or abilities your opponents control.)$Whenever Geist of Saint Traft attacks, put a 4/4 white Angel creature token with flying onto the battlefield tapped and attacking. Exile that token at end of combat.| diff --git a/Utils/release/getting_implemented_cards.txt b/Utils/release/getting_implemented_cards.txt index 94755e9e9d8..06cf52b409a 100644 --- a/Utils/release/getting_implemented_cards.txt +++ b/Utils/release/getting_implemented_cards.txt @@ -45,9 +45,18 @@ git log a5d7ca83d7ac5e13805bff58f2838384a97beed6..head --diff-filter=A --name-st since 1.4.5.v0 git log f3019d70fd2ce7c0f2bdaeafafa36ef4d81330c5..head --diff-filter=A --name-status | sed -ne "s/^A[^u]Mage.Sets\/src\/mage\/sets\///p" | sort > added_cards.txt -since 1.4.6.v0 +since 1.4.6v0 git log 207f486afc462490790a3db141ff79e20cfb77c0..head --diff-filter=A --name-status | sed -ne "s/^A[^u]Mage.Sets\/src\/mage\/sets\///p" | sort > added_cards.txt +since 1.4.6v1 +git log 2ad15bbd48d5ae34b0cb5d709895d406b977d104..head --diff-filter=A --name-status | sed -ne "s/^A[^u]Mage.Sets\/src\/mage\/sets\///p" | sort > added_cards.txt + +since 1.4.7v0 +git log 8b37d0b989ba19f0dfccc81db66f5a21cc71fb94..head --diff-filter=A --name-status | sed -ne "s/^A[^u]Mage.Sets\/src\/mage\/sets\///p" | sort > added_cards.txt + +since 1.4.8v0 +git log 804f9e7fc2b481f7f784943409f558a671088372..head --diff-filter=A --name-status | sed -ne "s/^A[^u]Mage.Sets\/src\/mage\/sets\///p" | sort > added_cards.txt + 3. Copy added_cards.txt to trunk\Utils folder 4. Run script: > perl extract_in_wiki_format.perl diff --git a/pom.xml b/pom.xml index fbd77a3c7d7..5dbc875485c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.6 + 1.4.8 pom Mage Root Mage Root POM @@ -83,7 +83,7 @@ - 1.4.6 + 1.4.8 UTF-8