Merge branch 'magefree/master'

This commit is contained in:
Dilnu 2016-09-23 21:11:42 -04:00
commit eaa2d71a37
113 changed files with 2033 additions and 820 deletions

View file

@ -27,7 +27,7 @@ public class MageRoundPane extends JPanel {
private int X_OFFSET = 30; private int X_OFFSET = 30;
private int Y_OFFSET = 30; private int Y_OFFSET = 30;
private final Color defaultBackgroundColor = new Color(255, 255, 255, 200); private final Color defaultBackgroundColor = new Color(141, 130, 112, 200);
private Color backgroundColor = defaultBackgroundColor; private Color backgroundColor = defaultBackgroundColor;
private final int alpha = 0; private final int alpha = 0;
private static Map<ShadowKey, BufferedImage> SHADOW_IMAGE_CACHE; private static Map<ShadowKey, BufferedImage> SHADOW_IMAGE_CACHE;

View file

@ -201,7 +201,16 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnSubmitActionPerformed"/> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnSubmitActionPerformed"/>
</Events> </Events>
</Component> </Component>
<Component class="JComponent" name="cardInfoPane"> <Component class="javax.swing.JButton" name="btnSubmitTimer">
<Properties>
<Property name="text" type="java.lang.String" value="Submit in 1 minute"/>
<Property name="name" type="java.lang.String" value="btnSubmitTimer" noResource="true"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnSubmitTimerActionPerformed"/>
</Events>
</Component>
<Component class="JComponent" name="cardInfoPane">
</Component> </Component>
<Component class="javax.swing.JTextField" name="txtTimeRemaining"> <Component class="javax.swing.JTextField" name="txtTimeRemaining">
</Component> </Component>

View file

@ -27,6 +27,25 @@
*/ */
package mage.client.deckeditor; package mage.client.deckeditor;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import javax.swing.*;
import javax.swing.Timer;
import javax.swing.filechooser.FileFilter;
import mage.cards.Card; import mage.cards.Card;
import mage.cards.Sets; import mage.cards.Sets;
import mage.cards.decks.Deck; import mage.cards.decks.Deck;
@ -39,8 +58,8 @@ import mage.client.SessionHandler;
import mage.client.cards.BigCard; import mage.client.cards.BigCard;
import mage.client.cards.ICardGrid; import mage.client.cards.ICardGrid;
import mage.client.constants.Constants.DeckEditorMode; import mage.client.constants.Constants.DeckEditorMode;
import mage.client.deck.generator.DeckGenerator;
import mage.client.deck.generator.DeckGenerator.DeckGeneratorException; import mage.client.deck.generator.DeckGenerator.DeckGeneratorException;
import mage.client.deck.generator.DeckGenerator;
import mage.client.dialog.AddLandDialog; import mage.client.dialog.AddLandDialog;
import mage.client.plugins.impl.Plugins; import mage.client.plugins.impl.Plugins;
import mage.client.util.Event; import mage.client.util.Event;
@ -52,22 +71,6 @@ import mage.remote.Session;
import mage.view.CardView; import mage.view.CardView;
import mage.view.SimpleCardView; import mage.view.SimpleCardView;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import javax.swing.*;
import javax.swing.Timer;
import javax.swing.filechooser.FileFilter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
/** /**
* *
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
@ -84,6 +87,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
private int timeout; private int timeout;
private Timer countdown; private Timer countdown;
private UpdateDeckTask updateDeckTask; private UpdateDeckTask updateDeckTask;
private int timeToSubmit = -1;
/** /**
* Creates new form DeckEditorPanel * Creates new form DeckEditorPanel
@ -160,6 +164,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
this.txtTimeRemaining.setVisible(true); this.txtTimeRemaining.setVisible(true);
case SIDEBOARDING: case SIDEBOARDING:
this.btnSubmit.setVisible(true); this.btnSubmit.setVisible(true);
this.btnSubmitTimer.setVisible(true);
if (deck != null) { if (deck != null) {
this.cardSelector.loadSideboard(new ArrayList<>(deck.getSideboard()), this.bigCard); this.cardSelector.loadSideboard(new ArrayList<>(deck.getSideboard()), this.bigCard);
} }
@ -187,6 +192,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
case FREE_BUILDING: case FREE_BUILDING:
this.deckArea.setOrientation(/*limitedBuildingOrientation = */false); this.deckArea.setOrientation(/*limitedBuildingOrientation = */false);
this.btnSubmit.setVisible(false); this.btnSubmit.setVisible(false);
this.btnSubmitTimer.setVisible(false);
this.btnAddLand.setVisible(true); this.btnAddLand.setVisible(true);
this.cardSelector.loadCards(this.bigCard); this.cardSelector.loadCards(this.bigCard);
//this.cardTableSelector.loadCards(this.bigCard); //this.cardTableSelector.loadCards(this.bigCard);
@ -484,6 +490,11 @@ public class DeckEditorPanel extends javax.swing.JPanel {
if (s == 60) { if (s == 60) {
AudioManager.playOnCountdown1(); AudioManager.playOnCountdown1();
} }
if (timeToSubmit > 0) {
timeToSubmit --;
btnSubmitTimer.setText("Submit (" + timeToSubmit + ")");
btnSubmitTimer.setToolTipText("Submit your deck in " + timeToSubmit + " seconds!");
}
} }
private void initComponents() { private void initComponents() {
@ -501,6 +512,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
btnExit = new javax.swing.JButton(); btnExit = new javax.swing.JButton();
btnImport = new javax.swing.JButton(); btnImport = new javax.swing.JButton();
btnSubmit = new javax.swing.JButton(); btnSubmit = new javax.swing.JButton();
btnSubmitTimer = new javax.swing.JButton();
btnAddLand = new javax.swing.JButton(); btnAddLand = new javax.swing.JButton();
btnGenDeck = new javax.swing.JButton(); btnGenDeck = new javax.swing.JButton();
txtTimeRemaining = new javax.swing.JTextField(); txtTimeRemaining = new javax.swing.JTextField();
@ -594,6 +606,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
}); });
btnSubmit.setText("Submit"); btnSubmit.setText("Submit");
btnSubmitTimer.setToolTipText("Submit your deck now!");
btnSubmit.setName("btnSubmit"); // NOI18N btnSubmit.setName("btnSubmit"); // NOI18N
btnSubmit.addActionListener(new java.awt.event.ActionListener() { btnSubmit.addActionListener(new java.awt.event.ActionListener() {
@Override @Override
@ -602,6 +615,16 @@ public class DeckEditorPanel extends javax.swing.JPanel {
} }
}); });
btnSubmitTimer.setText("Submit (60s)");
btnSubmitTimer.setToolTipText("Submit your deck in one minute!");
btnSubmitTimer.setName("btnSubmitTimer");
btnSubmitTimer.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnSubmitTimerActionPerformed(evt);
}
});
btnAddLand.setText("Add Land"); btnAddLand.setText("Add Land");
btnAddLand.setName("btnAddLand"); // NOI18N btnAddLand.setName("btnAddLand"); // NOI18N
btnAddLand.addActionListener(new java.awt.event.ActionListener() { btnAddLand.addActionListener(new java.awt.event.ActionListener() {
@ -610,7 +633,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
btnAddLandActionPerformed(evt); btnAddLandActionPerformed(evt);
} }
}); });
btnGenDeck.setText("Generate"); btnGenDeck.setText("Generate");
btnGenDeck.setName("btnGenDeck"); btnGenDeck.setName("btnGenDeck");
btnGenDeck.addActionListener(new java.awt.event.ActionListener() { btnGenDeck.addActionListener(new java.awt.event.ActionListener() {
@ -658,7 +681,9 @@ public class DeckEditorPanel extends javax.swing.JPanel {
.addContainerGap() .addContainerGap()
.addComponent(btnAddLand) .addComponent(btnAddLand)
.addContainerGap() .addContainerGap()
.addComponent(btnSubmit)) .addComponent(btnSubmit)
.addContainerGap()
.addComponent(btnSubmitTimer))
.addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.addComponent(txtTimeRemaining)) .addComponent(txtTimeRemaining))
@ -682,7 +707,8 @@ public class DeckEditorPanel extends javax.swing.JPanel {
.addComponent(btnImport) .addComponent(btnImport)
.addComponent(btnGenDeck) .addComponent(btnGenDeck)
.addComponent(btnAddLand) .addComponent(btnAddLand)
.addComponent(btnSubmit)) .addComponent(btnSubmit)
.addComponent(btnSubmitTimer))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(txtTimeRemaining)) .addComponent(txtTimeRemaining))
@ -847,6 +873,26 @@ public class DeckEditorPanel extends javax.swing.JPanel {
} }
}//GEN-LAST:event_btnSubmitActionPerformed }//GEN-LAST:event_btnSubmitActionPerformed
private void btnSubmitTimerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSubmitTimerActionPerformed
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
timeToSubmit = 60;
this.btnSubmitTimer.setEnabled(false);
ScheduledFuture scheduledFuture = scheduledExecutorService.schedule(new Callable() {
public Object call() throws Exception {
if (updateDeckTask != null) {
updateDeckTask.cancel(true);
}
if (SessionHandler.submitDeck(tableId, deck.getDeckCardLists())) {
removeDeckEditor();
}
return null;
}
}, 60, TimeUnit.SECONDS);
}//GEN-LAST:event_btnSubmitTimerActionPerformed
private void btnAddLandActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAddLandActionPerformed private void btnAddLandActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAddLandActionPerformed
AddLandDialog addLand = new AddLandDialog(); AddLandDialog addLand = new AddLandDialog();
addLand.showDialog(deck, mode); addLand.showDialog(deck, mode);
@ -867,7 +913,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
} }
refreshDeck(); refreshDeck();
} }
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private mage.client.cards.BigCard bigCard; private mage.client.cards.BigCard bigCard;
private javax.swing.JButton btnExit; private javax.swing.JButton btnExit;
@ -882,6 +928,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
private javax.swing.JLabel lblDeckName; private javax.swing.JLabel lblDeckName;
private javax.swing.JTextField txtDeckName; private javax.swing.JTextField txtDeckName;
private javax.swing.JButton btnSubmit; private javax.swing.JButton btnSubmit;
private javax.swing.JButton btnSubmitTimer;
private javax.swing.JButton btnAddLand; private javax.swing.JButton btnAddLand;
private javax.swing.JButton btnGenDeck; private javax.swing.JButton btnGenDeck;
private JComponent cardInfoPane; private JComponent cardInfoPane;

View file

@ -916,33 +916,33 @@ public final class GamePanel extends javax.swing.JPanel {
private void updateSkipButtons(boolean turn, boolean endOfTurn, boolean nextMain, boolean allTurns, boolean stack, boolean endStepBeforeYourStep) { private void updateSkipButtons(boolean turn, boolean endOfTurn, boolean nextMain, boolean allTurns, boolean stack, boolean endStepBeforeYourStep) {
if (turn) { //F4 if (turn) { //F4
btnSkipToNextTurn.setBorder(new LineBorder(Color.red, BORDER_SIZE)); btnSkipToNextTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE));
} else { } else {
btnSkipToNextTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnSkipToNextTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE));
} }
if (endOfTurn) { // F5 if (endOfTurn) { // F5
btnSkipToEndTurn.setBorder(new LineBorder(Color.red, BORDER_SIZE)); btnSkipToEndTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE));
} else { } else {
btnSkipToEndTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnSkipToEndTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE));
} }
if (nextMain) { // F7 if (nextMain) { // F7
btnSkipToNextMain.setBorder(new LineBorder(Color.red, BORDER_SIZE)); btnSkipToNextMain.setBorder(new LineBorder(Color.orange, BORDER_SIZE));
} else { } else {
btnSkipToNextMain.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnSkipToNextMain.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE));
} }
if (stack) { // F8 if (stack) { // F8
btnSkipStack.setBorder(new LineBorder(Color.red, BORDER_SIZE)); btnSkipStack.setBorder(new LineBorder(Color.orange, BORDER_SIZE));
} else { } else {
btnSkipStack.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnSkipStack.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE));
} }
if (allTurns) { // F9 if (allTurns) { // F9
btnSkipToYourTurn.setBorder(new LineBorder(Color.red, BORDER_SIZE)); btnSkipToYourTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE));
} else { } else {
btnSkipToYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnSkipToYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE));
} }
if (endStepBeforeYourStep) { // F11 if (endStepBeforeYourStep) { // F11
btnSkipToEndStepBeforeYourTurn.setBorder(new LineBorder(Color.red, BORDER_SIZE)); btnSkipToEndStepBeforeYourTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE));
} else { } else {
btnSkipToEndStepBeforeYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnSkipToEndStepBeforeYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE));
} }

View file

@ -113,8 +113,8 @@ public class PlayerPanelExt extends javax.swing.JPanel {
private static final Border GREEN_BORDER = new LineBorder(Color.green, 3); private static final Border GREEN_BORDER = new LineBorder(Color.green, 3);
private static final Border RED_BORDER = new LineBorder(Color.red, 2); private static final Border RED_BORDER = new LineBorder(Color.red, 2);
private static final Border EMPTY_BORDER = BorderFactory.createEmptyBorder(0, 0, 0, 0); private static final Border EMPTY_BORDER = BorderFactory.createEmptyBorder(0, 0, 0, 0);
private final Color greenBackgroundColor = new Color(180, 255, 180, 200); private final Color greenBackgroundColor = new Color(206, 192, 174, 200);
private final Color deadBackgroundColor = new Color(200, 180, 180, 200); private final Color deadBackgroundColor = new Color(131, 94, 83, 200);
private int avatarId = -1; private int avatarId = -1;
private String flagName; private String flagName;
@ -430,7 +430,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
// Poison count // Poison count
poisonLabel.setText("0"); poisonLabel.setText("0");
r = new Rectangle(14, 14); r = new Rectangle(18, 18);
poisonLabel.setToolTipText("Poison"); poisonLabel.setToolTipText("Poison");
Image imagePoison = ImageHelper.getImageFromResources("/info/poison.png"); Image imagePoison = ImageHelper.getImageFromResources("/info/poison.png");
BufferedImage resizedPoison = ImageHelper.getResizedImage(BufferedImageBuilder.bufferImage(imagePoison, BufferedImage.TYPE_INT_ARGB), r); BufferedImage resizedPoison = ImageHelper.getResizedImage(BufferedImageBuilder.bufferImage(imagePoison, BufferedImage.TYPE_INT_ARGB), r);
@ -650,8 +650,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
.addGap(9) .addGap(9)
.addGroup(gl_panelBackground.createParallelGroup(Alignment.LEADING) .addGroup(gl_panelBackground.createParallelGroup(Alignment.LEADING)
.addGroup(gl_panelBackground.createSequentialGroup() .addGroup(gl_panelBackground.createSequentialGroup()
.addGap(3) .addComponent(poison, GroupLayout.PREFERRED_SIZE, 18, GroupLayout.PREFERRED_SIZE))
.addComponent(poison, GroupLayout.PREFERRED_SIZE, 14, GroupLayout.PREFERRED_SIZE))
.addGroup(gl_panelBackground.createSequentialGroup() .addGroup(gl_panelBackground.createSequentialGroup()
.addGap(2) .addGap(2)
.addComponent(btnWhiteMana, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE)) .addComponent(btnWhiteMana, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE))
@ -720,7 +719,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
.addComponent(avatar, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 80, Short.MAX_VALUE)) .addComponent(avatar, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 80, Short.MAX_VALUE))
// .addGroup(gl_panelBackground.createSequentialGroup() // .addGroup(gl_panelBackground.createSequentialGroup()
// .addComponent(avatarFlag, GroupLayout.PREFERRED_SIZE, 16, GroupLayout.PREFERRED_SIZE)) // .addComponent(avatarFlag, GroupLayout.PREFERRED_SIZE, 16, GroupLayout.PREFERRED_SIZE))
.addGap(14)) .addGap(8))
.addGroup(gl_panelBackground.createSequentialGroup() .addGroup(gl_panelBackground.createSequentialGroup()
.addGap(6) .addGap(6)
.addComponent(zonesPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(zonesPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
@ -734,7 +733,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
.addPreferredGap(ComponentPlacement.RELATED) .addPreferredGap(ComponentPlacement.RELATED)
.addComponent(btnPlayer) .addComponent(btnPlayer)
.addComponent(timerLabel) .addComponent(timerLabel)
.addGap(1) .addGap(2)
// Life & Hand // Life & Hand
.addGroup(gl_panelBackground.createParallelGroup(Alignment.LEADING) .addGroup(gl_panelBackground.createParallelGroup(Alignment.LEADING)
.addGroup(gl_panelBackground.createSequentialGroup() .addGroup(gl_panelBackground.createSequentialGroup()
@ -749,15 +748,15 @@ public class PlayerPanelExt extends javax.swing.JPanel {
// Poison // Poison
.addGroup(gl_panelBackground.createParallelGroup(Alignment.LEADING) .addGroup(gl_panelBackground.createParallelGroup(Alignment.LEADING)
.addGroup(gl_panelBackground.createSequentialGroup() .addGroup(gl_panelBackground.createSequentialGroup()
.addGap(4) .addGap(2)
.addComponent(poison, GroupLayout.PREFERRED_SIZE, 14, GroupLayout.PREFERRED_SIZE) .addComponent(poison, GroupLayout.PREFERRED_SIZE, 18, GroupLayout.PREFERRED_SIZE)
.addGap(4) .addGap(4)
.addComponent(btnWhiteMana, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE) .addComponent(btnWhiteMana, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE)
.addGap(2) .addGap(2)
.addComponent(btnBlueMana, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE) .addComponent(btnBlueMana, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE)
.addGap(2) .addGap(2)
.addComponent(btnBlackMana, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE) .addComponent(btnBlackMana, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE)
.addGap(5) .addGap(3)
.addComponent(grave, GroupLayout.PREFERRED_SIZE, 21, GroupLayout.PREFERRED_SIZE) .addComponent(grave, GroupLayout.PREFERRED_SIZE, 21, GroupLayout.PREFERRED_SIZE)
) )
.addGroup(gl_panelBackground.createSequentialGroup() .addGroup(gl_panelBackground.createSequentialGroup()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 926 B

After

Width:  |  Height:  |  Size: 20 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 721 B

After

Width:  |  Height:  |  Size: 21 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 470 B

After

Width:  |  Height:  |  Size: 21 KiB

Before After
Before After

View file

@ -41,7 +41,7 @@ public class MageVersion implements Serializable, Comparable<MageVersion> {
public final static int MAGE_VERSION_MAJOR = 1; public final static int MAGE_VERSION_MAJOR = 1;
public final static int MAGE_VERSION_MINOR = 4; public final static int MAGE_VERSION_MINOR = 4;
public final static int MAGE_VERSION_PATCH = 15; public final static int MAGE_VERSION_PATCH = 15;
public final static String MAGE_VERSION_MINOR_PATCH = "v2"; public final static String MAGE_VERSION_MINOR_PATCH = "v4";
public final static String MAGE_VERSION_INFO = ""; public final static String MAGE_VERSION_INFO = "";
private final int major; private final int major;

View file

@ -30,7 +30,6 @@ package mage.view;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.ObjectColor; import mage.ObjectColor;
import mage.abilities.Mode; import mage.abilities.Mode;
@ -55,7 +54,6 @@ import mage.game.stack.Spell;
import mage.game.stack.StackAbility; import mage.game.stack.StackAbility;
import mage.target.Target; import mage.target.Target;
import mage.target.Targets; import mage.target.Targets;
import org.apache.log4j.Logger;
/** /**
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
@ -81,7 +79,7 @@ public class CardView extends SimpleCardView {
protected List<String> manaCost; protected List<String> manaCost;
protected int convertedManaCost; protected int convertedManaCost;
protected Rarity rarity; protected Rarity rarity;
protected MageObjectType mageObjectType = MageObjectType.NULL; protected MageObjectType mageObjectType = MageObjectType.NULL;
protected boolean isAbility; protected boolean isAbility;
@ -323,7 +321,8 @@ public class CardView extends SimpleCardView {
this.mageObjectType = MageObjectType.SPELL; this.mageObjectType = MageObjectType.SPELL;
Spell spell = (Spell) card; Spell spell = (Spell) card;
for (SpellAbility spellAbility : spell.getSpellAbilities()) { for (SpellAbility spellAbility : spell.getSpellAbilities()) {
for (Mode mode : spellAbility.getModes().getSelectedModes()) { for (UUID modeId : spellAbility.getModes().getSelectedModes()) {
Mode mode = spellAbility.getModes().get(modeId);
if (mode.getTargets().size() > 0) { if (mode.getTargets().size() > 0) {
setTargets(spellAbility.getTargets()); setTargets(spellAbility.getTargets());
} }
@ -331,18 +330,19 @@ public class CardView extends SimpleCardView {
} }
// show for modal spell, which mode was choosen // show for modal spell, which mode was choosen
if (spell.getSpellAbility().isModal()) { if (spell.getSpellAbility().isModal()) {
for (Mode mode : spell.getSpellAbility().getModes().getSelectedModes()) { for (UUID modeId : spell.getSpellAbility().getModes().getSelectedModes()) {
Mode mode = spell.getSpellAbility().getModes().get(modeId);
this.rules.add("<span color='green'><i>Chosen mode: " + mode.getEffects().getText(mode) + "</i></span>"); this.rules.add("<span color='green'><i>Chosen mode: " + mode.getEffects().getText(mode) + "</i></span>");
} }
} }
} }
// Frame color // Frame color
this.frameColor = card.getFrameColor(game); this.frameColor = card.getFrameColor(game);
// Frame style // Frame style
this.frameStyle = card.getFrameStyle(); this.frameStyle = card.getFrameStyle();
// Get starting loyalty // Get starting loyalty
this.startingLoyalty = "" + card.getStartingLoyalty(); this.startingLoyalty = "" + card.getStartingLoyalty();
} }
@ -355,7 +355,7 @@ public class CardView extends SimpleCardView {
this.mageObjectType = MageObjectType.PERMANENT; this.mageObjectType = MageObjectType.PERMANENT;
this.power = Integer.toString(object.getPower().getValue()); this.power = Integer.toString(object.getPower().getValue());
this.toughness = Integer.toString(object.getToughness().getValue()); this.toughness = Integer.toString(object.getToughness().getValue());
this.loyalty = Integer.toString(((Permanent) object).getCounters((Game)null).getCount(CounterType.LOYALTY)); this.loyalty = Integer.toString(((Permanent) object).getCounters((Game) null).getCount(CounterType.LOYALTY));
} else { } else {
this.power = object.getPower().toString(); this.power = object.getPower().toString();
this.toughness = object.getToughness().toString(); this.toughness = object.getToughness().toString();
@ -488,7 +488,7 @@ public class CardView extends SimpleCardView {
this.rarity = Rarity.NA; this.rarity = Rarity.NA;
this.type = token.getTokenType(); this.type = token.getTokenType();
this.tokenDescriptor = token.getTokenDescriptor(); this.tokenDescriptor = token.getTokenDescriptor();
this.tokenSetCode = token.getOriginalExpansionSetCode(); this.tokenSetCode = token.getOriginalExpansionSetCode();
} }
protected final void setTargets(Targets targets) { protected final void setTargets(Targets targets) {
@ -547,7 +547,7 @@ public class CardView extends SimpleCardView {
public String getLoyalty() { public String getLoyalty() {
return loyalty; return loyalty;
} }
public String getStartingLoyalty() { public String getStartingLoyalty() {
return startingLoyalty; return startingLoyalty;
} }
@ -567,7 +567,7 @@ public class CardView extends SimpleCardView {
public ObjectColor getColor() { public ObjectColor getColor() {
return color; return color;
} }
public ObjectColor getFrameColor() { public ObjectColor getFrameColor() {
return frameColor; return frameColor;
} }
@ -807,4 +807,3 @@ public class CardView extends SimpleCardView {
} }
} }

View file

@ -99,7 +99,8 @@ public class StackAbilityView extends CardView {
private void updateTargets(Game game, StackAbility ability) { private void updateTargets(Game game, StackAbility ability) {
List<String> names = new ArrayList<>(); List<String> names = new ArrayList<>();
for (Mode mode : ability.getModes().getSelectedModes()) { for (UUID modeId : ability.getModes().getSelectedModes()) {
Mode mode = ability.getModes().get(modeId);
if (mode.getTargets().size() > 0) { if (mode.getTargets().size() > 0) {
setTargets(mode.getTargets()); setTargets(mode.getTargets());
} else { } else {
@ -132,7 +133,8 @@ public class StackAbilityView extends CardView {
// show for modal ability, which mode was choosen // show for modal ability, which mode was choosen
if (ability.isModal()) { if (ability.isModal()) {
Modes modes = ability.getModes(); Modes modes = ability.getModes();
for (Mode mode : modes.getSelectedModes()) { for (UUID modeId : modes.getSelectedModes()) {
Mode mode = modes.get(modeId);
this.rules.add("<span color='green'><i>Chosen mode: " + mode.getEffects().getText(mode) + "</i></span>"); this.rules.add("<span color='green'><i>Chosen mode: " + mode.getEffects().getText(mode) + "</i></span>");
} }
} }

View file

@ -1516,7 +1516,8 @@ public class ComputerPlayer extends PlayerImpl implements Player {
//TODO: improve this; //TODO: improve this;
AvailableMode: AvailableMode:
for (Mode mode : modes.getAvailableModes(source, game)) { for (Mode mode : modes.getAvailableModes(source, game)) {
for (Mode selectedMode : modes.getSelectedModes()) { for (UUID selectedModeId : modes.getSelectedModes()) {
Mode selectedMode = modes.get(selectedModeId);
if (selectedMode.getId().equals(mode.getId())) { if (selectedMode.getId().equals(mode.getId())) {
continue AvailableMode; continue AvailableMode;
} }

View file

@ -730,11 +730,14 @@ public class HumanPlayer extends PlayerImpl {
} }
private boolean checkPassStep(Game game) { private boolean checkPassStep(Game game) {
if (playerId.equals(game.getActivePlayerId())) { if (game.getStep() != null) {
return !this.getUserData().getUserSkipPrioritySteps().getYourTurn().isPhaseStepSet(game.getStep().getType()); if (playerId.equals(game.getActivePlayerId())) {
} else { return !this.getUserData().getUserSkipPrioritySteps().getYourTurn().isPhaseStepSet(game.getStep().getType());
return !this.getUserData().getUserSkipPrioritySteps().getOpponentTurn().isPhaseStepSet(game.getStep().getType()); } else {
return !this.getUserData().getUserSkipPrioritySteps().getOpponentTurn().isPhaseStepSet(game.getStep().getType());
}
} }
return true;
} }
@Override @Override
@ -1323,7 +1326,8 @@ public class HumanPlayer extends PlayerImpl {
AvailableModes: AvailableModes:
for (Mode mode : modes.getAvailableModes(source, game)) { for (Mode mode : modes.getAvailableModes(source, game)) {
int timesSelected = 0; int timesSelected = 0;
for (Mode selectedMode : modes.getSelectedModes()) { for (UUID selectedModeId : modes.getSelectedModes()) {
Mode selectedMode = modes.get(selectedModeId);
if (mode.getId().equals(selectedMode.getId())) { if (mode.getId().equals(selectedMode.getId())) {
if (modes.isEachModeMoreThanOnce()) { if (modes.isEachModeMoreThanOnce()) {
timesSelected++; timesSelected++;

View file

@ -102,6 +102,7 @@
<draftCube name="MTGO Legacy Cube March 2015" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeMarch2015"/> <draftCube name="MTGO Legacy Cube March 2015" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeMarch2015"/>
<draftCube name="MTGO Legacy Cube September 2015" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeSeptember2015"/> <draftCube name="MTGO Legacy Cube September 2015" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeSeptember2015"/>
<draftCube name="MTGO Legacy Cube January 2016" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeJanuary2016"/> <draftCube name="MTGO Legacy Cube January 2016" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeJanuary2016"/>
<draftCube name="MTGO Legacy Cube September 2016" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeSeptember2016"/>
<draftCube name="MTGO Legendary Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCube"/> <draftCube name="MTGO Legendary Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCube"/>
<draftCube name="MTGO Legendary Cube April 2016" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCubeApril2016"/> <draftCube name="MTGO Legendary Cube April 2016" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCubeApril2016"/>
<draftCube name="MTGO Vintage Cube 2013" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCube2013"/> <draftCube name="MTGO Vintage Cube 2013" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCube2013"/>

View file

@ -99,6 +99,7 @@
<draftCube name="MTGO Legacy Cube March 2015" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeMarch2015"/> <draftCube name="MTGO Legacy Cube March 2015" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeMarch2015"/>
<draftCube name="MTGO Legacy Cube September 2015" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeSeptember2015"/> <draftCube name="MTGO Legacy Cube September 2015" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeSeptember2015"/>
<draftCube name="MTGO Legacy Cube January 2016" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeJanuary2016"/> <draftCube name="MTGO Legacy Cube January 2016" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeJanuary2016"/>
<draftCube name="MTGO Legacy Cube September 2016" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeSeptember2016"/>
<draftCube name="MTGO Legendary Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCube"/> <draftCube name="MTGO Legendary Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCube"/>
<draftCube name="MTGO Legendary Cube April 2016" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCubeApril2016"/> <draftCube name="MTGO Legendary Cube April 2016" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCubeApril2016"/>
<draftCube name="MTGO Vintage Cube 2013" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCube2013"/> <draftCube name="MTGO Vintage Cube 2013" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCube2013"/>

View file

@ -567,7 +567,7 @@ public class TableController {
String creator = null; String creator = null;
StringBuilder opponent = new StringBuilder(); StringBuilder opponent = new StringBuilder();
for (Entry<UUID, UUID> entry : userPlayerMap.entrySet()) { // no AI players for (Entry<UUID, UUID> entry : userPlayerMap.entrySet()) { // no AI players
if (!match.getPlayer(entry.getValue()).hasQuit()) { if (match.getPlayer(entry.getValue()) != null && !match.getPlayer(entry.getValue()).hasQuit()) {
User user = UserManager.getInstance().getUser(entry.getKey()); User user = UserManager.getInstance().getUser(entry.getKey());
if (user != null) { if (user != null) {
user.ccGameStarted(match.getGame().getId(), entry.getValue()); user.ccGameStarted(match.getGame().getId(), entry.getValue());

View file

@ -104,7 +104,8 @@ class ZadaHedronGrinderTriggeredAbility extends TriggeredAbilityImpl {
if (isControlledInstantOrSorcery(spell)) { if (isControlledInstantOrSorcery(spell)) {
boolean targetsSource = false; boolean targetsSource = false;
for (Ability ability : spell.getSpellAbilities()) { for (Ability ability : spell.getSpellAbilities()) {
for (Mode mode : ability.getModes().getSelectedModes()) { for (UUID modeId : ability.getModes().getSelectedModes()) {
Mode mode = ability.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
if (!target.isNotTarget()) { if (!target.isNotTarget()) {
for (UUID targetId : target.getTargets()) { for (UUID targetId : target.getTargets()) {
@ -167,7 +168,8 @@ class ZadaHedronGrinderEffect extends OneShotEffect {
Target usedTarget = null; Target usedTarget = null;
setUsedTarget: setUsedTarget:
for (Ability ability : spell.getSpellAbilities()) { for (Ability ability : spell.getSpellAbilities()) {
for (Mode mode : ability.getModes().getSelectedModes()) { for (UUID modeId : ability.getModes().getSelectedModes()) {
Mode mode = ability.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
if (!target.isNotTarget() && target.getFirstTarget().equals(source.getSourceId())) { if (!target.isNotTarget() && target.getFirstTarget().equals(source.getSourceId())) {
usedTarget = target.copy(); usedTarget = target.copy();
@ -185,7 +187,8 @@ class ZadaHedronGrinderEffect extends OneShotEffect {
Spell copy = spell.copySpell(source.getControllerId()); Spell copy = spell.copySpell(source.getControllerId());
game.getStack().push(copy); game.getStack().push(copy);
setTarget: setTarget:
for (Mode mode : copy.getSpellAbility().getModes().getSelectedModes()) { for (UUID modeId : copy.getSpellAbility().getModes().getSelectedModes()) {
Mode mode = copy.getSpellAbility().getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
if (target.getClass().equals(usedTarget.getClass())) { if (target.getClass().equals(usedTarget.getClass())) {
target.clearChosen(); // For targets with Max > 1 we need to clear before the text is comapred target.clearChosen(); // For targets with Max > 1 we need to clear before the text is comapred

View file

@ -28,8 +28,6 @@
package mage.sets.championsofkamigawa; package mage.sets.championsofkamigawa;
import java.util.UUID; import java.util.UUID;
import mage.constants.*;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.EntersBattlefieldAbility;
@ -40,15 +38,17 @@ import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.common.RemoveCountersSourceCost; import mage.abilities.costs.common.RemoveCountersSourceCost;
import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.PutOntoBattlefieldTargetEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.IndestructibleAbility; import mage.abilities.keyword.IndestructibleAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardsImpl;
import mage.constants.*;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard;
import mage.filter.predicate.mageobject.CardTypePredicate; import mage.game.Game;
import mage.filter.predicate.other.OwnerPredicate; import mage.players.Player;
import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInHand;
import mage.watchers.common.CastFromHandWatcher; import mage.watchers.common.CastFromHandWatcher;
@ -57,12 +57,6 @@ import mage.watchers.common.CastFromHandWatcher;
*/ */
public class MyojinOfLifesWeb extends CardImpl { public class MyojinOfLifesWeb extends CardImpl {
private static final FilterCard filter = new FilterCard("any number of creature cards from your hand");
static {
filter.add(new CardTypePredicate(CardType.CREATURE));
filter.add(new OwnerPredicate(TargetController.YOU));
}
public MyojinOfLifesWeb(UUID ownerId) { public MyojinOfLifesWeb(UUID ownerId) {
super(ownerId, 229, "Myojin of Life's Web", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{6}{G}{G}{G}"); super(ownerId, 229, "Myojin of Life's Web", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{6}{G}{G}{G}");
this.expansionSetCode = "CHK"; this.expansionSetCode = "CHK";
@ -79,10 +73,10 @@ public class MyojinOfLifesWeb extends CardImpl {
// Myojin of Life's Web is indestructible as long as it has a divinity counter on it. // Myojin of Life's Web is indestructible as long as it has a divinity counter on it.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD,
new ConditionalContinuousEffect(new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield), new ConditionalContinuousEffect(new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield),
new SourceHasCounterCondition(CounterType.DIVINITY), "{this} is indestructible as long as it has a divinity counter on it"))); new SourceHasCounterCondition(CounterType.DIVINITY), "{this} is indestructible as long as it has a divinity counter on it")));
// Remove a divinity counter from Myojin of Life's Web: Put any number of creature cards from your hand onto the battlefield. // Remove a divinity counter from Myojin of Life's Web: Put any number of creature cards from your hand onto the battlefield.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutOntoBattlefieldTargetEffect(false), new RemoveCountersSourceCost(CounterType.DIVINITY.createInstance())); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MyojinOfLifesWebPutCreatureOnBattlefieldEffect(), new RemoveCountersSourceCost(CounterType.DIVINITY.createInstance()));
ability.addTarget(new TargetCardInHand(0, Integer.MAX_VALUE, filter));
this.addAbility(ability); this.addAbility(ability);
} }
@ -95,3 +89,35 @@ public class MyojinOfLifesWeb extends CardImpl {
return new MyojinOfLifesWeb(this); return new MyojinOfLifesWeb(this);
} }
} }
class MyojinOfLifesWebPutCreatureOnBattlefieldEffect extends OneShotEffect {
public MyojinOfLifesWebPutCreatureOnBattlefieldEffect() {
super(Outcome.PutCreatureInPlay);
this.staticText = "Put any number of creature cards from your hand onto the battlefield";
}
public MyojinOfLifesWebPutCreatureOnBattlefieldEffect(final MyojinOfLifesWebPutCreatureOnBattlefieldEffect effect) {
super(effect);
}
@Override
public MyojinOfLifesWebPutCreatureOnBattlefieldEffect copy() {
return new MyojinOfLifesWebPutCreatureOnBattlefieldEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
TargetCardInHand target = new TargetCardInHand(0, Integer.MAX_VALUE, new FilterCreatureCard("creature cards from your hand to put onto the battlefield"));
if (controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) {
return controller.moveCards(new CardsImpl(target.getTargets()).getCards(game),
Zone.BATTLEFIELD, source, game, false, false, false, null);
}
return false;
}
}

View file

@ -70,7 +70,7 @@ public class GoblinArtisans extends CardImpl {
// {tap}: Flip a coin. If you win the flip, draw a card. If you lose the flip, counter target artifact spell you control that isn't the target of an ability from another creature named Goblin Artisans. // {tap}: Flip a coin. If you win the flip, draw a card. If you lose the flip, counter target artifact spell you control that isn't the target of an ability from another creature named Goblin Artisans.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GoblinArtisansEffect(), new TapSourceCost())); this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GoblinArtisansEffect(), new TapSourceCost()));
} }
public GoblinArtisans(final GoblinArtisans card) { public GoblinArtisans(final GoblinArtisans card) {
@ -83,15 +83,14 @@ public class GoblinArtisans extends CardImpl {
} }
} }
class GoblinArtisansEffect extends OneShotEffect { class GoblinArtisansEffect extends OneShotEffect {
private static final FilterPermanent filter = new FilterPermanent("permanent named Goblin Artisans"); private static final FilterPermanent filter = new FilterPermanent("permanent named Goblin Artisans");
static { static {
filter.add(new NamePredicate("Goblin Artisans")); filter.add(new NamePredicate("Goblin Artisans"));
} }
public GoblinArtisansEffect() { public GoblinArtisansEffect() {
super(Outcome.Damage); super(Outcome.Damage);
staticText = "Flip a coin. If you win the flip, draw a card. If you lose the flip, counter target artifact spell you control that isn't the target of an ability from another creature named Goblin Artisans."; staticText = "Flip a coin. If you win the flip, draw a card. If you lose the flip, counter target artifact spell you control that isn't the target of an ability from another creature named Goblin Artisans.";
@ -109,37 +108,38 @@ class GoblinArtisansEffect extends OneShotEffect {
controller.drawCards(1, game); controller.drawCards(1, game);
} else { } else {
List<Permanent> artifacts = game.getBattlefield().getActivePermanents(new FilterControlledArtifactPermanent(), source.getControllerId(), game); List<Permanent> artifacts = game.getBattlefield().getActivePermanents(new FilterControlledArtifactPermanent(), source.getControllerId(), game);
if (artifacts.isEmpty()){//Don't even bother if there is no artifact to 'counter'/sacrifice if (artifacts.isEmpty()) {//Don't even bother if there is no artifact to 'counter'/sacrifice
return true; return true;
} }
filter.add(Predicates.not(new PermanentIdPredicate(source.getSourceId()))); filter.add(Predicates.not(new PermanentIdPredicate(source.getSourceId())));
//removed the activating instance of Artisans, btw, wasn't that filter declared as static final? How come I can do this here? :) //removed the activating instance of Artisans, btw, wasn't that filter declared as static final? How come I can do this here? :)
List<Permanent> list = game.getBattlefield().getAllActivePermanents(filter, game); List<Permanent> list = game.getBattlefield().getAllActivePermanents(filter, game);
for (Permanent perm : list){ // should I limit below for a particular kind of ability? Going for the most general, it's unlikely there'll be any other artisans anyway, so not concerned about efficiency :p for (Permanent perm : list) { // should I limit below for a particular kind of ability? Going for the most general, it's unlikely there'll be any other artisans anyway, so not concerned about efficiency :p
for (Ability abil : perm.getAbilities(game)){//below is copied from TargetsPermanentPredicate, but why only "selectedModes"? Shouldnt be more general as well? for (Ability abil : perm.getAbilities(game)) {//below is copied from TargetsPermanentPredicate, but why only "selectedModes"? Shouldnt be more general as well?
for (Mode mode : abil.getModes().getSelectedModes()){ for (UUID modeId : abil.getModes().getSelectedModes()) {
Mode mode = abil.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetId : target.getTargets()) { for (UUID targetId : target.getTargets()) {
artifacts.remove(game.getPermanentOrLKIBattlefield(targetId)); artifacts.remove(game.getPermanentOrLKIBattlefield(targetId));
}// we could }// we could
}// remove this }// remove this
}//closing bracers }//closing bracers
}// pyramid, if it's bothering anyone }// pyramid, if it's bothering anyone
} //they are all one-liners after all :) } //they are all one-liners after all :)
if (!artifacts.isEmpty()){ if (!artifacts.isEmpty()) {
Cards cards=new CardsImpl(); Cards cards = new CardsImpl();
for (Permanent perm : artifacts){ for (Permanent perm : artifacts) {
cards.add(perm.getId()); cards.add(perm.getId());
} }
TargetCard target = new TargetCard(Zone.BATTLEFIELD, new FilterCard()); TargetCard target = new TargetCard(Zone.BATTLEFIELD, new FilterCard());
controller.choose(Outcome.Sacrifice, cards, target, game); controller.choose(Outcome.Sacrifice, cards, target, game);
game.getPermanent(target.getFirstTarget()).sacrifice(source.getSourceId(), game); game.getPermanent(target.getFirstTarget()).sacrifice(source.getSourceId(), game);
} }
return true; return true;
}
} }
}
return false; return false;
} }

View file

@ -120,7 +120,7 @@ class JelevaNephaliasScourgeEffect extends OneShotEffect {
for (int i = 0; i < cardsToExile; i++) { for (int i = 0; i < cardsToExile; i++) {
Card card = player.getLibrary().removeFromTop(game); Card card = player.getLibrary().removeFromTop(game);
if (card != null) { if (card != null) {
card.moveToExile(CardUtil.getCardExileZoneId(game, source), sourceCard.getName(), source.getSourceId(), game); card.moveToExile(CardUtil.getCardExileZoneId(game, source), sourceCard.getIdName(), source.getSourceId(), game);
} }
} }
} }

View file

@ -27,7 +27,6 @@
*/ */
package mage.sets.conspiracytakethecrown; package mage.sets.conspiracytakethecrown;
import java.util.HashSet;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
@ -41,8 +40,7 @@ import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.watchers.Watcher; import mage.watchers.common.CardsAmountDrawnThisTurnWatcher;
/** /**
* *
@ -60,7 +58,7 @@ public class LeovoldEmissaryOfTrest extends CardImpl {
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
// Each opponent can't draw more than one card each turn. (Based on SpiritOfTheLabyrinth) // Each opponent can't draw more than one card each turn. (Based on SpiritOfTheLabyrinth)
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new LeovoldEmissaryOfTrestEffect()), new LeovoldEmissaryOfTrestWatcher()); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new LeovoldEmissaryOfTrestEffect()), new CardsAmountDrawnThisTurnWatcher());
// Whenever you or a permanent you control becomes the target of a spell or ability an opponent controls, you may draw a card. // Whenever you or a permanent you control becomes the target of a spell or ability an opponent controls, you may draw a card.
this.addAbility(new LeovoldEmissaryOfTrestTriggeredAbility()); this.addAbility(new LeovoldEmissaryOfTrestTriggeredAbility());
@ -76,47 +74,6 @@ public class LeovoldEmissaryOfTrest extends CardImpl {
} }
} }
class LeovoldEmissaryOfTrestWatcher extends Watcher {
private final HashSet<UUID> playersThatDrewCard;
public LeovoldEmissaryOfTrestWatcher() {
super("DrewCard", WatcherScope.GAME);
this.playersThatDrewCard = new HashSet<>();
}
public LeovoldEmissaryOfTrestWatcher(final LeovoldEmissaryOfTrestWatcher watcher) {
super(watcher);
this.playersThatDrewCard = new HashSet<>();
playersThatDrewCard.addAll(watcher.playersThatDrewCard);
}
@Override
public LeovoldEmissaryOfTrestWatcher copy() {
return new LeovoldEmissaryOfTrestWatcher(this);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.DREW_CARD ) {
playersThatDrewCard.add(event.getPlayerId());
}
}
@Override
public void reset() {
super.reset();
playersThatDrewCard.clear();
}
public boolean hasPlayerDrewCardThisTurn(UUID playerId) {
return playersThatDrewCard.contains(playerId);
}
}
class LeovoldEmissaryOfTrestEffect extends ContinuousRuleModifyingEffectImpl { class LeovoldEmissaryOfTrestEffect extends ContinuousRuleModifyingEffectImpl {
public LeovoldEmissaryOfTrestEffect() { public LeovoldEmissaryOfTrestEffect() {
@ -133,11 +90,6 @@ class LeovoldEmissaryOfTrestEffect extends ContinuousRuleModifyingEffectImpl {
return new LeovoldEmissaryOfTrestEffect(this); return new LeovoldEmissaryOfTrestEffect(this);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public boolean checksEventType(GameEvent event, Game game) { public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DRAW_CARD; return event.getType() == GameEvent.EventType.DRAW_CARD;
@ -145,10 +97,9 @@ class LeovoldEmissaryOfTrestEffect extends ContinuousRuleModifyingEffectImpl {
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
LeovoldEmissaryOfTrestWatcher watcher = (LeovoldEmissaryOfTrestWatcher) game.getState().getWatchers().get("DrewCard"); CardsAmountDrawnThisTurnWatcher watcher = (CardsAmountDrawnThisTurnWatcher) game.getState().getWatchers().get(CardsAmountDrawnThisTurnWatcher.BASIC_KEY);
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
return watcher != null && controller != null && watcher.hasPlayerDrewCardThisTurn(event.getPlayerId()) return watcher != null && controller != null && watcher.getAmountCardsDrawn(event.getPlayerId()) >= 1
&& game.isOpponent(controller, event.getPlayerId()); && game.isOpponent(controller, event.getPlayerId());
} }
@ -178,9 +129,10 @@ class LeovoldEmissaryOfTrestTriggeredAbility extends TriggeredAbilityImpl {
public boolean checkTrigger(GameEvent event, Game game) { public boolean checkTrigger(GameEvent event, Game game) {
Player controller = game.getPlayer(this.getControllerId()); Player controller = game.getPlayer(this.getControllerId());
Player targetter = game.getPlayer(event.getPlayerId()); Player targetter = game.getPlayer(event.getPlayerId());
if (controller != null && targetter != null && !controller.getId().equals(targetter.getId())) { if (controller != null && targetter != null
&& game.isOpponent(controller, targetter.getId())) {
if (event.getTargetId().equals(controller.getId())) { if (event.getTargetId().equals(controller.getId())) {
return true; return true; // Player was targeted
} }
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId()); Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId());
if (permanent != null && this.getControllerId().equals(permanent.getControllerId())) { if (permanent != null && this.getControllerId().equals(permanent.getControllerId())) {
@ -192,6 +144,6 @@ class LeovoldEmissaryOfTrestTriggeredAbility extends TriggeredAbilityImpl {
@Override @Override
public String getRule() { public String getRule() {
return "Whenever you or a permanent you control becomes the target of a spell or ability an opponent controls, you may draw a card."; return "Whenever you or a permanent you control becomes the target of a spell or ability an opponent controls, " + super.getRule();
} }
} }

View file

@ -43,6 +43,7 @@ import mage.choices.ChoiceImpl;
import mage.constants.*; import mage.constants.*;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.players.Player; import mage.players.Player;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
@ -95,6 +96,12 @@ class ChooseNumberEffect extends OneShotEffect {
int numberChoice = controller.announceXMana(0, Integer.MAX_VALUE, "Choose a number. Noncreature spells with the chosen converted mana cost can't be cast", game, source); int numberChoice = controller.announceXMana(0, Integer.MAX_VALUE, "Choose a number. Noncreature spells with the chosen converted mana cost can't be cast", game, source);
game.getState().setValue(source.getSourceId().toString(), numberChoice); game.getState().setValue(source.getSourceId().toString(), numberChoice);
Permanent permanent = game.getPermanentEntering(source.getSourceId());
permanent.addInfo("chosen players", "<font color = 'blue'>Chosen Number: "+ numberChoice +"</font>", game);
game.informPlayers(permanent.getLogName() + ", chosen number: "+numberChoice);
return true; return true;
} }

View file

@ -33,13 +33,13 @@ import mage.Mana;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.mana.DynamicManaAbility; import mage.abilities.mana.DynamicManaAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.*; import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayer;
@ -48,7 +48,6 @@ import mage.filter.predicate.permanent.AnotherPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
/** /**
* *
@ -56,8 +55,8 @@ import mage.target.targetpointer.FixedTarget;
*/ */
public class SelvalaHeartOfTheWilds extends CardImpl { public class SelvalaHeartOfTheWilds extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature");
static { static {
filter.add(new AnotherPredicate()); filter.add(new AnotherPredicate());
filter.add(new GreatestPowerPredicate()); filter.add(new GreatestPowerPredicate());
@ -75,12 +74,14 @@ public class SelvalaHeartOfTheWilds extends CardImpl {
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
// Whenever another creature enters the battlefield, its controller may draw a card if its power is greater than each other creature's power. // Whenever another creature enters the battlefield, its controller may draw a card if its power is greater than each other creature's power.
this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new SelvalaHeartOfTheWildsEffect(), filter, false, SetTargetPointer.PERMANENT, rule)); this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new SelvalaHeartOfTheWildsEffect(), filter, false, SetTargetPointer.PERMANENT, rule));
// {G}, {T}: Add X mana in any combination of colors to your mana pool, where X is the greatest power among creatures you control. // {G}, {T}: Add X mana in any combination of colors to your mana pool, where X is the greatest power among creatures you control.
this.addAbility(new DynamicManaAbility(new Mana(0,0,0,0,0,0,1, 0), new GreatestPowerYouControlValue(), new TapSourceCost(), Ability ability = new DynamicManaAbility(new Mana(0, 0, 0, 0, 0, 0, 1, 0), new GreatestPowerYouControlValue(), new ManaCostsImpl<>("{G}"),
"Add X mana in any combination of colors to your mana pool, where X is the number of creatures with defender you control.")); "Add X mana in any combination of colors to your mana pool, where X is the greatest power among creatures you control.");
ability.addCost(new TapSourceCost());
this.addAbility(ability);
} }
public SelvalaHeartOfTheWilds(final SelvalaHeartOfTheWilds card) { public SelvalaHeartOfTheWilds(final SelvalaHeartOfTheWilds card) {
@ -112,12 +113,12 @@ class SelvalaHeartOfTheWildsEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source));
if(permanent == null){ if (permanent == null) {
permanent = (Permanent)game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.BATTLEFIELD); permanent = (Permanent) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.BATTLEFIELD);
} }
if (permanent != null) { if (permanent != null) {
Player cardowner = game.getPlayer(permanent.getControllerId()); Player cardowner = game.getPlayer(permanent.getControllerId());
if(cardowner.chooseUse(Outcome.DrawCard, "Would you like to draw a card?", source, game)){ if (cardowner.chooseUse(Outcome.DrawCard, "Would you like to draw a card?", source, game)) {
cardowner.drawCards(1, game); cardowner.drawCards(1, game);
} }
} }
@ -125,18 +126,17 @@ class SelvalaHeartOfTheWildsEffect extends OneShotEffect {
} }
} }
class GreatestPowerPredicate implements ObjectSourcePlayerPredicate<ObjectSourcePlayer<Permanent>> { class GreatestPowerPredicate implements ObjectSourcePlayerPredicate<ObjectSourcePlayer<Permanent>> {
@Override @Override
public boolean apply(ObjectSourcePlayer<Permanent> input, Game game) { public boolean apply(ObjectSourcePlayer<Permanent> input, Game game) {
int pow = input.getObject().getPower().getValue(); int pow = input.getObject().getPower().getValue();
for (UUID id :game.getPlayerList()){ for (UUID id : game.getPlayerList()) {
Player player = game.getPlayer(id); Player player = game.getPlayer(id);
if (player != null) { if (player != null) {
for (Permanent p : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), id, game)) { for (Permanent p : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), id, game)) {
if(p.getPower().getValue() >= pow && !p.equals(input.getObject())){ if (p.getPower().getValue() >= pow && !p.equals(input.getObject())) {
return false; //we found something with equal/more power return false; //we found something with equal/more power
} }
} }
@ -144,6 +144,7 @@ class GreatestPowerPredicate implements ObjectSourcePlayerPredicate<ObjectSource
} }
return true; return true;
} }
@Override @Override
public String toString() { public String toString() {
return "Greatest Power"; return "Greatest Power";

View file

@ -227,7 +227,8 @@ class IcefallRegentCostIncreaseEffect extends CostModificationEffectImpl {
public boolean applies(Ability abilityToModify, Ability source, Game game) { public boolean applies(Ability abilityToModify, Ability source, Game game) {
if (abilityToModify instanceof SpellAbility) { if (abilityToModify instanceof SpellAbility) {
if (game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { if (game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) {
for (Mode mode : abilityToModify.getModes().getSelectedModes()) { for (UUID modeId : abilityToModify.getModes().getSelectedModes()) {
Mode mode = abilityToModify.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetUUID : target.getTargets()) { for (UUID targetUUID : target.getTargets()) {
if (targetUUID.equals(source.getSourceId())) { if (targetUUID.equals(source.getSourceId())) {

View file

@ -80,7 +80,7 @@ class ReconnaissanceRemoveFromCombatEffect extends OneShotEffect {
public ReconnaissanceRemoveFromCombatEffect() { public ReconnaissanceRemoveFromCombatEffect() {
super(Outcome.Benefit); super(Outcome.Benefit);
this.staticText = "Remove target attacking creature from combat and untap it"; this.staticText = "Remove target attacking creature you control from combat and untap it";
} }
public ReconnaissanceRemoveFromCombatEffect(final ReconnaissanceRemoveFromCombatEffect effect) { public ReconnaissanceRemoveFromCombatEffect(final ReconnaissanceRemoveFromCombatEffect effect) {

View file

@ -109,7 +109,8 @@ class MonasterySiegeCostIncreaseEffect extends CostModificationEffectImpl {
if (new ModeChoiceSourceCondition("Dragons").apply(game, source)) { if (new ModeChoiceSourceCondition("Dragons").apply(game, source)) {
if (abilityToModify instanceof SpellAbility) { if (abilityToModify instanceof SpellAbility) {
if (game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { if (game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) {
for (Mode mode : abilityToModify.getModes().getSelectedModes()) { for (UUID modeId : abilityToModify.getModes().getSelectedModes()) {
Mode mode = abilityToModify.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetUUID : target.getTargets()) { for (UUID targetUUID : target.getTargets()) {
if (targetUUID.equals(source.getControllerId())) { if (targetUUID.equals(source.getControllerId())) {

View file

@ -101,7 +101,7 @@ class AetherbornMarauderEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
Permanent sourceObject = game.getPermanent(source.getSourceId()); Permanent sourceObject = game.getPermanent(source.getSourceId());
if (controller != null && sourceObject != null) { if (controller != null && sourceObject != null) {
FilterControlledPermanent filter = new FilterControlledPermanent("permanent you control from where you like to remove +1/+1 counters"); FilterControlledPermanent filter = new FilterControlledPermanent("permanent you control to remove +1/+1 counters from");
filter.add(new AnotherPredicate()); filter.add(new AnotherPredicate());
filter.add(new CounterPredicate(CounterType.P1P1)); filter.add(new CounterPredicate(CounterType.P1P1));
boolean firstRun = true; boolean firstRun = true;
@ -109,16 +109,19 @@ class AetherbornMarauderEffect extends OneShotEffect {
if (controller.chooseUse(outcome, "Move " + (firstRun ? "any" : "more") + " +1/+1 counters from other permanents you control to " + sourceObject.getLogName() + "?", source, game)) { if (controller.chooseUse(outcome, "Move " + (firstRun ? "any" : "more") + " +1/+1 counters from other permanents you control to " + sourceObject.getLogName() + "?", source, game)) {
firstRun = false; firstRun = false;
TargetControlledPermanent target = new TargetControlledPermanent(filter); TargetControlledPermanent target = new TargetControlledPermanent(filter);
Permanent fromPermanent = game.getPermanent(target.getFirstTarget()); target.setNotTarget(true);
if (fromPermanent != null) { if (target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), game)) {
int numberOfCounters = fromPermanent.getCounters(game).getCount(CounterType.P1P1); Permanent fromPermanent = game.getPermanent(target.getFirstTarget());
int numberToMove = 1; if (fromPermanent != null) {
if (numberOfCounters > 1) { int numberOfCounters = fromPermanent.getCounters(game).getCount(CounterType.P1P1);
numberToMove = controller.getAmount(0, numberOfCounters, "How many +1/+1 counters do you want to move?", game); int numberToMove = 1;
} if (numberOfCounters > 1) {
if (numberToMove > 0) { numberToMove = controller.getAmount(0, numberOfCounters, "How many +1/+1 counters do you want to move?", game);
fromPermanent.removeCounters(CounterType.P1P1.createInstance(numberToMove), game); }
sourceObject.addCounters(CounterType.P1P1.createInstance(numberToMove), game); if (numberToMove > 0) {
fromPermanent.removeCounters(CounterType.P1P1.createInstance(numberToMove), game);
sourceObject.addCounters(CounterType.P1P1.createInstance(numberToMove), game);
}
} }
} }
} else { } else {

View file

@ -1,146 +1,151 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.sets.kaladesh; package mage.sets.kaladesh;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.DiscardHandCost; import mage.abilities.costs.common.DiscardHandCost;
import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.mana.ColoredManaCost; import mage.abilities.costs.mana.ColoredManaCost;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.HasteAbility;
import mage.cards.Card; import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.ColoredManaSymbol; import mage.constants.ColoredManaSymbol;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.ExileZone;
import mage.players.Player; import mage.game.Game;
import mage.util.CardUtil; import mage.players.Player;
import mage.util.CardUtil;
/**
* /**
* @author emerald000 *
*/ * @author emerald000
public class BomatCourier extends CardImpl { */
public class BomatCourier extends CardImpl {
public BomatCourier(UUID ownerId) {
super(ownerId, 199, "Bomat Courier", Rarity.RARE, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}"); public BomatCourier(UUID ownerId) {
this.expansionSetCode = "KLD"; super(ownerId, 199, "Bomat Courier", Rarity.RARE, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}");
this.subtype.add("Construct"); this.expansionSetCode = "KLD";
this.power = new MageInt(1); this.subtype.add("Construct");
this.toughness = new MageInt(1); this.power = new MageInt(1);
this.toughness = new MageInt(1);
// Haste
this.addAbility(HasteAbility.getInstance()); // Haste
this.addAbility(HasteAbility.getInstance());
// Whenever Bomat Courier attacks, exile the top card of your library face down.
this.addAbility(new AttacksTriggeredAbility(new BomatCourierExileEffect(), false)); // Whenever Bomat Courier attacks, exile the top card of your library face down.
this.addAbility(new AttacksTriggeredAbility(new BomatCourierExileEffect(), false));
// {R}, Discard your hand, Sacrifice Bomat Courier: Put all cards exiled with Bomat Courier into their owners' hands.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BomatCourierReturnEffect(), new ColoredManaCost(ColoredManaSymbol.R)); // {R}, Discard your hand, Sacrifice Bomat Courier: Put all cards exiled with Bomat Courier into their owners' hands.
ability.addCost(new DiscardHandCost()); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BomatCourierReturnEffect(), new ColoredManaCost(ColoredManaSymbol.R));
ability.addCost(new SacrificeSourceCost()); ability.addCost(new DiscardHandCost());
this.addAbility(ability); ability.addCost(new SacrificeSourceCost());
} this.addAbility(ability);
}
public BomatCourier(final BomatCourier card) {
super(card); public BomatCourier(final BomatCourier card) {
} super(card);
}
@Override
public BomatCourier copy() { @Override
return new BomatCourier(this); public BomatCourier copy() {
} return new BomatCourier(this);
} }
}
class BomatCourierExileEffect extends OneShotEffect {
class BomatCourierExileEffect extends OneShotEffect {
BomatCourierExileEffect() {
super(Outcome.Exile); BomatCourierExileEffect() {
this.staticText = "exile the top card of your library face down"; super(Outcome.Exile);
} this.staticText = "exile the top card of your library face down";
}
BomatCourierExileEffect(final BomatCourierExileEffect effect) {
super(effect); BomatCourierExileEffect(final BomatCourierExileEffect effect) {
} super(effect);
}
@Override
public BomatCourierExileEffect copy() { @Override
return new BomatCourierExileEffect(this); public BomatCourierExileEffect copy() {
} return new BomatCourierExileEffect(this);
}
@Override
public boolean apply(Game game, Ability source) { @Override
Player controller = game.getPlayer(source.getControllerId()); public boolean apply(Game game, Ability source) {
MageObject sourceObject = source.getSourceObject(game); Player controller = game.getPlayer(source.getControllerId());
if (controller != null && sourceObject != null) { MageObject sourceObject = source.getSourceObject(game);
Card card = controller.getLibrary().getFromTop(game); if (controller != null && sourceObject != null) {
if (card != null) { Card card = controller.getLibrary().getFromTop(game);
UUID exileZoneId = CardUtil.getCardExileZoneId(game, source); if (card != null) {
card.setFaceDown(true, game); UUID exileZoneId = CardUtil.getCardExileZoneId(game, source);
controller.moveCardsToExile(card, source, game, false, exileZoneId, sourceObject.getIdName()); card.setFaceDown(true, game);
card.setFaceDown(true, game); controller.moveCardsToExile(card, source, game, false, exileZoneId, sourceObject.getIdName());
return true; card.setFaceDown(true, game);
} return true;
} }
return false; }
} return false;
} }
}
class BomatCourierReturnEffect extends OneShotEffect {
class BomatCourierReturnEffect extends OneShotEffect {
BomatCourierReturnEffect() {
super(Outcome.DrawCard); BomatCourierReturnEffect() {
this.staticText = "Put all cards exiled with {this} into their owners' hands"; super(Outcome.DrawCard);
} this.staticText = "Put all cards exiled with {this} into their owners' hands";
}
BomatCourierReturnEffect(final BomatCourierReturnEffect effect) {
super(effect); BomatCourierReturnEffect(final BomatCourierReturnEffect effect) {
} super(effect);
}
@Override
public BomatCourierReturnEffect copy() { @Override
return new BomatCourierReturnEffect(this); public BomatCourierReturnEffect copy() {
} return new BomatCourierReturnEffect(this);
}
@Override
public boolean apply(Game game, Ability source) { @Override
Player controller = game.getPlayer(source.getControllerId()); public boolean apply(Game game, Ability source) {
if (controller != null) { Player controller = game.getPlayer(source.getControllerId());
return controller.moveCards(game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source.getSourceId(), true)), Zone.HAND, source, game); if (controller != null) {
} ExileZone exileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source.getSourceId(), true));
return false; if (exileZone != null) {
} controller.moveCards(exileZone, Zone.HAND, source, game);
} }
return true;
}
return false;
}
}

View file

@ -35,7 +35,7 @@ import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.combat.CantAttackBlockAttachedEffect; import mage.abilities.effects.common.combat.CantAttackAttachedEffect;
import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.AttachmentType; import mage.constants.AttachmentType;
@ -81,8 +81,8 @@ public class CapturedByTheConsulate extends CardImpl {
Ability ability = new EnchantAbility(auraTarget.getTargetName()); Ability ability = new EnchantAbility(auraTarget.getTargetName());
this.addAbility(ability); this.addAbility(ability);
// Enchanted creature can't attack or block. // Enchanted creature can't attack.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackBlockAttachedEffect(AttachmentType.AURA))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackAttachedEffect(AttachmentType.AURA)));
// Whenever an opponent casts a spell, if it has a single target, change the target to enchanted creature if able. // Whenever an opponent casts a spell, if it has a single target, change the target to enchanted creature if able.
this.addAbility(new CapturedByTheConsulateTriggeredAbility(Zone.BATTLEFIELD, new CapturedByTheConsulateEffect())); this.addAbility(new CapturedByTheConsulateTriggeredAbility(Zone.BATTLEFIELD, new CapturedByTheConsulateEffect()));
@ -141,7 +141,8 @@ class CapturedByTheConsulateTriggeredAbility extends TriggeredAbilityImpl {
} }
if (stackObject != null) { if (stackObject != null) {
int numberOfTargets = 0; int numberOfTargets = 0;
for (Mode mode : stackObject.getStackAbility().getModes().getSelectedModes()) { for (UUID modeId : stackObject.getStackAbility().getModes().getSelectedModes()) {
Mode mode = stackObject.getStackAbility().getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
numberOfTargets += target.getTargets().size(); numberOfTargets += target.getTargets().size();
} }

View file

@ -99,7 +99,7 @@ class CombustibleGearhulkEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (controller != null && sourcePermanent != null) { if (controller != null && sourcePermanent != null) {
UUID opponentId; UUID opponentId;
if (game.getOpponents(controller.getId()).size() == 1) { if (game.getOpponents(controller.getId()).size() == 1) {

View file

@ -45,6 +45,7 @@ import mage.constants.Zone;
import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.filter.predicate.mageobject.SubtypePredicate;
/** /**
* *
@ -52,21 +53,21 @@ import mage.filter.predicate.mageobject.CardTypePredicate;
*/ */
public class EraOfInnovation extends CardImpl { public class EraOfInnovation extends CardImpl {
private static final FilterControlledPermanent filter = new FilterControlledPermanent("an artifact or creature"); private static final FilterControlledPermanent filter = new FilterControlledPermanent("an artifact or Artificer");
static { static {
filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT), filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT),
new CardTypePredicate(CardType.CREATURE))); new SubtypePredicate("Artificer")));
} }
public EraOfInnovation(UUID ownerId) { public EraOfInnovation(UUID ownerId) {
super(ownerId, 45, "Era of Innovation", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); super(ownerId, 45, "Era of Innovation", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}");
this.expansionSetCode = "KLD"; this.expansionSetCode = "KLD";
// Whenever an artifact or creature enters the battlefield under you control, you may pay {1}. If you do, you get {E}{E}. // Whenever an artifact or Artificer enters the battlefield under you control, you may pay {1}. If you do, you get {E}{E}.
Effect effect = new DoIfCostPaid(new GetEnergyCountersControllerEffect(2), new GenericManaCost(1)); Effect effect = new DoIfCostPaid(new GetEnergyCountersControllerEffect(2), new GenericManaCost(1));
this.addAbility(new EntersBattlefieldAllTriggeredAbility(effect, filter, this.addAbility(new EntersBattlefieldAllTriggeredAbility(effect, filter,
"Whenever an artifact or creature enters the battlefield under you control, you may pay {1}. If you do, you get {E}{E}.")); "Whenever an artifact or Artificer enters the battlefield under you control, you may pay {1}. If you do, you get {E}{E}."));
// {E}{E}{E}{E}{E}{E}, Sacrifice Era of Innovation: Draw three cards. // {E}{E}{E}{E}{E}{E}, Sacrifice Era of Innovation: Draw three cards.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(3), new PayEnergyCost(6)); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(3), new PayEnergyCost(6));

View file

@ -1,82 +1,81 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.sets.kaladesh; package mage.sets.kaladesh;
import java.util.UUID; import java.util.UUID;
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect;
import mage.abilities.keyword.EquipAbility; import mage.abilities.keyword.EquipAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.SetTargetPointer; import mage.constants.SetTargetPointer;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
/** /**
* *
* @author emerald000 * @author emerald000
*/ */
public class InventorsGoggles extends CardImpl { public class InventorsGoggles extends CardImpl {
public InventorsGoggles(UUID ownerId) { public InventorsGoggles(UUID ownerId) {
super(ownerId, 218, "Inventor's Goggles", Rarity.COMMON, new CardType[]{CardType.ARTIFACT}, "{1}"); super(ownerId, 218, "Inventor's Goggles", Rarity.COMMON, new CardType[]{CardType.ARTIFACT}, "{1}");
this.expansionSetCode = "KLD"; this.expansionSetCode = "KLD";
this.subtype.add("Equipment"); this.subtype.add("Equipment");
// Equipped creature gets +1/+2. // Equipped creature gets +1/+2.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(1, 2, Duration.WhileOnBattlefield))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(1, 2, Duration.WhileOnBattlefield)));
// Whenever an Artificer enters the battlefield under your control, you may attach Inventor's Goggles to it. // Whenever an Artificer enters the battlefield under your control, you may attach Inventor's Goggles to it.
this.addAbility(new EntersBattlefieldAllTriggeredAbility( this.addAbility(new EntersBattlefieldControlledTriggeredAbility(
Zone.BATTLEFIELD, Zone.BATTLEFIELD,
new AttachEffect(Outcome.BoostCreature, "attach {this} to it"), new AttachEffect(Outcome.BoostCreature, "attach {this} to it"),
new FilterPermanent("Artificer", "Artificer"), new FilterPermanent("Artificer", "Artificer"),
true, true,
SetTargetPointer.PERMANENT, SetTargetPointer.PERMANENT,
null, null));
true));
// Equip {2}
// Equip {2} this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(2)));
this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(2))); }
}
public InventorsGoggles(final InventorsGoggles card) {
public InventorsGoggles(final InventorsGoggles card) { super(card);
super(card); }
}
@Override
@Override public InventorsGoggles copy() {
public InventorsGoggles copy() { return new InventorsGoggles(this);
return new InventorsGoggles(this); }
} }
}

View file

@ -81,7 +81,7 @@ class LostLegacyEffect extends SearchTargetGraveyardHandLibraryForCardNameAndExi
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
String cardName = (String) game.getState().getValue(source.getSourceId().toString() + NameACardEffect.INFO_KEY); String cardName = (String) game.getState().getValue(source.getSourceId().toString() + NameACardEffect.INFO_KEY);
Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source)); Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source));
if (targetPlayer != null) { if (targetPlayer != null && cardName != null && !cardName.isEmpty()) {
FilterCard filter = new FilterCard(); FilterCard filter = new FilterCard();
filter.add(new NamePredicate(cardName)); filter.add(new NamePredicate(cardName));
int cardsInHandBefore = targetPlayer.getHand().count(filter, game); int cardsInHandBefore = targetPlayer.getHand().count(filter, game);

View file

@ -187,10 +187,10 @@ class MultiformWonder2Effect extends ContinuousEffectImpl {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent target = game.getPermanent(source.getFirstTarget()); Permanent sourceObject = game.getPermanent(source.getSourceId());
if (target != null) { if (sourceObject != null) {
target.addPower(power); sourceObject.addPower(power);
target.addToughness(toughness); sourceObject.addToughness(toughness);
return true; return true;
} }
return false; return false;

View file

@ -41,7 +41,7 @@ import mage.game.Game;
import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.EntersTheBattlefieldEvent;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType; import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent; import mage.game.events.NumberOfTriggersEvent;
/** /**
* *
@ -85,15 +85,28 @@ class PanharmoniconEffect extends ReplacementEffectImpl {
@Override @Override
public boolean checksEventType(GameEvent event, Game game) { public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == EventType.ENTERS_THE_BATTLEFIELD; return event.getType() == EventType.NUMBER_OF_TRIGGERS;
} }
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
if (event instanceof EntersTheBattlefieldEvent) { if (event instanceof NumberOfTriggersEvent) {
Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); NumberOfTriggersEvent numberOfTriggersEvent = (NumberOfTriggersEvent) event;
if (permanent != null) { // Only triggers of the controller of Panharmonicon
return permanent.getCardType().contains(CardType.ARTIFACT) || permanent.getCardType().contains(CardType.CREATURE); if (source.getControllerId().equals(event.getPlayerId())) {
GameEvent sourceEvent = numberOfTriggersEvent.getSourceEvent();
// Only EtB triggers
if (sourceEvent.getType() == EventType.ENTERS_THE_BATTLEFIELD && sourceEvent instanceof EntersTheBattlefieldEvent) {
EntersTheBattlefieldEvent entersTheBattlefieldEvent = (EntersTheBattlefieldEvent) sourceEvent;
// Only for entering artifacts or creatures
if (entersTheBattlefieldEvent.getTarget().getCardType().contains(CardType.ARTIFACT)
|| entersTheBattlefieldEvent.getTarget().getCardType().contains(CardType.CREATURE)) {
// Only for triggers of permanents
if (game.getPermanent(numberOfTriggersEvent.getSourceId()) != null) {
return true;
}
}
}
} }
} }
return false; return false;

View file

@ -33,15 +33,18 @@ import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.PutOnLibraryTargetEffect;
import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect; import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect;
import mage.abilities.mana.ColorlessManaAbility; import mage.abilities.mana.ColorlessManaAbility;
import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.common.FilterArtifactCard; import mage.filter.common.FilterArtifactCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCardInYourGraveyard;
/** /**
@ -61,10 +64,7 @@ public class SequesteredStash extends CardImpl {
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutTopCardOfLibraryIntoGraveControllerEffect(5), new GenericManaCost(4)); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutTopCardOfLibraryIntoGraveControllerEffect(5), new GenericManaCost(4));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeSourceCost()); ability.addCost(new SacrificeSourceCost());
Effect effect = new PutOnLibraryTargetEffect(true); ability.addEffect(new SequesteredStashEffect());
effect.setText("Then you may put an artifact card from your graveyard on top of your library");
ability.addEffect(effect);
ability.addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard")));
this.addAbility(ability); this.addAbility(ability);
} }
@ -78,3 +78,39 @@ public class SequesteredStash extends CardImpl {
return new SequesteredStash(this); return new SequesteredStash(this);
} }
} }
class SequesteredStashEffect extends OneShotEffect {
public SequesteredStashEffect() {
super(Outcome.Benefit);
this.staticText = "Then you may put an artifact card from your graveyard on top of your library";
}
public SequesteredStashEffect(final SequesteredStashEffect effect) {
super(effect);
}
@Override
public SequesteredStashEffect copy() {
return new SequesteredStashEffect(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 FilterArtifactCard("artifact card from your graveyard"));
target.setNotTarget(true);
if (target.canChoose(source.getSourceId(), source.getControllerId(), game)
&& controller.chooseUse(outcome, "Put an artifact card from your graveyard to library?", source, game)
&& controller.choose(outcome, target, source.getSourceId(), game)) {
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
controller.moveCards(card, Zone.LIBRARY, source, game);
}
}
return true;
}
}

View file

@ -44,6 +44,7 @@ import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
/** /**
* *
@ -57,6 +58,7 @@ public class SparkOfCreativity extends CardImpl {
// Choose target creature. Exile the top card of your library. You may have Spark of Creativity deal damage to that creature equal to the converted mana cost of the exiled card. If you don't, you may play that card until end of turn. // Choose target creature. Exile the top card of your library. You may have Spark of Creativity deal damage to that creature equal to the converted mana cost of the exiled card. If you don't, you may play that card until end of turn.
this.getSpellAbility().addEffect(new SparkOfCreativityEffect()); this.getSpellAbility().addEffect(new SparkOfCreativityEffect());
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
} }
public SparkOfCreativity(final SparkOfCreativity card) { public SparkOfCreativity(final SparkOfCreativity card) {
@ -142,9 +144,7 @@ class SparkOfCreativityPlayEffect extends AsThoughEffectImpl {
if (objectReference.refersTo(objectId, game) && affectedControllerId.equals(source.getControllerId())) { if (objectReference.refersTo(objectId, game) && affectedControllerId.equals(source.getControllerId())) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller != null) {
if (controller.chooseUse(outcome, "Play the exiled card?", source, game)) { return true;
return true;
}
} else { } else {
discard(); discard();
} }

View file

@ -52,11 +52,15 @@ public class SubtleStrike extends CardImpl {
this.getSpellAbility().getModes().setMinModes(1); this.getSpellAbility().getModes().setMinModes(1);
this.getSpellAbility().getModes().setMaxModes(2); this.getSpellAbility().getModes().setMaxModes(2);
// Target creature gets -1/-1 until end of turn. // Target creature gets -1/-1 until end of turn.
this.getSpellAbility().addEffect(new BoostTargetEffect(-1, -1, Duration.EndOfTurn)); BoostTargetEffect minusOneMinusOne = new BoostTargetEffect(-1, -1, Duration.EndOfTurn);
minusOneMinusOne.setText("Target creature gets -1/-1 until end of turn");
this.getSpellAbility().addEffect(minusOneMinusOne);
this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addTarget(new TargetCreaturePermanent());
// Put a +1/+1 counter on target creature. // Put a +1/+1 counter on target creature.
Mode mode1 = new Mode(); Mode mode1 = new Mode();
mode1.getEffects().add(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); AddCountersTargetEffect plusOnePlusOneCounter = new AddCountersTargetEffect(CounterType.P1P1.createInstance());
plusOnePlusOneCounter.setText("Put a +1/+1 counter on target creature");
mode1.getEffects().add(plusOnePlusOneCounter);
mode1.getTargets().add(new TargetCreaturePermanent()); mode1.getTargets().add(new TargetCreaturePermanent());
this.getSpellAbility().addMode(mode1); this.getSpellAbility().addMode(mode1);

View file

@ -56,7 +56,7 @@ public class AltarOfTheBrood extends CardImpl {
// Whenever another permanent enters the battlefield under your control, each opponent puts the top card of his or her library into his or her graveyard. // Whenever another permanent enters the battlefield under your control, each opponent puts the top card of his or her library into his or her graveyard.
this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD,
new PutTopCardOfLibraryIntoGraveEachPlayerEffect(1, TargetController.OPPONENT), filter, false)); new PutTopCardOfLibraryIntoGraveEachPlayerEffect(1, TargetController.OPPONENT), filter, false, null, true));
} }
public AltarOfTheBrood(final AltarOfTheBrood card) { public AltarOfTheBrood(final AltarOfTheBrood card) {

View file

@ -29,15 +29,18 @@ package mage.sets.legions;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility;
import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.SetTargetPointer; import mage.constants.SetTargetPointer;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.token.SliverToken; import mage.game.permanent.token.SliverToken;
import mage.players.Player;
/** /**
* *
@ -54,10 +57,8 @@ public class BroodSliver extends CardImpl {
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
// Whenever a Sliver deals combat damage to a player, its controller may put a 1/1 colorless Sliver creature token onto the battlefield. // Whenever a Sliver deals combat damage to a player, its controller may put a 1/1 colorless Sliver creature token onto the battlefield.
Effect effect = new CreateTokenTargetEffect(new SliverToken()); this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility(new BroodSliverEffect(),
effect.setText("its controller may put a 1/1 colorless Sliver creature token onto the battlefield"); new FilterCreaturePermanent("Sliver", "a Sliver"), false, SetTargetPointer.PLAYER, true));
this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility(effect,
new FilterCreaturePermanent("Sliver", "a Sliver"), true, SetTargetPointer.PLAYER, true));
} }
public BroodSliver(final BroodSliver card) { public BroodSliver(final BroodSliver card) {
@ -69,3 +70,32 @@ public class BroodSliver extends CardImpl {
return new BroodSliver(this); return new BroodSliver(this);
} }
} }
class BroodSliverEffect extends OneShotEffect {
public BroodSliverEffect() {
super(Outcome.PutCardInPlay);
this.staticText = "its controller may put a 1/1 colorless Sliver creature token onto the battlefield";
}
public BroodSliverEffect(final BroodSliverEffect effect) {
super(effect);
}
@Override
public BroodSliverEffect copy() {
return new BroodSliverEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player permanentController = game.getPlayer(getTargetPointer().getFirst(game, source));
if (permanentController != null) {
if (permanentController.chooseUse(outcome, "put a 1/1 colorless Sliver creature token onto the battlefield", source, game)) {
return new SliverToken().putOntoBattlefield(1, game, source.getSourceId(), permanentController.getId());
}
return true;
}
return false;
}
}

View file

@ -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.lorwyn;
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.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.dynamicvalue.common.StaticValue;
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.constants.Zone;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author Styxo
*/
public class SilvergillDouser extends CardImpl {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Merfolk and/or Faeries you control");
static {
filter.add(Predicates.or(new SubtypePredicate("Merfolk"), new SubtypePredicate("Faerie")));
}
public SilvergillDouser(UUID ownerId) {
super(ownerId, 87, "Silvergill Douser", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{U}");
this.expansionSetCode = "LRW";
this.subtype.add("Merfolk");
this.subtype.add("Wizard");
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// {tap}: Target creature gets -X/-0 until end of turn, where X is the number of Merfolk and/or Faeries you control.
DynamicValue number = new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent(filter), -1);
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(number, new StaticValue(0), Duration.EndOfTurn, true), new TapSourceCost());
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
public SilvergillDouser(final SilvergillDouser card) {
super(card);
}
@Override
public SilvergillDouser copy() {
return new SilvergillDouser(this);
}
}

View file

@ -27,12 +27,9 @@
*/ */
package mage.sets.magic2014; package mage.sets.magic2014;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.Mode; import mage.abilities.Mode;
import mage.abilities.TriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
@ -42,14 +39,11 @@ import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.Filter;
import mage.filter.FilterAbility;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.stack.StackAbility; import mage.game.stack.StackAbility;
import mage.game.stack.StackObject;
import mage.players.Player; import mage.players.Player;
import mage.target.TargetObject; import mage.target.common.TargetTriggeredAbility;
/** /**
* *
@ -96,7 +90,7 @@ class StrionicResonatorEffect extends OneShotEffect {
Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (controller != null && sourcePermanent != null) { if (controller != null && sourcePermanent != null) {
stackAbility.createCopyOnStack(game, source, source.getControllerId(), true); stackAbility.createCopyOnStack(game, source, source.getControllerId(), true);
game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(": ").append(controller.getLogName()).append(" copied activated ability").toString()); game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(": ").append(controller.getLogName()).append(" copied triggered ability").toString());
return true; return true;
} }
} }
@ -116,76 +110,3 @@ class StrionicResonatorEffect extends OneShotEffect {
return sb.toString(); return sb.toString();
} }
} }
class TargetTriggeredAbility extends TargetObject {
public TargetTriggeredAbility() {
this.minNumberOfTargets = 1;
this.maxNumberOfTargets = 1;
this.zone = Zone.STACK;
this.targetName = "target triggered ability you control";
}
public TargetTriggeredAbility(final TargetTriggeredAbility target) {
super(target);
}
@Override
public boolean canTarget(UUID id, Ability source, Game game) {
if (source != null && source.getSourceId().equals(id)) {
return false;
}
StackObject stackObject = game.getStack().getStackObject(id);
return stackObject.getStackAbility() != null
&& (stackObject.getStackAbility() instanceof TriggeredAbility)
&& source != null
&& stackObject.getStackAbility().getControllerId().equals(source.getControllerId());
}
@Override
public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) {
return canChoose(sourceControllerId, game);
}
@Override
public boolean canChoose(UUID sourceControllerId, Game game) {
for (StackObject stackObject : game.getStack()) {
if (stackObject.getStackAbility() != null
&& stackObject.getStackAbility() instanceof TriggeredAbility
&& stackObject.getStackAbility().getControllerId().equals(sourceControllerId)) {
return true;
}
}
return false;
}
@Override
public Set<UUID> possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) {
return possibleTargets(sourceControllerId, game);
}
@Override
public Set<UUID> possibleTargets(UUID sourceControllerId, Game game) {
Set<UUID> possibleTargets = new HashSet<>();
for (StackObject stackObject : game.getStack()) {
if (stackObject.getStackAbility() != null
&& stackObject.getStackAbility() instanceof TriggeredAbility
&& stackObject.getStackAbility().getControllerId().equals(sourceControllerId)) {
possibleTargets.add(stackObject.getStackAbility().getId());
}
}
return possibleTargets;
}
@Override
public TargetTriggeredAbility copy() {
return new TargetTriggeredAbility(this);
}
@Override
public Filter getFilter() {
return new FilterAbility();
}
}

View file

@ -135,7 +135,8 @@ class PsychicRebuttalPredicate implements ObjectPlayerPredicate<ObjectPlayer<Sta
if (controllerId == null) { if (controllerId == null) {
return false; return false;
} }
for (Mode mode : input.getObject().getStackAbility().getModes().getSelectedModes()) { for (UUID modeId : input.getObject().getStackAbility().getModes().getSelectedModes()) {
Mode mode = input.getObject().getStackAbility().getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetId : target.getTargets()) { for (UUID targetId : target.getTargets()) {
if (controllerId.equals(targetId)) { if (controllerId.equals(targetId)) {

View file

@ -118,20 +118,19 @@ class FoodChainManaEffect extends ManaEffect {
ChoiceColor choice = new ChoiceColor(); ChoiceColor choice = new ChoiceColor();
controller.choose(Outcome.PutManaInPool, choice, game); controller.choose(Outcome.PutManaInPool, choice, game);
ObjectColor chosenColor = choice.getColor(); ObjectColor chosenColor = choice.getColor();
if (chosenColor == null) {
return false;
}
Mana mana = null; Mana mana = null;
if (chosenColor.isBlack()) { if (chosenColor.isBlack()) {
mana = new FoodChainManaBuilder().setMana(Mana.BlackMana(manaCostExiled + 1), source, game).build(); mana = new FoodChainManaBuilder().setMana(Mana.BlackMana(manaCostExiled + 1), source, game).build();
} } else if (chosenColor.isBlue()) {
else if (chosenColor.isBlue()) {
mana = new FoodChainManaBuilder().setMana(Mana.BlueMana(manaCostExiled + 1), source, game).build(); mana = new FoodChainManaBuilder().setMana(Mana.BlueMana(manaCostExiled + 1), source, game).build();
} } else if (chosenColor.isRed()) {
else if (chosenColor.isRed()) {
mana = new FoodChainManaBuilder().setMana(Mana.RedMana(manaCostExiled + 1), source, game).build(); mana = new FoodChainManaBuilder().setMana(Mana.RedMana(manaCostExiled + 1), source, game).build();
} } else if (chosenColor.isGreen()) {
else if (chosenColor.isGreen()) {
mana = new FoodChainManaBuilder().setMana(Mana.GreenMana(manaCostExiled + 1), source, game).build(); mana = new FoodChainManaBuilder().setMana(Mana.GreenMana(manaCostExiled + 1), source, game).build();
} } else if (chosenColor.isWhite()) {
else if (chosenColor.isWhite()) {
mana = new FoodChainManaBuilder().setMana(Mana.WhiteMana(manaCostExiled + 1), source, game).build(); mana = new FoodChainManaBuilder().setMana(Mana.WhiteMana(manaCostExiled + 1), source, game).build();
} }
if (mana != null) { if (mana != null) {

View file

@ -29,18 +29,12 @@ package mage.sets.mirrodinbesieged;
import java.util.UUID; import java.util.UUID;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.common.ruleModifying.CantHaveCountersSourceEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
/** /**
* *
@ -58,7 +52,7 @@ public class MelirasKeepers extends CardImpl {
this.toughness = new MageInt(4); this.toughness = new MageInt(4);
// Melira's Keepers can't have counters placed on it // Melira's Keepers can't have counters placed on it
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MelirasKeepersEffect())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantHaveCountersSourceEffect()));
} }
public MelirasKeepers(final MelirasKeepers card) { public MelirasKeepers(final MelirasKeepers card) {
@ -71,31 +65,3 @@ public class MelirasKeepers extends CardImpl {
} }
} }
class MelirasKeepersEffect extends ContinuousRuleModifyingEffectImpl {
public MelirasKeepersEffect() {
super(Duration.WhileOnBattlefield, Outcome.PreventDamage);
staticText = "{this} can't have counters placed on it";
}
public MelirasKeepersEffect(final MelirasKeepersEffect effect) {
super(effect);
}
@Override
public MelirasKeepersEffect copy() {
return new MelirasKeepersEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == EventType.ADD_COUNTER;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
return event.getTargetId().equals(source.getSourceId());
}
}

View file

@ -106,7 +106,8 @@ class ElderwoodScionCostReductionEffect extends CostModificationEffectImpl {
public boolean applies(Ability abilityToModify, Ability source, Game game) { public boolean applies(Ability abilityToModify, Ability source, Game game) {
if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) { if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) {
if (abilityToModify.getControllerId().equals(source.getControllerId())) { if (abilityToModify.getControllerId().equals(source.getControllerId())) {
for (Mode mode : abilityToModify.getModes().getSelectedModes()) { for (UUID modeId : abilityToModify.getModes().getSelectedModes()) {
Mode mode = abilityToModify.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetUUID : target.getTargets()) { for (UUID targetUUID : target.getTargets()) {
if (targetUUID.equals(source.getSourceId())) { if (targetUUID.equals(source.getSourceId())) {

View file

@ -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.prophecy;
import java.util.UUID;
import mage.abilities.effects.common.SetPlayerLifeTargetEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.target.TargetPlayer;
/**
*
* @author Styxo
*/
public class BlessedWind extends CardImpl {
public BlessedWind(UUID ownerId) {
super(ownerId, 4, "Blessed Wind", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{7}{W}{W}");
this.expansionSetCode = "PCY";
// Target player's life total becomes 20.
this.getSpellAbility().addEffect(new SetPlayerLifeTargetEffect(20));
this.getSpellAbility().addTarget(new TargetPlayer());
}
public BlessedWind(final BlessedWind card) {
super(card);
}
@Override
public BlessedWind copy() {
return new BlessedWind(this);
}
}

View file

@ -30,7 +30,7 @@ package mage.sets.ravnica;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.LeavesBattlefieldAllTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.RemoveCountersSourceCost; import mage.abilities.costs.common.RemoveCountersSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
@ -41,12 +41,8 @@ import mage.constants.CardType;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.game.Game; import mage.filter.common.FilterCreaturePermanent;
import mage.game.events.GameEvent; import mage.filter.predicate.permanent.TokenPredicate;
import mage.game.events.GameEvent.EventType;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentToken;
import mage.game.permanent.token.SpiritWhiteToken; import mage.game.permanent.token.SpiritWhiteToken;
/** /**
@ -55,6 +51,12 @@ import mage.game.permanent.token.SpiritWhiteToken;
*/ */
public class TwilightDrover extends CardImpl { public class TwilightDrover extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature token");
static {
filter.add(new TokenPredicate());
}
public TwilightDrover(UUID ownerId) { public TwilightDrover(UUID ownerId) {
super(ownerId, 33, "Twilight Drover", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{W}"); super(ownerId, 33, "Twilight Drover", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{W}");
this.expansionSetCode = "RAV"; this.expansionSetCode = "RAV";
@ -64,8 +66,8 @@ public class TwilightDrover extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// Whenever a creature token leaves the battlefield, put a +1/+1 counter on Twilight Drover. // Whenever a creature token leaves the battlefield, put a +1/+1 counter on Twilight Drover.
this.addAbility(new TwilightDroverTriggeredAbility()); this.addAbility(new LeavesBattlefieldAllTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter));
// {2}{W}, Remove a +1/+1 counter from Twilight Drover: Put two 1/1 white Spirit creature tokens with flying onto the battlefield. // {2}{W}, Remove a +1/+1 counter from Twilight Drover: Put two 1/1 white Spirit creature tokens with flying onto the battlefield.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new SpiritWhiteToken("RAV"), 2), new ManaCostsImpl<>("{2}{W}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new SpiritWhiteToken("RAV"), 2), new ManaCostsImpl<>("{2}{W}"));
ability.addCost(new RemoveCountersSourceCost(CounterType.P1P1.createInstance())); ability.addCost(new RemoveCountersSourceCost(CounterType.P1P1.createInstance()));
@ -81,42 +83,3 @@ public class TwilightDrover extends CardImpl {
return new TwilightDrover(this); return new TwilightDrover(this);
} }
} }
class TwilightDroverTriggeredAbility extends TriggeredAbilityImpl {
TwilightDroverTriggeredAbility() {
super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false);
}
TwilightDroverTriggeredAbility(final TwilightDroverTriggeredAbility ability) {
super(ability);
}
@Override
public TwilightDroverTriggeredAbility copy() {
return new TwilightDroverTriggeredAbility(this);
}
@Override
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;
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
UUID targetId = event.getTargetId();
Permanent permanent = game.getPermanentOrLKIBattlefield(targetId);
if (permanent != null) {
return permanent.getCardType().contains(CardType.CREATURE) && permanent instanceof PermanentToken;
}
}
return false;
}
@Override
public String getRule() {
return "Whenever a creature token leaves the battlefield, put a +1/+1 counter on {this}";
}
}

View file

@ -52,7 +52,6 @@ public class LightmineField extends CardImpl {
super(ownerId, 32, "Lightmine Field", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); super(ownerId, 32, "Lightmine Field", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}");
this.expansionSetCode = "ROE"; this.expansionSetCode = "ROE";
// Whenever one or more creatures attack, Lightmine Field deals damage to each of those creatures equal to the number of attacking creatures. // Whenever one or more creatures attack, Lightmine Field deals damage to each of those creatures equal to the number of attacking creatures.
this.addAbility(new LightmineFieldTriggeredAbility()); this.addAbility(new LightmineFieldTriggeredAbility());
} }
@ -122,7 +121,7 @@ class LightmineFieldEffect extends OneShotEffect {
for (UUID attacker : attackers) { for (UUID attacker : attackers) {
Permanent creature = game.getPermanent(attacker); Permanent creature = game.getPermanent(attacker);
if (creature != null) { if (creature != null) {
creature.damage(damage, source.getSourceId(), game, false, false); creature.damage(damage, source.getSourceId(), game, false, true);
} }
} }
return true; return true;

View file

@ -28,7 +28,6 @@
package mage.sets.scourge; package mage.sets.scourge;
import java.util.Iterator; import java.util.Iterator;
import java.util.Random;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
@ -108,7 +107,8 @@ class GripOfChaosTriggeredAbility extends TriggeredAbilityImpl {
} }
if (stackObject != null) { if (stackObject != null) {
int numberOfTargets = 0; int numberOfTargets = 0;
for (Mode mode : stackObject.getStackAbility().getModes().getSelectedModes()) { for (UUID modeId : stackObject.getStackAbility().getModes().getSelectedModes()) {
Mode mode = stackObject.getStackAbility().getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
numberOfTargets += target.getTargets().size(); numberOfTargets += target.getTargets().size();
} }
@ -149,7 +149,8 @@ class GripOfChaosEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
StackObject stackObject = game.getStack().getStackObject(this.getTargetPointer().getFirst(game, source)); StackObject stackObject = game.getStack().getStackObject(this.getTargetPointer().getFirst(game, source));
if (stackObject != null) { if (stackObject != null) {
for (Mode mode : stackObject.getStackAbility().getModes().getSelectedModes()) { for (UUID modeId : stackObject.getStackAbility().getModes().getSelectedModes()) {
Mode mode = stackObject.getStackAbility().getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
UUID oldTargetId = target.getFirstTarget(); UUID oldTargetId = target.getFirstTarget();
Set<UUID> possibleTargets = target.possibleTargets(source.getSourceId(), source.getControllerId(), game); Set<UUID> possibleTargets = target.possibleTargets(source.getSourceId(), source.getControllerId(), game);

View file

@ -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.scourge;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.filter.Filter.ComparisonType;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.filter.predicate.mageobject.ConvertedManaCostPredicate;
/**
*
* @author Eirkei
*/
public class KrosanDrover extends CardImpl {
private static final FilterCard filter = new FilterCard("Creature spells with converted mana cost 6 or greater");
static {
filter.add(new CardTypePredicate(CardType.CREATURE));
filter.add(new ConvertedManaCostPredicate(ComparisonType.GreaterThan, 5));
}
public KrosanDrover(UUID ownerId) {
super(ownerId, 122, "Krosan Drover", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{G}");
this.expansionSetCode = "SCG";
this.subtype.add("Elf");
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Creature spells you cast with converted mana cost 6 or greater cost {2} less to cast.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(filter, 2)));
}
public KrosanDrover(final KrosanDrover card) {
super(card);
}
@Override
public KrosanDrover copy() {
return new KrosanDrover(this);
}
}

View file

@ -29,19 +29,14 @@ package mage.sets.shadowmoor;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.common.ruleModifying.CantHaveCountersSourceEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
/** /**
* *
@ -60,7 +55,7 @@ public class Tatterkite extends CardImpl {
this.addAbility(FlyingAbility.getInstance()); this.addAbility(FlyingAbility.getInstance());
// Tatterkite can't have counters placed on it. // Tatterkite can't have counters placed on it.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new CantHaveCountersSourceEffect(Duration.WhileOnBattlefield))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantHaveCountersSourceEffect()));
} }
@ -73,34 +68,3 @@ public class Tatterkite extends CardImpl {
return new Tatterkite(this); return new Tatterkite(this);
} }
} }
class CantHaveCountersSourceEffect extends ContinuousRuleModifyingEffectImpl {
public CantHaveCountersSourceEffect(Duration duration) {
super(duration, Outcome.Detriment);
staticText = "{this} can't have counters placed on it";
}
public CantHaveCountersSourceEffect(final CantHaveCountersSourceEffect effect) {
super(effect);
}
@Override
public CantHaveCountersSourceEffect copy() {
return new CantHaveCountersSourceEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == EventType.ADD_COUNTERS;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
UUID sourceId = source.getSourceId();
if (sourceId != null) {
return sourceId.equals(event.getTargetId());
}
return false;
}
}

View file

@ -140,7 +140,8 @@ class AccursedWitchSpellsCostReductionEffect extends CostModificationEffectImpl
public boolean applies(Ability abilityToModify, Ability source, Game game) { public boolean applies(Ability abilityToModify, Ability source, Game game) {
if (abilityToModify instanceof SpellAbility) { if (abilityToModify instanceof SpellAbility) {
if (game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { if (game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) {
for (Mode mode : abilityToModify.getModes().getSelectedModes()) { for (UUID modeId : abilityToModify.getModes().getSelectedModes()) {
Mode mode = abilityToModify.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetUUID : target.getTargets()) { for (UUID targetUUID : target.getTargets()) {
Permanent permanent = game.getPermanent(targetUUID); Permanent permanent = game.getPermanent(targetUUID);

View file

@ -155,7 +155,8 @@ class InfectiousCurseCostReductionEffect extends CostModificationEffectImpl {
public boolean applies(Ability abilityToModify, Ability source, Game game) { public boolean applies(Ability abilityToModify, Ability source, Game game) {
if (abilityToModify instanceof SpellAbility) { if (abilityToModify instanceof SpellAbility) {
if (source.getControllerId().equals(abilityToModify.getControllerId())) { if (source.getControllerId().equals(abilityToModify.getControllerId())) {
for (Mode mode : abilityToModify.getModes().getSelectedModes()) { for (UUID modeId : abilityToModify.getModes().getSelectedModes()) {
Mode mode = abilityToModify.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetUUID : target.getTargets()) { for (UUID targetUUID : target.getTargets()) {
Permanent enchantment = game.getPermanent(source.getSourceId()); Permanent enchantment = game.getPermanent(source.getSourceId());

View file

@ -84,7 +84,8 @@ class HinderingLightPredicate implements ObjectPlayerPredicate<ObjectPlayer<Stac
if (controllerId == null) { if (controllerId == null) {
return false; return false;
} }
for (Mode mode : input.getObject().getStackAbility().getModes().getSelectedModes()) { for (UUID modeId : input.getObject().getStackAbility().getModes().getSelectedModes()) {
Mode mode = input.getObject().getStackAbility().getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetId : target.getTargets()) { for (UUID targetId : target.getTargets()) {
if (controllerId.equals(targetId)) { if (controllerId.equals(targetId)) {

View file

@ -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.timespiral;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.MadnessAbility;
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 anonymous
*/
public class PsychoticEpisode extends CardImpl {
public PsychoticEpisode(UUID ownerId) {
super(ownerId, 126, "Psychotic Episode", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{1}{B}{B}");
this.expansionSetCode = "TSP";
// Target player reveals his or her hand and the top card of his or her library. You choose a card revealed this way. That player puts the chosen card on the bottom of his or her library.
this.getSpellAbility().addEffect(new PsychoticEpisodeEffect());
this.getSpellAbility().addTarget(new TargetPlayer());
// Madness {1}{B}
this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{1}{B}")));
}
public PsychoticEpisode(final PsychoticEpisode card) {
super(card);
}
@Override
public PsychoticEpisode copy() {
return new PsychoticEpisode(this);
}
}
class PsychoticEpisodeEffect extends OneShotEffect {
PsychoticEpisodeEffect() {
super(Outcome.Discard);
staticText = "Target player reveals his or her hand and the top card of his or her library. You choose a card revealed this way. That player puts the chosen card on the bottom of his or her library.";
}
PsychoticEpisodeEffect(final PsychoticEpisodeEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(targetPointer.getFirst(game, source));
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game);
if (player != null && controller != null && sourceObject != null) {
TargetCard targetCard = new TargetCard(Zone.ALL, new FilterCard());
targetCard.setRequired(true);
Cards options = player.getHand().copy();
Card topdeck = player.getLibrary().getFromTop(game);
options.add(topdeck);
controller.lookAtCards("Top of Library (Psychotic Episode)", topdeck, game);
if (controller.choose(Outcome.Discard, options, targetCard, game)) {
Card card = game.getCard(targetCard.getFirstTarget());
if (card != null) {
CardsImpl cards = new CardsImpl();
cards.add(card);
player.revealCards(sourceObject.getIdName(), cards, game);
player.putCardsOnBottomOfLibrary(cards, game, source, true);
}
}
return true;
}
return false;
}
@Override
public PsychoticEpisodeEffect copy() {
return new PsychoticEpisodeEffect(this);
}
}

View file

@ -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.timespiral;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilityAllEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.target.common.TargetAttackingOrBlockingCreature;
/**
*
* @author HanClinto
*
* A relatively straightforward merge between GemhideSliver.java and
* CrossbowInfantry.java
*/
public class QuilledSliver extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("Sliver", "All Slivers");
public QuilledSliver(UUID ownerId) {
super(ownerId, 37, "Quilled Sliver", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{W}");
this.expansionSetCode = "TSP";
this.subtype.add("Sliver");
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// All Slivers have "{tap}: This permanent deals 1 damage to target attacking or blocking creature."
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new TapSourceCost());
ability.addTarget(new TargetAttackingOrBlockingCreature());
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD,
new GainAbilityAllEffect(ability,
Duration.WhileOnBattlefield, filter,
"All Slivers have \"{T}: This permanent deals 1 damage to target attacking or blocking creature.\"")));
}
public QuilledSliver(final QuilledSliver card) {
super(card);
}
@Override
public QuilledSliver copy() {
return new QuilledSliver(this);
}
}

View file

@ -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.urzassaga;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.Effect;
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.FilterControlledCreaturePermanent;
import mage.filter.common.FilterControlledPermanent;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author maxlebedev
*/
public class Curfew extends CardImpl {
public Curfew(UUID ownerId) {
super(ownerId, 68, "Curfew", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{U}");
this.expansionSetCode = "USG";
// Each player returns a creature he or she controls to its owner's hand.
this.getSpellAbility().addEffect(new CurfewEffect());
}
public Curfew(final Curfew card) {
super(card);
}
@Override
public Curfew copy() {
return new Curfew(this);
}
}
class CurfewEffect extends OneShotEffect{
public CurfewEffect() {
super(Outcome.ReturnToHand);
staticText = "Each player returns a creature he or she controls to its owner's hand";
}
@Override
public boolean apply(Game game, Ability source) {
game.informPlayers("Each player returns a creature he or she controls to its owner's hand");
for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) {
Player player = game.getPlayer(playerId);
if (player != null) {
TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent();
List<Permanent> liste = game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), playerId, game);
if(!liste.isEmpty()){
player.choose(Outcome.ReturnToHand, target, source.getSourceId(), game);
Permanent permanent = game.getPermanent(target.getFirstTarget());
if (permanent != null) {
permanent.moveToZone(Zone.HAND, source.getSourceId(), game, false);
}
}
}
}
return true;
}
@Override
public Effect copy() {
return new CurfewEffect();
}
}

View file

@ -96,7 +96,7 @@ class SmokestackEffect extends OneShotEffect {
int count = sourcePermanent.getCounters(game).getCount("Soot"); int count = sourcePermanent.getCounters(game).getCount("Soot");
if (count > 0) { if (count > 0) {
int amount = Math.min(count, game.getBattlefield().countAll(new FilterControlledPermanent(), activePlayer.getId(), game)); int amount = Math.min(count, game.getBattlefield().countAll(new FilterControlledPermanent(), activePlayer.getId(), game));
Target target = new TargetControlledPermanent(amount, amount, new FilterControlledPermanent(), false); Target target = new TargetControlledPermanent(amount, amount, new FilterControlledPermanent(), true);
//A spell or ability could have removed the only legal target this player //A spell or ability could have removed the only legal target this player
//had, if thats the case this ability should fizzle. //had, if thats the case this ability should fizzle.
if (target.canChoose(activePlayer.getId(), game)) { if (target.canChoose(activePlayer.getId(), game)) {

View file

@ -113,13 +113,13 @@ class TorchlingTargetPredicate implements Predicate<MageObject> {
if (spell != null) { if (spell != null) {
int numberOfTargets = 0; int numberOfTargets = 0;
for (SpellAbility spellAbility : spell.getSpellAbilities()) { for (SpellAbility spellAbility : spell.getSpellAbilities()) {
for (Mode mode : spellAbility.getModes().getSelectedModes()) { for (UUID modeId : spellAbility.getModes().getSelectedModes()) {
Mode mode = spellAbility.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetId : target.getTargets()) { for (UUID targetId : target.getTargets()) {
if (!targetId.equals(sourceId)) { if (!targetId.equals(sourceId)) {
return false; return false;
} } else {
else {
numberOfTargets++; numberOfTargets++;
} }
} }

View file

@ -96,7 +96,8 @@ class KaerveksTorchCostIncreaseEffect extends CostModificationEffectImpl {
@Override @Override
public boolean applies(Ability abilityToModify, Ability source, Game game) { public boolean applies(Ability abilityToModify, Ability source, Game game) {
if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) { if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) {
for (Mode mode : abilityToModify.getModes().getSelectedModes()) { for (UUID modeId : abilityToModify.getModes().getSelectedModes()) {
Mode mode = abilityToModify.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetId : target.getTargets()) { for (UUID targetId : target.getTargets()) {
if (targetId.equals(source.getSourceObject(game).getId())) { if (targetId.equals(source.getSourceObject(game).getId())) {

View file

@ -111,7 +111,7 @@ class TerastodonEffect extends OneShotEffect {
if (destroyedPermanents.containsKey(permanent.getControllerId())) { if (destroyedPermanents.containsKey(permanent.getControllerId())) {
numberPermanents = destroyedPermanents.get(permanent.getControllerId()); numberPermanents = destroyedPermanents.get(permanent.getControllerId());
} }
destroyedPermanents.put(permanent.getControllerId(), numberPermanents); destroyedPermanents.put(permanent.getControllerId(), numberPermanents + 1);
} }
} }
} }

View file

@ -38,10 +38,6 @@ import org.mage.test.serverside.base.CardTestPlayerBaseAI;
*/ */
public class CastDestroySpellsTest extends CardTestPlayerBaseAI { public class CastDestroySpellsTest extends CardTestPlayerBaseAI {
/**
*
*
*/
@Test @Test
public void testOrzhovCharm() { public void testOrzhovCharm() {
// Choose one - // Choose one -
@ -58,6 +54,8 @@ public class CastDestroySpellsTest extends CardTestPlayerBaseAI {
// Cycling abilities you activate cost you up to {2} less to activate. // Cycling abilities you activate cost you up to {2} less to activate.
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Orzhov Charm", "Silvercoat Lion");
setModeChoice(playerA, "2");
setStopAt(1, PhaseStep.BEGIN_COMBAT); setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute(); execute();

View file

@ -219,7 +219,7 @@ public class UndyingTest extends CardTestPlayerBase {
} }
/** /**
* Tatterkite is getting counters on it, i have him in a edh deck with * Tatterkite is getting counters on it, I have him in a edh deck with
* Mikaeus, the Lunarch and when Tatterkite dies it triggers the undying and * Mikaeus, the Lunarch and when Tatterkite dies it triggers the undying and
* he gets the +1/+1 counters * he gets the +1/+1 counters
*/ */

View file

@ -0,0 +1,107 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation 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.modal;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class OneOrBothTest extends CardTestPlayerBase {
@Test
public void testSubtleStrikeFirstMode() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
// Choose one or both
// Target creature gets -1/-1 until end of turn.
// Put a +1/+1 counter on target creature.
addCard(Zone.HAND, playerA, "Subtle Strike"); // Instant {1}{B}
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion");
addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Subtle Strike", "Pillarfield Ox");
setModeChoice(playerA, "1");
setModeChoice(playerA, null);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPowerToughness(playerA, "Silvercoat Lion", 2, 2);
assertPowerToughness(playerB, "Pillarfield Ox", 1, 3);
}
@Test
public void testSubtleStrikeSecondMode() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
// Choose one or both
// Target creature gets -1/-1 until end of turn.
// Put a +1/+1 counter on target creature.
addCard(Zone.HAND, playerA, "Subtle Strike"); // Instant {1}{B}
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion");
addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Subtle Strike", "Pillarfield Ox");
setModeChoice(playerA, "2");
setModeChoice(playerA, null);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPowerToughness(playerA, "Silvercoat Lion", 2, 2);
assertPowerToughness(playerB, "Pillarfield Ox", 3, 5);
}
@Test
public void testSubtleStrikeBothModes() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
// Choose one or both
// Target creature gets -1/-1 until end of turn.
// Put a +1/+1 counter on target creature.
addCard(Zone.HAND, playerA, "Subtle Strike"); // Instant {1}{B}
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion");
addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Subtle Strike", "Pillarfield Ox");
addTarget(playerA, "Silvercoat Lion");
setModeChoice(playerA, "1");
setModeChoice(playerA, "2");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPowerToughness(playerA, "Silvercoat Lion", 3, 3);
assertPowerToughness(playerB, "Pillarfield Ox", 1, 3);
}
}

View file

@ -0,0 +1,129 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation 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.replacement;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class PanharmoniconTest extends CardTestPlayerBase {
/**
* Check that Panharmonicon adds EtB triggers correctly.
*
*/
@Test
public void testAddsTrigger() {
// If an artifact or creature entering the battlefield causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.
addCard(Zone.BATTLEFIELD, playerA, "Panharmonicon");
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
// Whenever another creature enters the battlefield, you gain 1 life.
addCard(Zone.HAND, playerA, "Soul Warden");
// When Devout Monk enters the battlefield, you gain 1 life.
addCard(Zone.HAND, playerA, "Devout Monk");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Soul Warden");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Devout Monk"); // Life: 20 + 2*1 + 2*1 = 24
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerA, 24);
}
/**
* Check that Panharmonicon doesn't add to opponents' triggers.
*
*/
@Test
public void testDoesntAddOpponentsTriggers() {
// If an artifact or creature entering the battlefield causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.
addCard(Zone.BATTLEFIELD, playerA, "Panharmonicon");
addCard(Zone.BATTLEFIELD, playerB, "Plains", 2);
// Whenever another creature enters the battlefield, you gain 1 life.
addCard(Zone.HAND, playerB, "Soul Warden");
// When Devout Monk enters the battlefield, you gain 1 life.
addCard(Zone.HAND, playerB, "Devout Monk");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Soul Warden");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Devout Monk"); // Life: 20 + 1 + 1 = 22
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerB, 22);
}
/**
* Check that Panharmonicon doesn't add to lands triggers.
*
*/
@Test
public void testDoesntAddLandsTriggers() {
// If an artifact or creature entering the battlefield causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.
addCard(Zone.BATTLEFIELD, playerA, "Panharmonicon");
// When Radiant Fountain enters the battlefield, you gain 2 life.
addCard(Zone.HAND, playerA, "Radiant Fountain");
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Radiant Fountain"); // Life: 20 + 2 = 22
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerA, 22);
}
/**
* Check that Panharmonicon doesn't add to non-permanents triggers.
*
*/
@Test
public void testDoesntAddNonPermanentsTriggers() {
// If an artifact or creature entering the battlefield causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.
addCard(Zone.BATTLEFIELD, playerA, "Panharmonicon");
// When a Dragon enters the battlefield, you may return Bladewing's Thrall from your graveyard to the battlefield.
addCard(Zone.GRAVEYARD, playerA, "Bladewing's Thrall");
// A 4/4 vanilla dragon
addCard(Zone.HAND, playerA, "Scion of Ugin");
addCard(Zone.BATTLEFIELD, playerA, "Plains", 6);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Scion of Ugin");
setChoice(playerA, "No"); // Return Bladewing's Thrall from your graveyard to the battlefield?
setChoice(playerA, "Yes"); // Should not get run since there is only one trigger.
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertGraveyardCount(playerA, "Bladewing's Thrall", 1);
}
}

View file

@ -39,20 +39,22 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
public class BrutalExpulsionTest extends CardTestPlayerBase { public class BrutalExpulsionTest extends CardTestPlayerBase {
/** /**
* Brutal Expulsion targeting Gideon, Ally of Zendikar. Gideon has 3 loyalty. Brutal Expulsion resolves, * Brutal Expulsion targeting Gideon, Ally of Zendikar. Gideon has 3
* leaves 1 loyalty. I attack Gideon for 1 with a Scion token, Gideon dies. Instead of going to graveyard, * loyalty. Brutal Expulsion resolves, leaves 1 loyalty. I attack Gideon for
* Expulsion sends Gideon to exile. However, in game Gideon went to graveyard. * 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 @Test
public void testPlaneswalkerExile() { public void testPlaneswalkerExile() {
// Choose one or both // Choose one or both
// - Return target spell or creature to its owner's hand; // - 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. // 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"); addCard(Zone.HAND, playerA, "Brutal Expulsion"); // {2}{U}{R}
// Shock deals 2 damage to target creature or player. // Shock deals 2 damage to target creature or player.
addCard(Zone.HAND, playerA, "Shock"); addCard(Zone.HAND, playerA, "Shock"); // {R}
addCard(Zone.BATTLEFIELD, playerA, "Island", 4); addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
// Planeswalker with 4 loyalty. // Planeswalker with 4 loyalty.
addCard(Zone.BATTLEFIELD, playerB, "Gideon, Ally of Zendikar"); addCard(Zone.BATTLEFIELD, playerB, "Gideon, Ally of Zendikar");
@ -60,12 +62,12 @@ public class BrutalExpulsionTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Brutal Expulsion", playerB); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Brutal Expulsion", playerB);
setModeChoice(playerA, "2"); setModeChoice(playerA, "2");
setModeChoice(playerA, null); setModeChoice(playerA, null);
setChoice(playerA, "Yes"); setChoice(playerA, "Yes"); // Redirect to planeswalker
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shock", playerB); castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Shock", playerB);
setChoice(playerA, "Yes"); setChoice(playerA, "Yes"); // Redirect to planeswalker
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); setStopAt(1, PhaseStep.END_COMBAT);
execute(); execute();
assertPermanentCount(playerB, "Gideon, Ally of Zendikar", 0); assertPermanentCount(playerB, "Gideon, Ally of Zendikar", 0);

View file

@ -15,24 +15,23 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
* @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
*/ */
public class BroodSliverTest extends CardTestPlayerBase { public class BroodSliverTest extends CardTestPlayerBase {
/* /*
Reported bug: It lets the controller of Brood Sliver choose whether or not the token is created, instead of the attacking Sliver's controller. Reported bug: It lets the controller of Brood Sliver choose whether or not the token is created, instead of the attacking Sliver's controller.
*/ */
@Test @Test
public void testTokenCreatedBySliverController() { public void testTokenCreatedBySliverController() {
// Brood Sliver {4}{G} 3/3 Sliver // Brood Sliver {4}{G} 3/3 Sliver
// Whenever a Sliver deals combat damage to a player, its controller may put a 1/1 colorless Sliver creature token onto the battlefield. // Whenever a Sliver deals combat damage to a player, its controller may put a 1/1 colorless Sliver creature token onto the battlefield.
addCard(Zone.BATTLEFIELD, playerB, "Brood Sliver"); addCard(Zone.BATTLEFIELD, playerB, "Brood Sliver");
addCard(Zone.BATTLEFIELD, playerA, "Venom Sliver"); // 1/1 deathtouch granting sliver addCard(Zone.BATTLEFIELD, playerA, "Venom Sliver"); // 1/1 deathtouch granting sliver
attack(1, playerA, "Venom Sliver"); attack(1, playerA, "Venom Sliver");
setChoice(playerA, "Yes"); // controller of Venom Sliver dealing damage should get the choice to create token setChoice(playerA, "Yes"); // controller of Venom Sliver dealing damage should get the choice to create token
setChoice(playerB, "No"); // Brood Sliver controller should not be given choice in the first place
setStopAt(1, PhaseStep.END_COMBAT); setStopAt(1, PhaseStep.END_COMBAT);
execute(); execute();
assertLife(playerB, 19); assertLife(playerB, 19);
assertPermanentCount(playerA, "Sliver", 1); assertPermanentCount(playerA, "Sliver", 1);
assertPermanentCount(playerB, "Sliver", 0); assertPermanentCount(playerB, "Sliver", 0);

View file

@ -287,7 +287,8 @@ public class TestPlayer implements Player {
} }
UUID modeId = ability.getModes().getModeId(modeNr); UUID modeId = ability.getModes().getModeId(modeNr);
for (Mode mode : ability.getModes().getSelectedModes()) { for (UUID currentModeId : ability.getModes().getSelectedModes()) {
Mode mode = ability.getModes().get(currentModeId);
if (mode.getId().equals(modeId)) { if (mode.getId().equals(modeId)) {
selectedMode = mode; selectedMode = mode;
ability.getModes().setActiveMode(mode); ability.getModes().setActiveMode(mode);

View file

@ -306,7 +306,8 @@ public abstract class AbilityImpl implements Ability {
&& game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL_LATE, getId(), getSourceId(), getControllerId()), this)) { && game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL_LATE, getId(), getSourceId(), getControllerId()), this)) {
return false; return false;
} }
for (Mode mode : this.getModes().getSelectedModes()) { for (UUID modeId : this.getModes().getSelectedModes()) {
Mode mode = this.getModes().get(modeId);
this.getModes().setActiveMode(mode); this.getModes().setActiveMode(mode);
//20121001 - 601.2c //20121001 - 601.2c
// 601.2c The player announces his or her choice of an appropriate player, object, or zone for // 601.2c The player announces his or her choice of an appropriate player, object, or zone for
@ -1060,7 +1061,8 @@ public abstract class AbilityImpl implements Ability {
} }
} else if (object instanceof Spell && ((Spell) object).getSpellAbility().getModes().size() > 1) { } else if (object instanceof Spell && ((Spell) object).getSpellAbility().getModes().size() > 1) {
Modes spellModes = ((Spell) object).getSpellAbility().getModes(); Modes spellModes = ((Spell) object).getSpellAbility().getModes();
for (Mode selectedMode : spellModes.getSelectedModes()) { for (UUID selectedModeId : spellModes.getSelectedModes()) {
Mode selectedMode = spellModes.get(selectedModeId);
int item = 0; int item = 0;
for (Mode mode : spellModes.values()) { for (Mode mode : spellModes.values()) {
item++; item++;

View file

@ -41,7 +41,6 @@ import mage.constants.TargetController;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import mage.util.CardUtil;
/** /**
* *
@ -49,8 +48,8 @@ import mage.util.CardUtil;
*/ */
public class Modes extends LinkedHashMap<UUID, Mode> { public class Modes extends LinkedHashMap<UUID, Mode> {
private Mode mode; // the current mode of the selected modes private Mode currentMode; // the current mode of the selected modes
private final ArrayList<Mode> selectedModes = new ArrayList<>(); private final ArrayList<UUID> selectedModes = new ArrayList<>();
private int minModes; private int minModes;
private int maxModes; private int maxModes;
private TargetController modeChooser; private TargetController modeChooser;
@ -58,11 +57,11 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
private boolean eachModeOnlyOnce; // state if each mode can be chosen only once as long as the source object exists private boolean eachModeOnlyOnce; // state if each mode can be chosen only once as long as the source object exists
public Modes() { public Modes() {
this.mode = new Mode(); this.currentMode = new Mode();
this.put(mode.getId(), mode); this.put(currentMode.getId(), currentMode);
this.minModes = 1; this.minModes = 1;
this.maxModes = 1; this.maxModes = 1;
this.selectedModes.add(mode); this.selectedModes.add(currentMode.getId());
this.modeChooser = TargetController.YOU; this.modeChooser = TargetController.YOU;
this.eachModeOnlyOnce = false; this.eachModeOnlyOnce = false;
this.eachModeMoreThanOnce = false; this.eachModeMoreThanOnce = false;
@ -75,23 +74,8 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
this.minModes = modes.minModes; this.minModes = modes.minModes;
this.maxModes = modes.maxModes; this.maxModes = modes.maxModes;
if (modes.size() == 1) { this.currentMode = values().iterator().next();
this.mode = values().iterator().next(); selectedModes.addAll(modes.getSelectedModes());
this.selectedModes.add(mode);
} else {
// probably there is still a problem with copying modes with the same mode selected multiple times.
for (Mode selectedMode : modes.getSelectedModes()) {
Mode copiedMode = selectedMode.copy();
this.selectedModes.add(copiedMode);
if (modes.getSelectedModes().size() == 1) {
this.mode = copiedMode;
} else {
if (selectedMode.equals(modes.getMode())) {
this.mode = copiedMode;
}
}
}
}
this.modeChooser = modes.modeChooser; this.modeChooser = modes.modeChooser;
this.eachModeOnlyOnce = modes.eachModeOnlyOnce; this.eachModeOnlyOnce = modes.eachModeOnlyOnce;
this.eachModeMoreThanOnce = modes.eachModeMoreThanOnce; this.eachModeMoreThanOnce = modes.eachModeMoreThanOnce;
@ -102,21 +86,21 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
} }
public Mode getMode() { public Mode getMode() {
return mode; return currentMode;
} }
public UUID getModeId(int index) { public UUID getModeId(int index) {
int idx = 0; int idx = 0;
for (Mode currentMode : this.values()) { for (Mode mode : this.values()) {
idx++; idx++;
if (idx == index) { if (idx == index) {
return currentMode.getId(); return mode.getId();
} }
} }
return null; return null;
} }
public ArrayList<Mode> getSelectedModes() { public ArrayList<UUID> getSelectedModes() {
return selectedModes; return selectedModes;
} }
@ -145,8 +129,8 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
} }
public void setActiveMode(Mode mode) { public void setActiveMode(Mode mode) {
if (selectedModes.contains(mode)) { if (selectedModes.contains(mode.getId())) {
this.mode = mode; this.currentMode = mode;
} }
} }
@ -175,7 +159,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
for (Mode mode : this.values()) { for (Mode mode : this.values()) {
if ((!isEachModeOnlyOnce() || onceSelectedModes == null || !onceSelectedModes.contains(mode.getId())) if ((!isEachModeOnlyOnce() || onceSelectedModes == null || !onceSelectedModes.contains(mode.getId()))
&& mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) { && mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) {
this.selectedModes.add(mode.copy()); this.selectedModes.add(mode.getId());
} }
} }
if (isEachModeOnlyOnce()) { if (isEachModeOnlyOnce()) {
@ -203,7 +187,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
Player player = game.getPlayer(playerId); Player player = game.getPlayer(playerId);
// player chooses modes manually // player chooses modes manually
this.mode = null; this.currentMode = null;
while (this.selectedModes.size() < this.getMaxModes()) { while (this.selectedModes.size() < this.getMaxModes()) {
Mode choice = player.chooseMode(this, source, game); Mode choice = player.chooseMode(this, source, game);
if (choice == null) { if (choice == null) {
@ -212,9 +196,9 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
} }
return this.selectedModes.size() >= this.getMinModes(); return this.selectedModes.size() >= this.getMinModes();
} }
this.selectedModes.add(choice.copy()); this.selectedModes.add(choice.getId());
if (mode == null) { if (currentMode == null) {
mode = choice; currentMode = choice;
} }
} }
if (isEachModeOnlyOnce()) { if (isEachModeOnlyOnce()) {
@ -222,10 +206,10 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
} }
return true; return true;
} }
if (mode == null) { if (currentMode == null) {
this.selectedModes.clear(); this.selectedModes.clear();
Mode copiedMode = this.values().iterator().next().copy(); Mode copiedMode = this.values().iterator().next().copy();
this.selectedModes.add(copiedMode); this.selectedModes.add(copiedMode.getId());
this.setActiveMode(copiedMode); this.setActiveMode(copiedMode);
} }
if (isEachModeOnlyOnce()) { if (isEachModeOnlyOnce()) {
@ -234,27 +218,46 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
return true; return true;
} }
private void setAlreadySelectedModes(ArrayList<Mode> selectedModes, Ability source, Game game) { /**
String key = getKey(source, game); * Saves the already selected modes to the state value
Set<UUID> onceSelectedModes = (Set<UUID>) game.getState().getValue(key); *
if (onceSelectedModes == null) { * @param selectedModes
onceSelectedModes = new HashSet<>(); * @param source
* @param game
*/
private void setAlreadySelectedModes(ArrayList<UUID> selectedModes, Ability source, Game game) {
for (UUID modeId : selectedModes) {
String key = getKey(source, game, modeId);
game.getState().setValue(key, true);
} }
for (Mode mode : selectedModes) {
onceSelectedModes.add(mode.getId());
}
game.getState().setValue(key, onceSelectedModes);
} }
// The already once selected modes for a modal card are stored as a state value
// That's important for modal abilities with modes that can only selected once while the object stays in its zone
@SuppressWarnings("unchecked")
private Set<UUID> getAlreadySelectedModes(Ability source, Game game) { private Set<UUID> getAlreadySelectedModes(Ability source, Game game) {
return (Set<UUID>) game.getState().getValue(getKey(source, game)); Set<UUID> onceSelectedModes = new HashSet<>();
for (UUID modeId : this.keySet()) {
Object exist = game.getState().getValue(getKey(source, game, modeId));
if (exist != null) {
onceSelectedModes.add(modeId);
}
}
return onceSelectedModes;
} }
private String getKey(Ability source, Game game) { // creates the key the selected modes are saved with to the state values
return CardUtil.getObjectZoneString("selectedModes", source.getSourceId(), game, game.getState().getZoneChangeCounter(source.getSourceId()), false); private String getKey(Ability source, Game game, UUID modeId) {
return source.getSourceId().toString() + game.getState().getZoneChangeCounter(source.getSourceId()) + modeId.toString();
} }
/**
* Returns all (still) available modes of the ability
*
* @param source
* @param game
* @return
*/
public List<Mode> getAvailableModes(Ability source, Game game) { public List<Mode> getAvailableModes(Ability source, Game game) {
List<Mode> availableModes = new ArrayList<>(); List<Mode> availableModes = new ArrayList<>();
Set<UUID> nonAvailableModes; Set<UUID> nonAvailableModes;

View file

@ -56,6 +56,9 @@ public abstract class StaticAbility extends AbilityImpl {
if (game.getShortLivingLKI(getSourceId(), zone)) { if (game.getShortLivingLKI(getSourceId(), zone)) {
return true; // maybe this can be a problem if effects removed the ability from the object return true; // maybe this can be a problem if effects removed the ability from the object
} }
if (game.getPermanentEntering(getSourceId()) != null && zone.equals(Zone.BATTLEFIELD)) {
return true; // abilities of permanents entering battlefield are countes as on battlefield
}
return super.isInUseableZone(game, source, event); return super.isInUseableZone(game, source, event);
} }

View file

@ -41,6 +41,7 @@ import mage.cards.Card;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.events.NumberOfTriggersEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.stack.Spell; import mage.game.stack.Spell;
@ -124,7 +125,12 @@ public class TriggeredAbilities extends ConcurrentHashMap<String, TriggeredAbili
} }
if (ability.checkTrigger(event, game)) { if (ability.checkTrigger(event, game)) {
ability.trigger(game, ability.getControllerId()); NumberOfTriggersEvent numberOfTriggersEvent = new NumberOfTriggersEvent(ability.getControllerId(), ability.getSourceId(), event);
if (!game.replaceEvent(numberOfTriggersEvent)) {
for (int i = 0; i < numberOfTriggersEvent.getAmount(); i++) {
ability.trigger(game, ability.getControllerId());
}
}
} }
} }
} }

View file

@ -29,6 +29,7 @@ package mage.abilities.common;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.constants.SetTargetPointer;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.events.DamagedPlayerEvent; import mage.game.events.DamagedPlayerEvent;
@ -41,7 +42,8 @@ import mage.target.targetpointer.FixedTarget;
*/ */
public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbilityImpl { public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbilityImpl {
private boolean setTargetPointer; protected boolean setTargetPointer;
protected String text;
public DealsCombatDamageToAPlayerTriggeredAbility(Effect effect, boolean optional) { public DealsCombatDamageToAPlayerTriggeredAbility(Effect effect, boolean optional) {
this(effect, optional, false); this(effect, optional, false);
@ -52,8 +54,15 @@ public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbility
this.setTargetPointer = setTargetPointer; this.setTargetPointer = setTargetPointer;
} }
public DealsCombatDamageToAPlayerTriggeredAbility(Effect effect, boolean optional, String text, boolean setTargetPointer) {
super(Zone.BATTLEFIELD, effect, optional);
this.text = text;
this.setTargetPointer = setTargetPointer;
}
public DealsCombatDamageToAPlayerTriggeredAbility(final DealsCombatDamageToAPlayerTriggeredAbility ability) { public DealsCombatDamageToAPlayerTriggeredAbility(final DealsCombatDamageToAPlayerTriggeredAbility ability) {
super(ability); super(ability);
this.text = ability.text;
this.setTargetPointer = ability.setTargetPointer; this.setTargetPointer = ability.setTargetPointer;
} }
@ -84,7 +93,10 @@ public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbility
@Override @Override
public String getRule() { public String getRule() {
return "Whenever {this} deals combat damage to a player, " + super.getRule(); if (text == null || text.isEmpty()) {
return "Whenever {this} deals combat damage to a player, " + super.getRule();
}
return text;
} }
} }

View file

@ -73,12 +73,11 @@ public class DealsDamageToAPlayerAllTriggeredAbility extends TriggeredAbilityImp
} }
@Override @Override
public boolean checkTrigger(GameEvent event, Game game) { public boolean checkTrigger(GameEvent event, Game game) {
if (!onlyCombat || ((DamagedPlayerEvent) event).isCombatDamage()) { if (!onlyCombat || ((DamagedPlayerEvent) event).isCombatDamage()) {
Permanent permanent = game.getPermanent(event.getSourceId()); Permanent permanent = game.getPermanent(event.getSourceId());
if (permanent != null) { if (permanent != null) {
controllerId = permanent.getControllerId(); if (filter.match(permanent, getSourceId(), getControllerId(), game)) {
if (filter.match(permanent, sourceId, controllerId, game)) {
if (!setTargetPointer.equals(SetTargetPointer.NONE)) { if (!setTargetPointer.equals(SetTargetPointer.NONE)) {
for (Effect effect : this.getEffects()) { for (Effect effect : this.getEffects()) {
effect.setValue("damage", event.getAmount()); effect.setValue("damage", event.getAmount());

View file

@ -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.abilities.common;
import java.util.UUID;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
/**
*
* @author Styxo
*/
public class LeavesBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl {
protected FilterPermanent filter;
public LeavesBattlefieldAllTriggeredAbility(Effect effect, FilterPermanent filter) {
this(effect, filter, false);
}
public LeavesBattlefieldAllTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional) {
this(Zone.BATTLEFIELD, effect, filter, optional);
}
public LeavesBattlefieldAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional) {
super(zone, effect, optional);
this.filter = filter;
}
public LeavesBattlefieldAllTriggeredAbility(final LeavesBattlefieldAllTriggeredAbility ability) {
super(ability);
filter = ability.filter;
}
@Override
public LeavesBattlefieldAllTriggeredAbility copy() {
return new LeavesBattlefieldAllTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
UUID targetId = event.getTargetId();
Permanent permanent = game.getPermanentOrLKIBattlefield(targetId);
if (permanent != null) {
return filter.match(permanent, getSourceId(), getControllerId(), game);
}
}
return false;
}
@Override
public String getRule() {
return "Whenever " + filter.getMessage() + " leaves the battlefield, " + super.getRule();
}
}

View file

@ -51,7 +51,8 @@ public class ChangeATargetOfTargetSpellAbilityToSourceEffect extends OneShotEffe
} else { } else {
return false; return false;
} }
for (Mode mode : sourceAbility.getModes().getSelectedModes()) { for (UUID modeId : sourceAbility.getModes().getSelectedModes()) {
Mode mode = sourceAbility.getModes().get(modeId);
targets.addAll(mode.getTargets()); targets.addAll(mode.getTargets());
} }
@ -102,12 +103,10 @@ public class ChangeATargetOfTargetSpellAbilityToSourceEffect extends OneShotEffe
} }
if (oldTargetName != null) { if (oldTargetName != null) {
game.informPlayers(sourceObject.getLogName() + ": Changed target of " + stackObject.getLogName() + " from " + oldTargetName + " to " + sourceObject.getLogName()); game.informPlayers(sourceObject.getLogName() + ": Changed target of " + stackObject.getLogName() + " from " + oldTargetName + " to " + sourceObject.getLogName());
} else if (twoTimesTarget) {
game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its not valid to target it twice for " + stackObject.getLogName());
} else { } else {
if (twoTimesTarget) { game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its no valid target for " + stackObject.getLogName());
game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its not valid to target it twice for " + stackObject.getLogName());
} else {
game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its no valid target for " + stackObject.getLogName());
}
} }
return true; return true;
} }

View file

@ -104,6 +104,10 @@ public class CopyEffect extends ContinuousEffectImpl {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
if (affectedObjectList.isEmpty()) {
this.discard();
return false;
}
Permanent permanent = affectedObjectList.get(0).getPermanent(game); Permanent permanent = affectedObjectList.get(0).getPermanent(game);
if (permanent == null) { if (permanent == null) {
permanent = (Permanent) game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD, source.getSourceObjectZoneChangeCounter()); permanent = (Permanent) game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD, source.getSourceObjectZoneChangeCounter());

View file

@ -111,13 +111,13 @@ public class PutTopCardOfLibraryIntoGraveEachPlayerEffect extends OneShotEffect
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
switch (targetController) { switch (targetController) {
case OPPONENT: case OPPONENT:
sb.append("Each opponent "); sb.append("each opponent ");
break; break;
case ANY: case ANY:
sb.append("Each player "); sb.append("each player ");
break; break;
case NOT_YOU: case NOT_YOU:
sb.append("Each other player "); sb.append("each other player ");
break; break;
default: default:
throw new UnsupportedOperationException("TargetController type not supported."); throw new UnsupportedOperationException("TargetController type not supported.");

View file

@ -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.abilities.effects.common;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.game.Game;
import mage.players.Player;
/**
*
* @author Styxo
*/
public class SetPlayerLifeTargetEffect extends OneShotEffect {
protected DynamicValue amount;
public SetPlayerLifeTargetEffect(int amount) {
this(new StaticValue(amount));
}
public SetPlayerLifeTargetEffect(DynamicValue amount) {
super(Outcome.Neutral);
this.amount = amount;
this.staticText = setText();
}
public SetPlayerLifeTargetEffect(final SetPlayerLifeTargetEffect effect) {
super(effect);
this.amount = effect.amount;
}
@Override
public SetPlayerLifeTargetEffect copy() {
return new SetPlayerLifeTargetEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(targetPointer.getFirst(game, source));
if (player != null) {
player.setLife(amount.calculate(game, source, this), game);
return true;
}
return false;
}
private String setText() {
StringBuilder sb = new StringBuilder("Target player's life total becomes ");
sb.append(amount.toString());
return sb.toString();
}
}

View file

@ -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.abilities.effects.common.ruleModifying;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.events.GameEvent;
/**
*
* @author Styxo
*/
public class CantHaveCountersSourceEffect extends ContinuousRuleModifyingEffectImpl {
public CantHaveCountersSourceEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment);
staticText = "{this} can't have counters placed on it";
}
public CantHaveCountersSourceEffect(final CantHaveCountersSourceEffect effect) {
super(effect);
}
@Override
public CantHaveCountersSourceEffect copy() {
return new CantHaveCountersSourceEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ADD_COUNTERS;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
UUID sourceId = source.getSourceId();
if (sourceId != null) {
return sourceId.equals(event.getTargetId());
}
return false;
}
}

View file

@ -122,7 +122,10 @@ class CrewCost extends CostImpl {
public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
int sumPower = 0; int sumPower = 0;
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, controllerId, game)) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, controllerId, game)) {
sumPower += permanent.getPower().getValue(); int powerToAdd = permanent.getPower().getValue();
if (powerToAdd > 0) {
sumPower += powerToAdd;
}
if (sumPower >= value) { if (sumPower >= value) {
return true; return true;
} }

View file

@ -1,4 +1,4 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
@ -82,7 +82,8 @@ public class HeroicAbility extends TriggeredAbilityImpl {
private boolean checkSpell(Spell spell, Game game) { private boolean checkSpell(Spell spell, Game game) {
if (spell != null) { if (spell != null) {
SpellAbility sa = spell.getSpellAbility(); SpellAbility sa = spell.getSpellAbility();
for (Mode mode : sa.getModes().getSelectedModes()) { for (UUID modeId : sa.getModes().getSelectedModes()) {
Mode mode = sa.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
if (!target.isNotTarget() && target.getTargets().contains(this.getSourceId())) { if (!target.isNotTarget() && target.getTargets().contains(this.getSourceId())) {
return true; return true;

View file

@ -29,7 +29,6 @@ package mage.cards;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.util.*; import java.util.*;
import mage.MageObject; import mage.MageObject;
import mage.MageObjectImpl; import mage.MageObjectImpl;
import mage.Mana; import mage.Mana;
@ -53,10 +52,8 @@ import mage.game.command.Commander;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent; import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentCard;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.game.stack.StackObject; import mage.game.stack.StackObject;
import mage.players.Player;
import mage.util.GameLog; import mage.util.GameLog;
import mage.watchers.Watcher; import mage.watchers.Watcher;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
@ -315,11 +312,11 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
public String getTokenSetCode() { public String getTokenSetCode() {
return tokenSetCode; return tokenSetCode;
} }
@Override @Override
public String getTokenDescriptor() { public String getTokenDescriptor() {
return tokenDescriptor; return tokenDescriptor;
} }
@Override @Override
public List<Mana> getMana() { public List<Mana> getMana() {
@ -342,22 +339,29 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
Zone fromZone = game.getState().getZone(objectId); Zone fromZone = game.getState().getZone(objectId);
ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, sourceId, ownerId, fromZone, toZone, appliedEffects); ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, sourceId, ownerId, fromZone, toZone, appliedEffects);
ZoneChangeInfo zoneChangeInfo; ZoneChangeInfo zoneChangeInfo;
if (toZone == Zone.LIBRARY) { if (null != toZone) {
zoneChangeInfo = new ZoneChangeInfo.Library(event, flag /* put on top */); switch (toZone) {
} else if (toZone == Zone.BATTLEFIELD) { case LIBRARY:
zoneChangeInfo = new ZoneChangeInfo.Battlefield(event, flag /* comes into play tapped */); zoneChangeInfo = new ZoneChangeInfo.Library(event, flag /* put on top */);
} else { break;
zoneChangeInfo = new ZoneChangeInfo(event); case BATTLEFIELD:
zoneChangeInfo = new ZoneChangeInfo.Battlefield(event, flag /* comes into play tapped */);
break;
default:
zoneChangeInfo = new ZoneChangeInfo(event);
break;
}
return ZonesHandler.moveCard(zoneChangeInfo, game);
} }
return ZonesHandler.moveCard(zoneChangeInfo, game); return false;
} }
@Override @Override
public boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId) { public boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId) {
Card mainCard = getMainCard(); Card mainCard = getMainCard();
ZoneChangeEvent event = new ZoneChangeEvent(mainCard.getId(), ability.getId(), controllerId, fromZone, Zone.STACK); ZoneChangeEvent event = new ZoneChangeEvent(mainCard.getId(), ability.getId(), controllerId, fromZone, Zone.STACK);
ZoneChangeInfo.Stack info = ZoneChangeInfo.Stack info
new ZoneChangeInfo.Stack(event, new Spell(this, ability.copy(), controllerId, event.getFromZone())); = new ZoneChangeInfo.Stack(event, new Spell(this, ability.copy(), controllerId, event.getFromZone()));
return ZonesHandler.cast(info, game); return ZonesHandler.cast(info, game);
} }
@ -449,6 +453,9 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
} else if (game.getPlayer(ownerId).getSideboard().contains(this.getId())) { } else if (game.getPlayer(ownerId).getSideboard().contains(this.getId())) {
game.getPlayer(ownerId).getSideboard().remove(this.getId()); game.getPlayer(ownerId).getSideboard().remove(this.getId());
removed = true; removed = true;
} else if (game.getPhase() == null) {
// E.g. Commander of commander game
removed = true;
} }
break; break;
case BATTLEFIELD: // for sacrificing permanents or putting to library case BATTLEFIELD: // for sacrificing permanents or putting to library
@ -461,7 +468,9 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
break; break;
} }
if (removed) { if (removed) {
game.rememberLKI(lkiObject != null ? lkiObject.getId() : objectId, fromZone, lkiObject != null ? lkiObject : this); if (!fromZone.equals(Zone.OUTSIDE)) {
game.rememberLKI(lkiObject != null ? lkiObject.getId() : objectId, fromZone, lkiObject != null ? lkiObject : this);
}
} else { } else {
logger.warn("Couldn't find card in fromZone, card=" + getIdName() + ", fromZone=" + fromZone); logger.warn("Couldn't find card in fromZone, card=" + getIdName() + ", fromZone=" + fromZone);
} }
@ -598,7 +607,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
returnCode = false; returnCode = false;
} }
} }
if(finalAmount > 0) { if (finalAmount > 0) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.COUNTERS_ADDED, objectId, getControllerOrOwner(), counter.getName(), amount)); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.COUNTERS_ADDED, objectId, getControllerOrOwner(), counter.getName(), amount));
} }
} else { } else {
@ -656,7 +665,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
} }
return super.getColor(game); return super.getColor(game);
} }
@Override @Override
public List<String> getSubtype(Game game) { public List<String> getSubtype(Game game) {
if (game != null) { if (game != null) {

View file

@ -27,6 +27,7 @@
*/ */
package mage.filter.predicate.mageobject; package mage.filter.predicate.mageobject;
import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Mode; import mage.abilities.Mode;
import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicate;
@ -51,7 +52,8 @@ public class NumberOfTargetsPredicate implements Predicate<MageObject> {
StackObject stackObject = game.getState().getStack().getStackObject(input.getId()); StackObject stackObject = game.getState().getStack().getStackObject(input.getId());
if (stackObject != null) { if (stackObject != null) {
int numberOfTargets = 0; int numberOfTargets = 0;
for (Mode mode : stackObject.getStackAbility().getModes().getSelectedModes()) { for (UUID modeId : stackObject.getStackAbility().getModes().getSelectedModes()) {
Mode mode = stackObject.getStackAbility().getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
numberOfTargets += target.getTargets().size(); numberOfTargets += target.getTargets().size();
} }

Some files were not shown because too many files have changed in this diff Show more