Merge branch 'magefree/master'
|
@ -27,7 +27,7 @@ public class MageRoundPane extends JPanel {
|
|||
|
||||
private int X_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 final int alpha = 0;
|
||||
private static Map<ShadowKey, BufferedImage> SHADOW_IMAGE_CACHE;
|
||||
|
|
|
@ -201,7 +201,16 @@
|
|||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnSubmitActionPerformed"/>
|
||||
</Events>
|
||||
</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 class="javax.swing.JTextField" name="txtTimeRemaining">
|
||||
</Component>
|
||||
|
|
|
@ -27,6 +27,25 @@
|
|||
*/
|
||||
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.Sets;
|
||||
import mage.cards.decks.Deck;
|
||||
|
@ -39,8 +58,8 @@ import mage.client.SessionHandler;
|
|||
import mage.client.cards.BigCard;
|
||||
import mage.client.cards.ICardGrid;
|
||||
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;
|
||||
import mage.client.dialog.AddLandDialog;
|
||||
import mage.client.plugins.impl.Plugins;
|
||||
import mage.client.util.Event;
|
||||
|
@ -52,22 +71,6 @@ import mage.remote.Session;
|
|||
import mage.view.CardView;
|
||||
import mage.view.SimpleCardView;
|
||||
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
|
||||
|
@ -84,6 +87,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
private int timeout;
|
||||
private Timer countdown;
|
||||
private UpdateDeckTask updateDeckTask;
|
||||
private int timeToSubmit = -1;
|
||||
|
||||
/**
|
||||
* Creates new form DeckEditorPanel
|
||||
|
@ -160,6 +164,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
this.txtTimeRemaining.setVisible(true);
|
||||
case SIDEBOARDING:
|
||||
this.btnSubmit.setVisible(true);
|
||||
this.btnSubmitTimer.setVisible(true);
|
||||
if (deck != null) {
|
||||
this.cardSelector.loadSideboard(new ArrayList<>(deck.getSideboard()), this.bigCard);
|
||||
}
|
||||
|
@ -187,6 +192,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
case FREE_BUILDING:
|
||||
this.deckArea.setOrientation(/*limitedBuildingOrientation = */false);
|
||||
this.btnSubmit.setVisible(false);
|
||||
this.btnSubmitTimer.setVisible(false);
|
||||
this.btnAddLand.setVisible(true);
|
||||
this.cardSelector.loadCards(this.bigCard);
|
||||
//this.cardTableSelector.loadCards(this.bigCard);
|
||||
|
@ -484,6 +490,11 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
if (s == 60) {
|
||||
AudioManager.playOnCountdown1();
|
||||
}
|
||||
if (timeToSubmit > 0) {
|
||||
timeToSubmit --;
|
||||
btnSubmitTimer.setText("Submit (" + timeToSubmit + ")");
|
||||
btnSubmitTimer.setToolTipText("Submit your deck in " + timeToSubmit + " seconds!");
|
||||
}
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
|
@ -501,6 +512,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
btnExit = new javax.swing.JButton();
|
||||
btnImport = new javax.swing.JButton();
|
||||
btnSubmit = new javax.swing.JButton();
|
||||
btnSubmitTimer = new javax.swing.JButton();
|
||||
btnAddLand = new javax.swing.JButton();
|
||||
btnGenDeck = new javax.swing.JButton();
|
||||
txtTimeRemaining = new javax.swing.JTextField();
|
||||
|
@ -594,6 +606,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
});
|
||||
|
||||
btnSubmit.setText("Submit");
|
||||
btnSubmitTimer.setToolTipText("Submit your deck now!");
|
||||
btnSubmit.setName("btnSubmit"); // NOI18N
|
||||
btnSubmit.addActionListener(new java.awt.event.ActionListener() {
|
||||
@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.setName("btnAddLand"); // NOI18N
|
||||
btnAddLand.addActionListener(new java.awt.event.ActionListener() {
|
||||
|
@ -610,7 +633,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
btnAddLandActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
btnGenDeck.setText("Generate");
|
||||
btnGenDeck.setName("btnGenDeck");
|
||||
btnGenDeck.addActionListener(new java.awt.event.ActionListener() {
|
||||
|
@ -658,7 +681,9 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
.addContainerGap()
|
||||
.addComponent(btnAddLand)
|
||||
.addContainerGap()
|
||||
.addComponent(btnSubmit))
|
||||
.addComponent(btnSubmit)
|
||||
.addContainerGap()
|
||||
.addComponent(btnSubmitTimer))
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(txtTimeRemaining))
|
||||
|
@ -682,7 +707,8 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
.addComponent(btnImport)
|
||||
.addComponent(btnGenDeck)
|
||||
.addComponent(btnAddLand)
|
||||
.addComponent(btnSubmit))
|
||||
.addComponent(btnSubmit)
|
||||
.addComponent(btnSubmitTimer))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(txtTimeRemaining))
|
||||
|
@ -847,6 +873,26 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
}
|
||||
}//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
|
||||
AddLandDialog addLand = new AddLandDialog();
|
||||
addLand.showDialog(deck, mode);
|
||||
|
@ -867,7 +913,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
}
|
||||
refreshDeck();
|
||||
}
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private mage.client.cards.BigCard bigCard;
|
||||
private javax.swing.JButton btnExit;
|
||||
|
@ -882,6 +928,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
private javax.swing.JLabel lblDeckName;
|
||||
private javax.swing.JTextField txtDeckName;
|
||||
private javax.swing.JButton btnSubmit;
|
||||
private javax.swing.JButton btnSubmitTimer;
|
||||
private javax.swing.JButton btnAddLand;
|
||||
private javax.swing.JButton btnGenDeck;
|
||||
private JComponent cardInfoPane;
|
||||
|
|
|
@ -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) {
|
||||
if (turn) { //F4
|
||||
btnSkipToNextTurn.setBorder(new LineBorder(Color.red, BORDER_SIZE));
|
||||
btnSkipToNextTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE));
|
||||
} else {
|
||||
btnSkipToNextTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE));
|
||||
}
|
||||
if (endOfTurn) { // F5
|
||||
btnSkipToEndTurn.setBorder(new LineBorder(Color.red, BORDER_SIZE));
|
||||
btnSkipToEndTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE));
|
||||
} else {
|
||||
btnSkipToEndTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE));
|
||||
}
|
||||
if (nextMain) { // F7
|
||||
btnSkipToNextMain.setBorder(new LineBorder(Color.red, BORDER_SIZE));
|
||||
btnSkipToNextMain.setBorder(new LineBorder(Color.orange, BORDER_SIZE));
|
||||
} else {
|
||||
btnSkipToNextMain.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE));
|
||||
}
|
||||
if (stack) { // F8
|
||||
btnSkipStack.setBorder(new LineBorder(Color.red, BORDER_SIZE));
|
||||
btnSkipStack.setBorder(new LineBorder(Color.orange, BORDER_SIZE));
|
||||
} else {
|
||||
btnSkipStack.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE));
|
||||
}
|
||||
if (allTurns) { // F9
|
||||
btnSkipToYourTurn.setBorder(new LineBorder(Color.red, BORDER_SIZE));
|
||||
btnSkipToYourTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE));
|
||||
} else {
|
||||
btnSkipToYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE));
|
||||
}
|
||||
|
||||
if (endStepBeforeYourStep) { // F11
|
||||
btnSkipToEndStepBeforeYourTurn.setBorder(new LineBorder(Color.red, BORDER_SIZE));
|
||||
btnSkipToEndStepBeforeYourTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE));
|
||||
} else {
|
||||
btnSkipToEndStepBeforeYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE));
|
||||
}
|
||||
|
|
|
@ -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 RED_BORDER = new LineBorder(Color.red, 2);
|
||||
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 deadBackgroundColor = new Color(200, 180, 180, 200);
|
||||
private final Color greenBackgroundColor = new Color(206, 192, 174, 200);
|
||||
private final Color deadBackgroundColor = new Color(131, 94, 83, 200);
|
||||
|
||||
private int avatarId = -1;
|
||||
private String flagName;
|
||||
|
@ -430,7 +430,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
|
|||
|
||||
// Poison count
|
||||
poisonLabel.setText("0");
|
||||
r = new Rectangle(14, 14);
|
||||
r = new Rectangle(18, 18);
|
||||
poisonLabel.setToolTipText("Poison");
|
||||
Image imagePoison = ImageHelper.getImageFromResources("/info/poison.png");
|
||||
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)
|
||||
.addGroup(gl_panelBackground.createParallelGroup(Alignment.LEADING)
|
||||
.addGroup(gl_panelBackground.createSequentialGroup()
|
||||
.addGap(3)
|
||||
.addComponent(poison, GroupLayout.PREFERRED_SIZE, 14, GroupLayout.PREFERRED_SIZE))
|
||||
.addComponent(poison, GroupLayout.PREFERRED_SIZE, 18, GroupLayout.PREFERRED_SIZE))
|
||||
.addGroup(gl_panelBackground.createSequentialGroup()
|
||||
.addGap(2)
|
||||
.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))
|
||||
// .addGroup(gl_panelBackground.createSequentialGroup()
|
||||
// .addComponent(avatarFlag, GroupLayout.PREFERRED_SIZE, 16, GroupLayout.PREFERRED_SIZE))
|
||||
.addGap(14))
|
||||
.addGap(8))
|
||||
.addGroup(gl_panelBackground.createSequentialGroup()
|
||||
.addGap(6)
|
||||
.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)
|
||||
.addComponent(btnPlayer)
|
||||
.addComponent(timerLabel)
|
||||
.addGap(1)
|
||||
.addGap(2)
|
||||
// Life & Hand
|
||||
.addGroup(gl_panelBackground.createParallelGroup(Alignment.LEADING)
|
||||
.addGroup(gl_panelBackground.createSequentialGroup()
|
||||
|
@ -749,15 +748,15 @@ public class PlayerPanelExt extends javax.swing.JPanel {
|
|||
// Poison
|
||||
.addGroup(gl_panelBackground.createParallelGroup(Alignment.LEADING)
|
||||
.addGroup(gl_panelBackground.createSequentialGroup()
|
||||
.addGap(4)
|
||||
.addComponent(poison, GroupLayout.PREFERRED_SIZE, 14, GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(2)
|
||||
.addComponent(poison, GroupLayout.PREFERRED_SIZE, 18, GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(4)
|
||||
.addComponent(btnWhiteMana, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(2)
|
||||
.addComponent(btnBlueMana, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(2)
|
||||
.addComponent(btnBlackMana, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(5)
|
||||
.addGap(3)
|
||||
.addComponent(grave, GroupLayout.PREFERRED_SIZE, 21, GroupLayout.PREFERRED_SIZE)
|
||||
)
|
||||
.addGroup(gl_panelBackground.createSequentialGroup()
|
||||
|
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 926 B After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 721 B After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 470 B After Width: | Height: | Size: 21 KiB |
|
@ -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_MINOR = 4;
|
||||
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 = "";
|
||||
|
||||
private final int major;
|
||||
|
|
|
@ -30,7 +30,6 @@ package mage.view;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Mode;
|
||||
|
@ -55,7 +54,6 @@ import mage.game.stack.Spell;
|
|||
import mage.game.stack.StackAbility;
|
||||
import mage.target.Target;
|
||||
import mage.target.Targets;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
|
@ -81,7 +79,7 @@ public class CardView extends SimpleCardView {
|
|||
protected List<String> manaCost;
|
||||
protected int convertedManaCost;
|
||||
protected Rarity rarity;
|
||||
|
||||
|
||||
protected MageObjectType mageObjectType = MageObjectType.NULL;
|
||||
|
||||
protected boolean isAbility;
|
||||
|
@ -323,7 +321,8 @@ public class CardView extends SimpleCardView {
|
|||
this.mageObjectType = MageObjectType.SPELL;
|
||||
Spell spell = (Spell) card;
|
||||
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) {
|
||||
setTargets(spellAbility.getTargets());
|
||||
}
|
||||
|
@ -331,18 +330,19 @@ public class CardView extends SimpleCardView {
|
|||
}
|
||||
// show for modal spell, which mode was choosen
|
||||
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>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Frame color
|
||||
this.frameColor = card.getFrameColor(game);
|
||||
|
||||
// Frame style
|
||||
this.frameStyle = card.getFrameStyle();
|
||||
|
||||
|
||||
// Get starting loyalty
|
||||
this.startingLoyalty = "" + card.getStartingLoyalty();
|
||||
}
|
||||
|
@ -355,7 +355,7 @@ public class CardView extends SimpleCardView {
|
|||
this.mageObjectType = MageObjectType.PERMANENT;
|
||||
this.power = Integer.toString(object.getPower().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 {
|
||||
this.power = object.getPower().toString();
|
||||
this.toughness = object.getToughness().toString();
|
||||
|
@ -488,7 +488,7 @@ public class CardView extends SimpleCardView {
|
|||
this.rarity = Rarity.NA;
|
||||
this.type = token.getTokenType();
|
||||
this.tokenDescriptor = token.getTokenDescriptor();
|
||||
this.tokenSetCode = token.getOriginalExpansionSetCode();
|
||||
this.tokenSetCode = token.getOriginalExpansionSetCode();
|
||||
}
|
||||
|
||||
protected final void setTargets(Targets targets) {
|
||||
|
@ -547,7 +547,7 @@ public class CardView extends SimpleCardView {
|
|||
public String getLoyalty() {
|
||||
return loyalty;
|
||||
}
|
||||
|
||||
|
||||
public String getStartingLoyalty() {
|
||||
return startingLoyalty;
|
||||
}
|
||||
|
@ -567,7 +567,7 @@ public class CardView extends SimpleCardView {
|
|||
public ObjectColor getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
public ObjectColor getFrameColor() {
|
||||
return frameColor;
|
||||
}
|
||||
|
@ -807,4 +807,3 @@ public class CardView extends SimpleCardView {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -99,7 +99,8 @@ public class StackAbilityView extends CardView {
|
|||
|
||||
private void updateTargets(Game game, StackAbility ability) {
|
||||
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) {
|
||||
setTargets(mode.getTargets());
|
||||
} else {
|
||||
|
@ -132,7 +133,8 @@ public class StackAbilityView extends CardView {
|
|||
// show for modal ability, which mode was choosen
|
||||
if (ability.isModal()) {
|
||||
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>");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1516,7 +1516,8 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
//TODO: improve this;
|
||||
AvailableMode:
|
||||
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())) {
|
||||
continue AvailableMode;
|
||||
}
|
||||
|
|
|
@ -730,11 +730,14 @@ public class HumanPlayer extends PlayerImpl {
|
|||
}
|
||||
|
||||
private boolean checkPassStep(Game game) {
|
||||
if (playerId.equals(game.getActivePlayerId())) {
|
||||
return !this.getUserData().getUserSkipPrioritySteps().getYourTurn().isPhaseStepSet(game.getStep().getType());
|
||||
} else {
|
||||
return !this.getUserData().getUserSkipPrioritySteps().getOpponentTurn().isPhaseStepSet(game.getStep().getType());
|
||||
if (game.getStep() != null) {
|
||||
if (playerId.equals(game.getActivePlayerId())) {
|
||||
return !this.getUserData().getUserSkipPrioritySteps().getYourTurn().isPhaseStepSet(game.getStep().getType());
|
||||
} else {
|
||||
return !this.getUserData().getUserSkipPrioritySteps().getOpponentTurn().isPhaseStepSet(game.getStep().getType());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1323,7 +1326,8 @@ public class HumanPlayer extends PlayerImpl {
|
|||
AvailableModes:
|
||||
for (Mode mode : modes.getAvailableModes(source, game)) {
|
||||
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 (modes.isEachModeMoreThanOnce()) {
|
||||
timesSelected++;
|
||||
|
|
|
@ -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 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 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 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"/>
|
||||
|
|
|
@ -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 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 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 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"/>
|
||||
|
|
|
@ -567,7 +567,7 @@ public class TableController {
|
|||
String creator = null;
|
||||
StringBuilder opponent = new StringBuilder();
|
||||
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());
|
||||
if (user != null) {
|
||||
user.ccGameStarted(match.getGame().getId(), entry.getValue());
|
||||
|
|
|
@ -104,7 +104,8 @@ class ZadaHedronGrinderTriggeredAbility extends TriggeredAbilityImpl {
|
|||
if (isControlledInstantOrSorcery(spell)) {
|
||||
boolean targetsSource = false;
|
||||
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()) {
|
||||
if (!target.isNotTarget()) {
|
||||
for (UUID targetId : target.getTargets()) {
|
||||
|
@ -167,7 +168,8 @@ class ZadaHedronGrinderEffect extends OneShotEffect {
|
|||
Target usedTarget = null;
|
||||
setUsedTarget:
|
||||
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()) {
|
||||
if (!target.isNotTarget() && target.getFirstTarget().equals(source.getSourceId())) {
|
||||
usedTarget = target.copy();
|
||||
|
@ -185,7 +187,8 @@ class ZadaHedronGrinderEffect extends OneShotEffect {
|
|||
Spell copy = spell.copySpell(source.getControllerId());
|
||||
game.getStack().push(copy);
|
||||
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()) {
|
||||
if (target.getClass().equals(usedTarget.getClass())) {
|
||||
target.clearChosen(); // For targets with Max > 1 we need to clear before the text is comapred
|
||||
|
|
|
@ -28,8 +28,6 @@
|
|||
package mage.sets.championsofkamigawa;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.constants.*;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldAbility;
|
||||
|
@ -40,15 +38,17 @@ import mage.abilities.condition.common.SourceHasCounterCondition;
|
|||
import mage.abilities.costs.common.RemoveCountersSourceCost;
|
||||
import mage.abilities.decorator.ConditionalContinuousEffect;
|
||||
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.counter.AddCountersSourceEffect;
|
||||
import mage.abilities.keyword.IndestructibleAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardsImpl;
|
||||
import mage.constants.*;
|
||||
import mage.counters.CounterType;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.predicate.mageobject.CardTypePredicate;
|
||||
import mage.filter.predicate.other.OwnerPredicate;
|
||||
import mage.filter.common.FilterCreatureCard;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInHand;
|
||||
import mage.watchers.common.CastFromHandWatcher;
|
||||
|
||||
|
@ -57,12 +57,6 @@ import mage.watchers.common.CastFromHandWatcher;
|
|||
*/
|
||||
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) {
|
||||
super(ownerId, 229, "Myojin of Life's Web", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{6}{G}{G}{G}");
|
||||
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.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD,
|
||||
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.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutOntoBattlefieldTargetEffect(false), new RemoveCountersSourceCost(CounterType.DIVINITY.createInstance()));
|
||||
ability.addTarget(new TargetCardInHand(0, Integer.MAX_VALUE, filter));
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MyojinOfLifesWebPutCreatureOnBattlefieldEffect(), new RemoveCountersSourceCost(CounterType.DIVINITY.createInstance()));
|
||||
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
|
@ -95,3 +89,35 @@ public class MyojinOfLifesWeb extends CardImpl {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GoblinArtisansEffect(), new TapSourceCost()));
|
||||
|
||||
|
||||
}
|
||||
|
||||
public GoblinArtisans(final GoblinArtisans card) {
|
||||
|
@ -83,15 +83,14 @@ public class GoblinArtisans extends CardImpl {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
class GoblinArtisansEffect extends OneShotEffect {
|
||||
|
||||
private static final FilterPermanent filter = new FilterPermanent("permanent named Goblin Artisans");
|
||||
|
||||
|
||||
static {
|
||||
filter.add(new NamePredicate("Goblin Artisans"));
|
||||
}
|
||||
|
||||
|
||||
public GoblinArtisansEffect() {
|
||||
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.";
|
||||
|
@ -109,37 +108,38 @@ class GoblinArtisansEffect extends OneShotEffect {
|
|||
controller.drawCards(1, game);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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? :)
|
||||
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 (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()){
|
||||
//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);
|
||||
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 (UUID modeId : abil.getModes().getSelectedModes()) {
|
||||
Mode mode = abil.getModes().get(modeId);
|
||||
for (Target target : mode.getTargets()) {
|
||||
for (UUID targetId : target.getTargets()) {
|
||||
artifacts.remove(game.getPermanentOrLKIBattlefield(targetId));
|
||||
}// we could
|
||||
}// remove this
|
||||
}//closing bracers
|
||||
}// pyramid, if it's bothering anyone
|
||||
} //they are all one-liners after all :)
|
||||
if (!artifacts.isEmpty()){
|
||||
Cards cards=new CardsImpl();
|
||||
for (Permanent perm : artifacts){
|
||||
for (UUID targetId : target.getTargets()) {
|
||||
artifacts.remove(game.getPermanentOrLKIBattlefield(targetId));
|
||||
}// we could
|
||||
}// remove this
|
||||
}//closing bracers
|
||||
}// pyramid, if it's bothering anyone
|
||||
} //they are all one-liners after all :)
|
||||
if (!artifacts.isEmpty()) {
|
||||
Cards cards = new CardsImpl();
|
||||
for (Permanent perm : artifacts) {
|
||||
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);
|
||||
game.getPermanent(target.getFirstTarget()).sacrifice(source.getSourceId(), game);
|
||||
}
|
||||
game.getPermanent(target.getFirstTarget()).sacrifice(source.getSourceId(), game);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ class JelevaNephaliasScourgeEffect extends OneShotEffect {
|
|||
for (int i = 0; i < cardsToExile; i++) {
|
||||
Card card = player.getLibrary().removeFromTop(game);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
*/
|
||||
package mage.sets.conspiracytakethecrown;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
|
@ -41,8 +40,7 @@ import mage.game.Game;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
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);
|
||||
|
||||
// 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.
|
||||
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 {
|
||||
|
||||
public LeovoldEmissaryOfTrestEffect() {
|
||||
|
@ -133,11 +90,6 @@ class LeovoldEmissaryOfTrestEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
return new LeovoldEmissaryOfTrestEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.DRAW_CARD;
|
||||
|
@ -145,10 +97,9 @@ class LeovoldEmissaryOfTrestEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
|
||||
@Override
|
||||
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());
|
||||
return watcher != null && controller != null && watcher.hasPlayerDrewCardThisTurn(event.getPlayerId())
|
||||
return watcher != null && controller != null && watcher.getAmountCardsDrawn(event.getPlayerId()) >= 1
|
||||
&& game.isOpponent(controller, event.getPlayerId());
|
||||
}
|
||||
|
||||
|
@ -178,9 +129,10 @@ class LeovoldEmissaryOfTrestTriggeredAbility extends TriggeredAbilityImpl {
|
|||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Player controller = game.getPlayer(this.getControllerId());
|
||||
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())) {
|
||||
return true;
|
||||
return true; // Player was targeted
|
||||
}
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId());
|
||||
if (permanent != null && this.getControllerId().equals(permanent.getControllerId())) {
|
||||
|
@ -192,6 +144,6 @@ class LeovoldEmissaryOfTrestTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ import mage.choices.ChoiceImpl;
|
|||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.players.Player;
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,13 +33,13 @@ import mage.Mana;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.mana.DynamicManaAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.ObjectSourcePlayer;
|
||||
|
@ -48,7 +48,6 @@ import mage.filter.predicate.permanent.AnotherPredicate;
|
|||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -56,8 +55,8 @@ import mage.target.targetpointer.FixedTarget;
|
|||
*/
|
||||
public class SelvalaHeartOfTheWilds extends CardImpl {
|
||||
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature");
|
||||
|
||||
static {
|
||||
filter.add(new AnotherPredicate());
|
||||
filter.add(new GreatestPowerPredicate());
|
||||
|
@ -75,12 +74,14 @@ public class SelvalaHeartOfTheWilds extends CardImpl {
|
|||
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.
|
||||
|
||||
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.
|
||||
this.addAbility(new DynamicManaAbility(new Mana(0,0,0,0,0,0,1, 0), new GreatestPowerYouControlValue(), new TapSourceCost(),
|
||||
"Add X mana in any combination of colors to your mana pool, where X is the number of creatures with defender you control."));
|
||||
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 greatest power among creatures you control.");
|
||||
ability.addCost(new TapSourceCost());
|
||||
this.addAbility(ability);
|
||||
|
||||
}
|
||||
|
||||
public SelvalaHeartOfTheWilds(final SelvalaHeartOfTheWilds card) {
|
||||
|
@ -112,12 +113,12 @@ class SelvalaHeartOfTheWildsEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source));
|
||||
if(permanent == null){
|
||||
permanent = (Permanent)game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.BATTLEFIELD);
|
||||
if (permanent == null) {
|
||||
permanent = (Permanent) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.BATTLEFIELD);
|
||||
}
|
||||
if (permanent != null) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -125,18 +126,17 @@ class SelvalaHeartOfTheWildsEffect extends OneShotEffect {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
class GreatestPowerPredicate implements ObjectSourcePlayerPredicate<ObjectSourcePlayer<Permanent>> {
|
||||
|
||||
@Override
|
||||
public boolean apply(ObjectSourcePlayer<Permanent> input, Game game) {
|
||||
int pow = input.getObject().getPower().getValue();
|
||||
|
||||
for (UUID id :game.getPlayerList()){
|
||||
for (UUID id : game.getPlayerList()) {
|
||||
Player player = game.getPlayer(id);
|
||||
if (player != null) {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -144,6 +144,7 @@ class GreatestPowerPredicate implements ObjectSourcePlayerPredicate<ObjectSource
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Greatest Power";
|
||||
|
|
|
@ -227,7 +227,8 @@ class IcefallRegentCostIncreaseEffect extends CostModificationEffectImpl {
|
|||
public boolean applies(Ability abilityToModify, Ability source, Game game) {
|
||||
if (abilityToModify instanceof SpellAbility) {
|
||||
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 (UUID targetUUID : target.getTargets()) {
|
||||
if (targetUUID.equals(source.getSourceId())) {
|
||||
|
|
|
@ -80,7 +80,7 @@ class ReconnaissanceRemoveFromCombatEffect extends OneShotEffect {
|
|||
|
||||
public ReconnaissanceRemoveFromCombatEffect() {
|
||||
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) {
|
||||
|
|
|
@ -109,7 +109,8 @@ class MonasterySiegeCostIncreaseEffect extends CostModificationEffectImpl {
|
|||
if (new ModeChoiceSourceCondition("Dragons").apply(game, source)) {
|
||||
if (abilityToModify instanceof SpellAbility) {
|
||||
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 (UUID targetUUID : target.getTargets()) {
|
||||
if (targetUUID.equals(source.getControllerId())) {
|
||||
|
|
|
@ -101,7 +101,7 @@ class AetherbornMarauderEffect extends OneShotEffect {
|
|||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Permanent sourceObject = game.getPermanent(source.getSourceId());
|
||||
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 CounterPredicate(CounterType.P1P1));
|
||||
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)) {
|
||||
firstRun = false;
|
||||
TargetControlledPermanent target = new TargetControlledPermanent(filter);
|
||||
Permanent fromPermanent = game.getPermanent(target.getFirstTarget());
|
||||
if (fromPermanent != null) {
|
||||
int numberOfCounters = fromPermanent.getCounters(game).getCount(CounterType.P1P1);
|
||||
int numberToMove = 1;
|
||||
if (numberOfCounters > 1) {
|
||||
numberToMove = controller.getAmount(0, numberOfCounters, "How many +1/+1 counters do you want to move?", game);
|
||||
}
|
||||
if (numberToMove > 0) {
|
||||
fromPermanent.removeCounters(CounterType.P1P1.createInstance(numberToMove), game);
|
||||
sourceObject.addCounters(CounterType.P1P1.createInstance(numberToMove), game);
|
||||
target.setNotTarget(true);
|
||||
if (target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), game)) {
|
||||
Permanent fromPermanent = game.getPermanent(target.getFirstTarget());
|
||||
if (fromPermanent != null) {
|
||||
int numberOfCounters = fromPermanent.getCounters(game).getCount(CounterType.P1P1);
|
||||
int numberToMove = 1;
|
||||
if (numberOfCounters > 1) {
|
||||
numberToMove = controller.getAmount(0, numberOfCounters, "How many +1/+1 counters do you want to move?", game);
|
||||
}
|
||||
if (numberToMove > 0) {
|
||||
fromPermanent.removeCounters(CounterType.P1P1.createInstance(numberToMove), game);
|
||||
sourceObject.addCounters(CounterType.P1P1.createInstance(numberToMove), game);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -1,146 +1,151 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are 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.kaladesh;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.AttacksTriggeredAbility;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.DiscardHandCost;
|
||||
import mage.abilities.costs.common.SacrificeSourceCost;
|
||||
import mage.abilities.costs.mana.ColoredManaCost;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.keyword.HasteAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.ColoredManaSymbol;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public class BomatCourier extends CardImpl {
|
||||
|
||||
public BomatCourier(UUID ownerId) {
|
||||
super(ownerId, 199, "Bomat Courier", Rarity.RARE, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}");
|
||||
this.expansionSetCode = "KLD";
|
||||
this.subtype.add("Construct");
|
||||
this.power = new MageInt(1);
|
||||
this.toughness = new MageInt(1);
|
||||
|
||||
// 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));
|
||||
|
||||
// {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));
|
||||
ability.addCost(new DiscardHandCost());
|
||||
ability.addCost(new SacrificeSourceCost());
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
public BomatCourier(final BomatCourier card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BomatCourier copy() {
|
||||
return new BomatCourier(this);
|
||||
}
|
||||
}
|
||||
|
||||
class BomatCourierExileEffect extends OneShotEffect {
|
||||
|
||||
BomatCourierExileEffect() {
|
||||
super(Outcome.Exile);
|
||||
this.staticText = "exile the top card of your library face down";
|
||||
}
|
||||
|
||||
BomatCourierExileEffect(final BomatCourierExileEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BomatCourierExileEffect copy() {
|
||||
return new BomatCourierExileEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
if (controller != null && sourceObject != null) {
|
||||
Card card = controller.getLibrary().getFromTop(game);
|
||||
if (card != null) {
|
||||
UUID exileZoneId = CardUtil.getCardExileZoneId(game, source);
|
||||
card.setFaceDown(true, game);
|
||||
controller.moveCardsToExile(card, source, game, false, exileZoneId, sourceObject.getIdName());
|
||||
card.setFaceDown(true, game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class BomatCourierReturnEffect extends OneShotEffect {
|
||||
|
||||
BomatCourierReturnEffect() {
|
||||
super(Outcome.DrawCard);
|
||||
this.staticText = "Put all cards exiled with {this} into their owners' hands";
|
||||
}
|
||||
|
||||
BomatCourierReturnEffect(final BomatCourierReturnEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BomatCourierReturnEffect copy() {
|
||||
return new BomatCourierReturnEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
return controller.moveCards(game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source.getSourceId(), true)), Zone.HAND, source, game);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.sets.kaladesh;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.AttacksTriggeredAbility;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.DiscardHandCost;
|
||||
import mage.abilities.costs.common.SacrificeSourceCost;
|
||||
import mage.abilities.costs.mana.ColoredManaCost;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.keyword.HasteAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.ColoredManaSymbol;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.ExileZone;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public class BomatCourier extends CardImpl {
|
||||
|
||||
public BomatCourier(UUID ownerId) {
|
||||
super(ownerId, 199, "Bomat Courier", Rarity.RARE, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}");
|
||||
this.expansionSetCode = "KLD";
|
||||
this.subtype.add("Construct");
|
||||
this.power = new MageInt(1);
|
||||
this.toughness = new MageInt(1);
|
||||
|
||||
// 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));
|
||||
|
||||
// {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));
|
||||
ability.addCost(new DiscardHandCost());
|
||||
ability.addCost(new SacrificeSourceCost());
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
public BomatCourier(final BomatCourier card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BomatCourier copy() {
|
||||
return new BomatCourier(this);
|
||||
}
|
||||
}
|
||||
|
||||
class BomatCourierExileEffect extends OneShotEffect {
|
||||
|
||||
BomatCourierExileEffect() {
|
||||
super(Outcome.Exile);
|
||||
this.staticText = "exile the top card of your library face down";
|
||||
}
|
||||
|
||||
BomatCourierExileEffect(final BomatCourierExileEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BomatCourierExileEffect copy() {
|
||||
return new BomatCourierExileEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
if (controller != null && sourceObject != null) {
|
||||
Card card = controller.getLibrary().getFromTop(game);
|
||||
if (card != null) {
|
||||
UUID exileZoneId = CardUtil.getCardExileZoneId(game, source);
|
||||
card.setFaceDown(true, game);
|
||||
controller.moveCardsToExile(card, source, game, false, exileZoneId, sourceObject.getIdName());
|
||||
card.setFaceDown(true, game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class BomatCourierReturnEffect extends OneShotEffect {
|
||||
|
||||
BomatCourierReturnEffect() {
|
||||
super(Outcome.DrawCard);
|
||||
this.staticText = "Put all cards exiled with {this} into their owners' hands";
|
||||
}
|
||||
|
||||
BomatCourierReturnEffect(final BomatCourierReturnEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BomatCourierReturnEffect copy() {
|
||||
return new BomatCourierReturnEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
ExileZone exileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source.getSourceId(), true));
|
||||
if (exileZone != null) {
|
||||
controller.moveCards(exileZone, Zone.HAND, source, game);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ import mage.abilities.common.SimpleStaticAbility;
|
|||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
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.cards.CardImpl;
|
||||
import mage.constants.AttachmentType;
|
||||
|
@ -81,8 +81,8 @@ public class CapturedByTheConsulate extends CardImpl {
|
|||
Ability ability = new EnchantAbility(auraTarget.getTargetName());
|
||||
this.addAbility(ability);
|
||||
|
||||
// Enchanted creature can't attack or block.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackBlockAttachedEffect(AttachmentType.AURA)));
|
||||
// Enchanted creature can't attack.
|
||||
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.
|
||||
this.addAbility(new CapturedByTheConsulateTriggeredAbility(Zone.BATTLEFIELD, new CapturedByTheConsulateEffect()));
|
||||
|
@ -141,7 +141,8 @@ class CapturedByTheConsulateTriggeredAbility extends TriggeredAbilityImpl {
|
|||
}
|
||||
if (stackObject != null) {
|
||||
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()) {
|
||||
numberOfTargets += target.getTargets().size();
|
||||
}
|
||||
|
|
|
@ -99,7 +99,7 @@ class CombustibleGearhulkEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||
if (controller != null && sourcePermanent != null) {
|
||||
UUID opponentId;
|
||||
if (game.getOpponents(controller.getId()).size() == 1) {
|
||||
|
|
|
@ -45,6 +45,7 @@ import mage.constants.Zone;
|
|||
import mage.filter.common.FilterControlledPermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
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 {
|
||||
|
||||
private static final FilterControlledPermanent filter = new FilterControlledPermanent("an artifact or creature");
|
||||
private static final FilterControlledPermanent filter = new FilterControlledPermanent("an artifact or Artificer");
|
||||
|
||||
static {
|
||||
filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT),
|
||||
new CardTypePredicate(CardType.CREATURE)));
|
||||
new SubtypePredicate("Artificer")));
|
||||
}
|
||||
|
||||
public EraOfInnovation(UUID ownerId) {
|
||||
super(ownerId, 45, "Era of Innovation", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}");
|
||||
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));
|
||||
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.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(3), new PayEnergyCost(6));
|
||||
|
|
|
@ -1,82 +1,81 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.sets.kaladesh;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
|
||||
import mage.abilities.keyword.EquipAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public class InventorsGoggles extends CardImpl {
|
||||
|
||||
public InventorsGoggles(UUID ownerId) {
|
||||
super(ownerId, 218, "Inventor's Goggles", Rarity.COMMON, new CardType[]{CardType.ARTIFACT}, "{1}");
|
||||
this.expansionSetCode = "KLD";
|
||||
this.subtype.add("Equipment");
|
||||
|
||||
// Equipped creature gets +1/+2.
|
||||
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.
|
||||
this.addAbility(new EntersBattlefieldAllTriggeredAbility(
|
||||
Zone.BATTLEFIELD,
|
||||
new AttachEffect(Outcome.BoostCreature, "attach {this} to it"),
|
||||
new FilterPermanent("Artificer", "Artificer"),
|
||||
true,
|
||||
SetTargetPointer.PERMANENT,
|
||||
null,
|
||||
true));
|
||||
|
||||
// Equip {2}
|
||||
this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(2)));
|
||||
}
|
||||
|
||||
public InventorsGoggles(final InventorsGoggles card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InventorsGoggles copy() {
|
||||
return new InventorsGoggles(this);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.sets.kaladesh;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
|
||||
import mage.abilities.keyword.EquipAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public class InventorsGoggles extends CardImpl {
|
||||
|
||||
public InventorsGoggles(UUID ownerId) {
|
||||
super(ownerId, 218, "Inventor's Goggles", Rarity.COMMON, new CardType[]{CardType.ARTIFACT}, "{1}");
|
||||
this.expansionSetCode = "KLD";
|
||||
this.subtype.add("Equipment");
|
||||
|
||||
// Equipped creature gets +1/+2.
|
||||
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.
|
||||
this.addAbility(new EntersBattlefieldControlledTriggeredAbility(
|
||||
Zone.BATTLEFIELD,
|
||||
new AttachEffect(Outcome.BoostCreature, "attach {this} to it"),
|
||||
new FilterPermanent("Artificer", "Artificer"),
|
||||
true,
|
||||
SetTargetPointer.PERMANENT,
|
||||
null));
|
||||
|
||||
// Equip {2}
|
||||
this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(2)));
|
||||
}
|
||||
|
||||
public InventorsGoggles(final InventorsGoggles card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InventorsGoggles copy() {
|
||||
return new InventorsGoggles(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ class LostLegacyEffect extends SearchTargetGraveyardHandLibraryForCardNameAndExi
|
|||
public boolean apply(Game game, Ability source) {
|
||||
String cardName = (String) game.getState().getValue(source.getSourceId().toString() + NameACardEffect.INFO_KEY);
|
||||
Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source));
|
||||
if (targetPlayer != null) {
|
||||
if (targetPlayer != null && cardName != null && !cardName.isEmpty()) {
|
||||
FilterCard filter = new FilterCard();
|
||||
filter.add(new NamePredicate(cardName));
|
||||
int cardsInHandBefore = targetPlayer.getHand().count(filter, game);
|
||||
|
|
|
@ -187,10 +187,10 @@ class MultiformWonder2Effect extends ContinuousEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent target = game.getPermanent(source.getFirstTarget());
|
||||
if (target != null) {
|
||||
target.addPower(power);
|
||||
target.addToughness(toughness);
|
||||
Permanent sourceObject = game.getPermanent(source.getSourceId());
|
||||
if (sourceObject != null) {
|
||||
sourceObject.addPower(power);
|
||||
sourceObject.addToughness(toughness);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -41,7 +41,7 @@ import mage.game.Game;
|
|||
import mage.game.events.EntersTheBattlefieldEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.events.NumberOfTriggersEvent;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -85,15 +85,28 @@ class PanharmoniconEffect extends ReplacementEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == EventType.ENTERS_THE_BATTLEFIELD;
|
||||
return event.getType() == EventType.NUMBER_OF_TRIGGERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (event instanceof EntersTheBattlefieldEvent) {
|
||||
Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget();
|
||||
if (permanent != null) {
|
||||
return permanent.getCardType().contains(CardType.ARTIFACT) || permanent.getCardType().contains(CardType.CREATURE);
|
||||
if (event instanceof NumberOfTriggersEvent) {
|
||||
NumberOfTriggersEvent numberOfTriggersEvent = (NumberOfTriggersEvent) event;
|
||||
// Only triggers of the controller of Panharmonicon
|
||||
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;
|
||||
|
|
|
@ -33,15 +33,18 @@ import mage.abilities.common.SimpleActivatedAbility;
|
|||
import mage.abilities.costs.common.SacrificeSourceCost;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.PutOnLibraryTargetEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect;
|
||||
import mage.abilities.mana.ColorlessManaAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterArtifactCard;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
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.addCost(new TapSourceCost());
|
||||
ability.addCost(new SacrificeSourceCost());
|
||||
Effect effect = new PutOnLibraryTargetEffect(true);
|
||||
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")));
|
||||
ability.addEffect(new SequesteredStashEffect());
|
||||
this.addAbility(ability);
|
||||
|
||||
}
|
||||
|
@ -78,3 +78,39 @@ public class SequesteredStash extends CardImpl {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ import mage.constants.Zone;
|
|||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
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.
|
||||
this.getSpellAbility().addEffect(new SparkOfCreativityEffect());
|
||||
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||
}
|
||||
|
||||
public SparkOfCreativity(final SparkOfCreativity card) {
|
||||
|
@ -142,9 +144,7 @@ class SparkOfCreativityPlayEffect extends AsThoughEffectImpl {
|
|||
if (objectReference.refersTo(objectId, game) && affectedControllerId.equals(source.getControllerId())) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
if (controller.chooseUse(outcome, "Play the exiled card?", source, game)) {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
discard();
|
||||
}
|
||||
|
|
|
@ -52,11 +52,15 @@ public class SubtleStrike extends CardImpl {
|
|||
this.getSpellAbility().getModes().setMinModes(1);
|
||||
this.getSpellAbility().getModes().setMaxModes(2);
|
||||
// • 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());
|
||||
// • Put a +1/+1 counter on target creature.
|
||||
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());
|
||||
this.getSpellAbility().addMode(mode1);
|
||||
|
||||
|
|
|
@ -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.
|
||||
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) {
|
||||
|
|
|
@ -29,15 +29,18 @@ package mage.sets.legions;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.CreateTokenTargetEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.token.SliverToken;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -54,10 +57,8 @@ public class BroodSliver extends CardImpl {
|
|||
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.
|
||||
Effect effect = new CreateTokenTargetEffect(new SliverToken());
|
||||
effect.setText("its controller may put a 1/1 colorless Sliver creature token onto the battlefield");
|
||||
this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility(effect,
|
||||
new FilterCreaturePermanent("Sliver", "a Sliver"), true, SetTargetPointer.PLAYER, true));
|
||||
this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility(new BroodSliverEffect(),
|
||||
new FilterCreaturePermanent("Sliver", "a Sliver"), false, SetTargetPointer.PLAYER, true));
|
||||
}
|
||||
|
||||
public BroodSliver(final BroodSliver card) {
|
||||
|
@ -69,3 +70,32 @@ public class BroodSliver extends CardImpl {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
84
Mage.Sets/src/mage/sets/lorwyn/SilvergillDouser.java
Normal 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);
|
||||
}
|
||||
}
|
|
@ -27,12 +27,9 @@
|
|||
*/
|
||||
package mage.sets.magic2014;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.TriggeredAbility;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
|
@ -42,14 +39,11 @@ import mage.constants.CardType;
|
|||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.Filter;
|
||||
import mage.filter.FilterAbility;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.game.stack.StackObject;
|
||||
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());
|
||||
if (controller != null && sourcePermanent != null) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -116,76 +110,3 @@ class StrionicResonatorEffect extends OneShotEffect {
|
|||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -135,7 +135,8 @@ class PsychicRebuttalPredicate implements ObjectPlayerPredicate<ObjectPlayer<Sta
|
|||
if (controllerId == null) {
|
||||
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 (UUID targetId : target.getTargets()) {
|
||||
if (controllerId.equals(targetId)) {
|
||||
|
|
|
@ -118,20 +118,19 @@ class FoodChainManaEffect extends ManaEffect {
|
|||
ChoiceColor choice = new ChoiceColor();
|
||||
controller.choose(Outcome.PutManaInPool, choice, game);
|
||||
ObjectColor chosenColor = choice.getColor();
|
||||
if (chosenColor == null) {
|
||||
return false;
|
||||
}
|
||||
Mana mana = null;
|
||||
if (chosenColor.isBlack()) {
|
||||
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();
|
||||
}
|
||||
else if (chosenColor.isRed()) {
|
||||
} else if (chosenColor.isRed()) {
|
||||
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();
|
||||
}
|
||||
else if (chosenColor.isWhite()) {
|
||||
} else if (chosenColor.isWhite()) {
|
||||
mana = new FoodChainManaBuilder().setMana(Mana.WhiteMana(manaCostExiled + 1), source, game).build();
|
||||
}
|
||||
if (mana != null) {
|
||||
|
|
|
@ -29,18 +29,12 @@ package mage.sets.mirrodinbesieged;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||
import mage.abilities.effects.common.ruleModifying.CantHaveCountersSourceEffect;
|
||||
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);
|
||||
|
||||
// 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) {
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -106,7 +106,8 @@ class ElderwoodScionCostReductionEffect extends CostModificationEffectImpl {
|
|||
public boolean applies(Ability abilityToModify, Ability source, Game game) {
|
||||
if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) {
|
||||
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 (UUID targetUUID : target.getTargets()) {
|
||||
if (targetUUID.equals(source.getSourceId())) {
|
||||
|
|
60
Mage.Sets/src/mage/sets/prophecy/BlessedWind.java
Normal 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);
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ package mage.sets.ravnica;
|
|||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.common.LeavesBattlefieldAllTriggeredAbility;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.RemoveCountersSourceCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
|
@ -41,12 +41,8 @@ import mage.constants.CardType;
|
|||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.permanent.TokenPredicate;
|
||||
import mage.game.permanent.token.SpiritWhiteToken;
|
||||
|
||||
/**
|
||||
|
@ -55,6 +51,12 @@ import mage.game.permanent.token.SpiritWhiteToken;
|
|||
*/
|
||||
public class TwilightDrover extends CardImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature token");
|
||||
|
||||
static {
|
||||
filter.add(new TokenPredicate());
|
||||
}
|
||||
|
||||
public TwilightDrover(UUID ownerId) {
|
||||
super(ownerId, 33, "Twilight Drover", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{W}");
|
||||
this.expansionSetCode = "RAV";
|
||||
|
@ -64,8 +66,8 @@ public class TwilightDrover extends CardImpl {
|
|||
this.toughness = new MageInt(1);
|
||||
|
||||
// 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.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new SpiritWhiteToken("RAV"), 2), new ManaCostsImpl<>("{2}{W}"));
|
||||
ability.addCost(new RemoveCountersSourceCost(CounterType.P1P1.createInstance()));
|
||||
|
@ -81,42 +83,3 @@ public class TwilightDrover extends CardImpl {
|
|||
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}";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,6 @@ public class LightmineField extends CardImpl {
|
|||
super(ownerId, 32, "Lightmine Field", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}");
|
||||
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.
|
||||
this.addAbility(new LightmineFieldTriggeredAbility());
|
||||
}
|
||||
|
@ -122,7 +121,7 @@ class LightmineFieldEffect extends OneShotEffect {
|
|||
for (UUID attacker : attackers) {
|
||||
Permanent creature = game.getPermanent(attacker);
|
||||
if (creature != null) {
|
||||
creature.damage(damage, source.getSourceId(), game, false, false);
|
||||
creature.damage(damage, source.getSourceId(), game, false, true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
package mage.sets.scourge;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
|
@ -108,7 +107,8 @@ class GripOfChaosTriggeredAbility extends TriggeredAbilityImpl {
|
|||
}
|
||||
if (stackObject != null) {
|
||||
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()) {
|
||||
numberOfTargets += target.getTargets().size();
|
||||
}
|
||||
|
@ -149,7 +149,8 @@ class GripOfChaosEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
StackObject stackObject = game.getStack().getStackObject(this.getTargetPointer().getFirst(game, source));
|
||||
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()) {
|
||||
UUID oldTargetId = target.getFirstTarget();
|
||||
Set<UUID> possibleTargets = target.possibleTargets(source.getSourceId(), source.getControllerId(), game);
|
||||
|
|
75
Mage.Sets/src/mage/sets/scourge/KrosanDrover.java
Normal 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);
|
||||
}
|
||||
}
|
|
@ -29,19 +29,14 @@ package mage.sets.shadowmoor;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||
import mage.abilities.effects.common.ruleModifying.CantHaveCountersSourceEffect;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -60,7 +55,7 @@ public class Tatterkite extends CardImpl {
|
|||
this.addAbility(FlyingAbility.getInstance());
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,7 +140,8 @@ class AccursedWitchSpellsCostReductionEffect extends CostModificationEffectImpl
|
|||
public boolean applies(Ability abilityToModify, Ability source, Game game) {
|
||||
if (abilityToModify instanceof SpellAbility) {
|
||||
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 (UUID targetUUID : target.getTargets()) {
|
||||
Permanent permanent = game.getPermanent(targetUUID);
|
||||
|
|
|
@ -155,7 +155,8 @@ class InfectiousCurseCostReductionEffect extends CostModificationEffectImpl {
|
|||
public boolean applies(Ability abilityToModify, Ability source, Game game) {
|
||||
if (abilityToModify instanceof SpellAbility) {
|
||||
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 (UUID targetUUID : target.getTargets()) {
|
||||
Permanent enchantment = game.getPermanent(source.getSourceId());
|
||||
|
|
|
@ -84,7 +84,8 @@ class HinderingLightPredicate implements ObjectPlayerPredicate<ObjectPlayer<Stac
|
|||
if (controllerId == null) {
|
||||
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 (UUID targetId : target.getTargets()) {
|
||||
if (controllerId.equals(targetId)) {
|
||||
|
|
120
Mage.Sets/src/mage/sets/timespiral/PsychoticEpisode.java
Normal 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);
|
||||
}
|
||||
}
|
82
Mage.Sets/src/mage/sets/timespiral/QuilledSliver.java
Normal 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);
|
||||
}
|
||||
}
|
109
Mage.Sets/src/mage/sets/urzassaga/Curfew.java
Normal 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();
|
||||
}
|
||||
}
|
||||
|
|
@ -96,7 +96,7 @@ class SmokestackEffect extends OneShotEffect {
|
|||
int count = sourcePermanent.getCounters(game).getCount("Soot");
|
||||
if (count > 0) {
|
||||
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
|
||||
//had, if thats the case this ability should fizzle.
|
||||
if (target.canChoose(activePlayer.getId(), game)) {
|
||||
|
|
|
@ -113,13 +113,13 @@ class TorchlingTargetPredicate implements Predicate<MageObject> {
|
|||
if (spell != null) {
|
||||
int numberOfTargets = 0;
|
||||
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 (UUID targetId : target.getTargets()) {
|
||||
if (!targetId.equals(sourceId)) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
numberOfTargets++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,7 +96,8 @@ class KaerveksTorchCostIncreaseEffect extends CostModificationEffectImpl {
|
|||
@Override
|
||||
public boolean applies(Ability abilityToModify, Ability source, Game game) {
|
||||
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 (UUID targetId : target.getTargets()) {
|
||||
if (targetId.equals(source.getSourceObject(game).getId())) {
|
||||
|
|
|
@ -111,7 +111,7 @@ class TerastodonEffect extends OneShotEffect {
|
|||
if (destroyedPermanents.containsKey(permanent.getControllerId())) {
|
||||
numberPermanents = destroyedPermanents.get(permanent.getControllerId());
|
||||
}
|
||||
destroyedPermanents.put(permanent.getControllerId(), numberPermanents);
|
||||
destroyedPermanents.put(permanent.getControllerId(), numberPermanents + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,10 +38,6 @@ import org.mage.test.serverside.base.CardTestPlayerBaseAI;
|
|||
*/
|
||||
public class CastDestroySpellsTest extends CardTestPlayerBaseAI {
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testOrzhovCharm() {
|
||||
// Choose one -
|
||||
|
@ -58,6 +54,8 @@ public class CastDestroySpellsTest extends CardTestPlayerBaseAI {
|
|||
// Cycling abilities you activate cost you up to {2} less to activate.
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Orzhov Charm", "Silvercoat Lion");
|
||||
setModeChoice(playerA, "2");
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
|
|
|
@ -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
|
||||
* he gets the +1/+1 counters
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -39,20 +39,22 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
|
|||
public class BrutalExpulsionTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* Brutal Expulsion targeting Gideon, Ally of Zendikar. Gideon has 3 loyalty. Brutal Expulsion resolves,
|
||||
* leaves 1 loyalty. I attack Gideon for 1 with a Scion token, Gideon dies. Instead of going to graveyard,
|
||||
* Expulsion sends Gideon to exile. However, in game Gideon went to graveyard.
|
||||
* Brutal Expulsion targeting Gideon, Ally of Zendikar. Gideon has 3
|
||||
* loyalty. Brutal Expulsion resolves, leaves 1 loyalty. I attack Gideon for
|
||||
* 1 with a Scion token, Gideon dies. Instead of going to graveyard,
|
||||
* Expulsion sends Gideon to exile. However, in game Gideon went to
|
||||
* graveyard.
|
||||
*/
|
||||
@Test
|
||||
public void testPlaneswalkerExile() {
|
||||
// Choose one or both
|
||||
// - Return target spell or creature to its owner's hand;
|
||||
// or Brutal Expulsion deals 2 damage to target creature or planeswalker. If that permanent would be put into a graveyard this turn, exile it instead.
|
||||
addCard(Zone.HAND, playerA, "Brutal Expulsion");
|
||||
addCard(Zone.HAND, playerA, "Brutal Expulsion"); // {2}{U}{R}
|
||||
// Shock deals 2 damage to target creature or player.
|
||||
addCard(Zone.HAND, playerA, "Shock");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
|
||||
addCard(Zone.HAND, playerA, "Shock"); // {R}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||
|
||||
// Planeswalker with 4 loyalty.
|
||||
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);
|
||||
setModeChoice(playerA, "2");
|
||||
setModeChoice(playerA, null);
|
||||
setChoice(playerA, "Yes");
|
||||
setChoice(playerA, "Yes"); // Redirect to planeswalker
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shock", playerB);
|
||||
setChoice(playerA, "Yes");
|
||||
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Shock", playerB);
|
||||
setChoice(playerA, "Yes"); // Redirect to planeswalker
|
||||
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
setStopAt(1, PhaseStep.END_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerB, "Gideon, Ally of Zendikar", 0);
|
||||
|
|
|
@ -15,24 +15,23 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
|
|||
* @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
*/
|
||||
@Test
|
||||
public void testTokenCreatedBySliverController() {
|
||||
|
||||
|
||||
// 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.
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Brood Sliver");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Venom Sliver"); // 1/1 deathtouch granting sliver
|
||||
|
||||
|
||||
attack(1, playerA, "Venom Sliver");
|
||||
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);
|
||||
execute();
|
||||
|
||||
|
||||
assertLife(playerB, 19);
|
||||
assertPermanentCount(playerA, "Sliver", 1);
|
||||
assertPermanentCount(playerB, "Sliver", 0);
|
||||
|
|
|
@ -287,7 +287,8 @@ public class TestPlayer implements Player {
|
|||
}
|
||||
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)) {
|
||||
selectedMode = mode;
|
||||
ability.getModes().setActiveMode(mode);
|
||||
|
|
|
@ -306,7 +306,8 @@ public abstract class AbilityImpl implements Ability {
|
|||
&& game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL_LATE, getId(), getSourceId(), getControllerId()), this)) {
|
||||
return false;
|
||||
}
|
||||
for (Mode mode : this.getModes().getSelectedModes()) {
|
||||
for (UUID modeId : this.getModes().getSelectedModes()) {
|
||||
Mode mode = this.getModes().get(modeId);
|
||||
this.getModes().setActiveMode(mode);
|
||||
//20121001 - 601.2c
|
||||
// 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) {
|
||||
Modes spellModes = ((Spell) object).getSpellAbility().getModes();
|
||||
for (Mode selectedMode : spellModes.getSelectedModes()) {
|
||||
for (UUID selectedModeId : spellModes.getSelectedModes()) {
|
||||
Mode selectedMode = spellModes.get(selectedModeId);
|
||||
int item = 0;
|
||||
for (Mode mode : spellModes.values()) {
|
||||
item++;
|
||||
|
|
|
@ -41,7 +41,6 @@ import mage.constants.TargetController;
|
|||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetOpponent;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -49,8 +48,8 @@ import mage.util.CardUtil;
|
|||
*/
|
||||
public class Modes extends LinkedHashMap<UUID, Mode> {
|
||||
|
||||
private Mode mode; // the current mode of the selected modes
|
||||
private final ArrayList<Mode> selectedModes = new ArrayList<>();
|
||||
private Mode currentMode; // the current mode of the selected modes
|
||||
private final ArrayList<UUID> selectedModes = new ArrayList<>();
|
||||
private int minModes;
|
||||
private int maxModes;
|
||||
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
|
||||
|
||||
public Modes() {
|
||||
this.mode = new Mode();
|
||||
this.put(mode.getId(), mode);
|
||||
this.currentMode = new Mode();
|
||||
this.put(currentMode.getId(), currentMode);
|
||||
this.minModes = 1;
|
||||
this.maxModes = 1;
|
||||
this.selectedModes.add(mode);
|
||||
this.selectedModes.add(currentMode.getId());
|
||||
this.modeChooser = TargetController.YOU;
|
||||
this.eachModeOnlyOnce = false;
|
||||
this.eachModeMoreThanOnce = false;
|
||||
|
@ -75,23 +74,8 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
this.minModes = modes.minModes;
|
||||
this.maxModes = modes.maxModes;
|
||||
|
||||
if (modes.size() == 1) {
|
||||
this.mode = values().iterator().next();
|
||||
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.currentMode = values().iterator().next();
|
||||
selectedModes.addAll(modes.getSelectedModes());
|
||||
this.modeChooser = modes.modeChooser;
|
||||
this.eachModeOnlyOnce = modes.eachModeOnlyOnce;
|
||||
this.eachModeMoreThanOnce = modes.eachModeMoreThanOnce;
|
||||
|
@ -102,21 +86,21 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
}
|
||||
|
||||
public Mode getMode() {
|
||||
return mode;
|
||||
return currentMode;
|
||||
}
|
||||
|
||||
public UUID getModeId(int index) {
|
||||
int idx = 0;
|
||||
for (Mode currentMode : this.values()) {
|
||||
for (Mode mode : this.values()) {
|
||||
idx++;
|
||||
if (idx == index) {
|
||||
return currentMode.getId();
|
||||
return mode.getId();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ArrayList<Mode> getSelectedModes() {
|
||||
public ArrayList<UUID> getSelectedModes() {
|
||||
return selectedModes;
|
||||
}
|
||||
|
||||
|
@ -145,8 +129,8 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
}
|
||||
|
||||
public void setActiveMode(Mode mode) {
|
||||
if (selectedModes.contains(mode)) {
|
||||
this.mode = mode;
|
||||
if (selectedModes.contains(mode.getId())) {
|
||||
this.currentMode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,7 +159,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
for (Mode mode : this.values()) {
|
||||
if ((!isEachModeOnlyOnce() || onceSelectedModes == null || !onceSelectedModes.contains(mode.getId()))
|
||||
&& mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) {
|
||||
this.selectedModes.add(mode.copy());
|
||||
this.selectedModes.add(mode.getId());
|
||||
}
|
||||
}
|
||||
if (isEachModeOnlyOnce()) {
|
||||
|
@ -203,7 +187,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
Player player = game.getPlayer(playerId);
|
||||
|
||||
// player chooses modes manually
|
||||
this.mode = null;
|
||||
this.currentMode = null;
|
||||
while (this.selectedModes.size() < this.getMaxModes()) {
|
||||
Mode choice = player.chooseMode(this, source, game);
|
||||
if (choice == null) {
|
||||
|
@ -212,9 +196,9 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
}
|
||||
return this.selectedModes.size() >= this.getMinModes();
|
||||
}
|
||||
this.selectedModes.add(choice.copy());
|
||||
if (mode == null) {
|
||||
mode = choice;
|
||||
this.selectedModes.add(choice.getId());
|
||||
if (currentMode == null) {
|
||||
currentMode = choice;
|
||||
}
|
||||
}
|
||||
if (isEachModeOnlyOnce()) {
|
||||
|
@ -222,10 +206,10 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
if (mode == null) {
|
||||
if (currentMode == null) {
|
||||
this.selectedModes.clear();
|
||||
Mode copiedMode = this.values().iterator().next().copy();
|
||||
this.selectedModes.add(copiedMode);
|
||||
this.selectedModes.add(copiedMode.getId());
|
||||
this.setActiveMode(copiedMode);
|
||||
}
|
||||
if (isEachModeOnlyOnce()) {
|
||||
|
@ -234,27 +218,46 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
return true;
|
||||
}
|
||||
|
||||
private void setAlreadySelectedModes(ArrayList<Mode> selectedModes, Ability source, Game game) {
|
||||
String key = getKey(source, game);
|
||||
Set<UUID> onceSelectedModes = (Set<UUID>) game.getState().getValue(key);
|
||||
if (onceSelectedModes == null) {
|
||||
onceSelectedModes = new HashSet<>();
|
||||
/**
|
||||
* Saves the already selected modes to the state value
|
||||
*
|
||||
* @param selectedModes
|
||||
* @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) {
|
||||
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) {
|
||||
return CardUtil.getObjectZoneString("selectedModes", source.getSourceId(), game, game.getState().getZoneChangeCounter(source.getSourceId()), false);
|
||||
// creates the key the selected modes are saved with to the state values
|
||||
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) {
|
||||
List<Mode> availableModes = new ArrayList<>();
|
||||
Set<UUID> nonAvailableModes;
|
||||
|
|
|
@ -56,6 +56,9 @@ public abstract class StaticAbility extends AbilityImpl {
|
|||
if (game.getShortLivingLKI(getSourceId(), zone)) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ import mage.cards.Card;
|
|||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.NumberOfTriggersEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.Spell;
|
||||
|
||||
|
@ -124,7 +125,12 @@ public class TriggeredAbilities extends ConcurrentHashMap<String, TriggeredAbili
|
|||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ package mage.abilities.common;
|
|||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.DamagedPlayerEvent;
|
||||
|
@ -41,7 +42,8 @@ import mage.target.targetpointer.FixedTarget;
|
|||
*/
|
||||
public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private boolean setTargetPointer;
|
||||
protected boolean setTargetPointer;
|
||||
protected String text;
|
||||
|
||||
public DealsCombatDamageToAPlayerTriggeredAbility(Effect effect, boolean optional) {
|
||||
this(effect, optional, false);
|
||||
|
@ -52,8 +54,15 @@ public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbility
|
|||
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) {
|
||||
super(ability);
|
||||
this.text = ability.text;
|
||||
this.setTargetPointer = ability.setTargetPointer;
|
||||
}
|
||||
|
||||
|
@ -84,7 +93,10 @@ public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbility
|
|||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -73,12 +73,11 @@ public class DealsDamageToAPlayerAllTriggeredAbility extends TriggeredAbilityImp
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (!onlyCombat || ((DamagedPlayerEvent) event).isCombatDamage()) {
|
||||
Permanent permanent = game.getPermanent(event.getSourceId());
|
||||
if (permanent != null) {
|
||||
controllerId = permanent.getControllerId();
|
||||
if (filter.match(permanent, sourceId, controllerId, game)) {
|
||||
if (filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||
if (!setTargetPointer.equals(SetTargetPointer.NONE)) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setValue("damage", event.getAmount());
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -51,7 +51,8 @@ public class ChangeATargetOfTargetSpellAbilityToSourceEffect extends OneShotEffe
|
|||
} else {
|
||||
return false;
|
||||
}
|
||||
for (Mode mode : sourceAbility.getModes().getSelectedModes()) {
|
||||
for (UUID modeId : sourceAbility.getModes().getSelectedModes()) {
|
||||
Mode mode = sourceAbility.getModes().get(modeId);
|
||||
targets.addAll(mode.getTargets());
|
||||
}
|
||||
|
||||
|
@ -102,12 +103,10 @@ public class ChangeATargetOfTargetSpellAbilityToSourceEffect extends OneShotEffe
|
|||
}
|
||||
if (oldTargetName != null) {
|
||||
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 {
|
||||
if (twoTimesTarget) {
|
||||
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());
|
||||
}
|
||||
game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its no valid target for " + stackObject.getLogName());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -104,6 +104,10 @@ public class CopyEffect extends ContinuousEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
if (affectedObjectList.isEmpty()) {
|
||||
this.discard();
|
||||
return false;
|
||||
}
|
||||
Permanent permanent = affectedObjectList.get(0).getPermanent(game);
|
||||
if (permanent == null) {
|
||||
permanent = (Permanent) game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD, source.getSourceObjectZoneChangeCounter());
|
||||
|
|
|
@ -111,13 +111,13 @@ public class PutTopCardOfLibraryIntoGraveEachPlayerEffect extends OneShotEffect
|
|||
StringBuilder sb = new StringBuilder();
|
||||
switch (targetController) {
|
||||
case OPPONENT:
|
||||
sb.append("Each opponent ");
|
||||
sb.append("each opponent ");
|
||||
break;
|
||||
case ANY:
|
||||
sb.append("Each player ");
|
||||
sb.append("each player ");
|
||||
break;
|
||||
case NOT_YOU:
|
||||
sb.append("Each other player ");
|
||||
sb.append("each other player ");
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("TargetController type not supported.");
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -122,7 +122,10 @@ class CrewCost extends CostImpl {
|
|||
public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
|
||||
int sumPower = 0;
|
||||
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) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* 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) {
|
||||
if (spell != null) {
|
||||
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()) {
|
||||
if (!target.isNotTarget() && target.getTargets().contains(this.getSourceId())) {
|
||||
return true;
|
||||
|
|
|
@ -29,7 +29,6 @@ package mage.cards;
|
|||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.*;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectImpl;
|
||||
import mage.Mana;
|
||||
|
@ -53,10 +52,8 @@ import mage.game.command.Commander;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentCard;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
import mage.util.GameLog;
|
||||
import mage.watchers.Watcher;
|
||||
import org.apache.log4j.Logger;
|
||||
|
@ -315,11 +312,11 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
public String getTokenSetCode() {
|
||||
return tokenSetCode;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getTokenDescriptor() {
|
||||
return tokenDescriptor;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Mana> getMana() {
|
||||
|
@ -342,22 +339,29 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
Zone fromZone = game.getState().getZone(objectId);
|
||||
ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, sourceId, ownerId, fromZone, toZone, appliedEffects);
|
||||
ZoneChangeInfo zoneChangeInfo;
|
||||
if (toZone == Zone.LIBRARY) {
|
||||
zoneChangeInfo = new ZoneChangeInfo.Library(event, flag /* put on top */);
|
||||
} else if (toZone == Zone.BATTLEFIELD) {
|
||||
zoneChangeInfo = new ZoneChangeInfo.Battlefield(event, flag /* comes into play tapped */);
|
||||
} else {
|
||||
zoneChangeInfo = new ZoneChangeInfo(event);
|
||||
if (null != toZone) {
|
||||
switch (toZone) {
|
||||
case LIBRARY:
|
||||
zoneChangeInfo = new ZoneChangeInfo.Library(event, flag /* put on top */);
|
||||
break;
|
||||
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
|
||||
public boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId) {
|
||||
Card mainCard = getMainCard();
|
||||
ZoneChangeEvent event = new ZoneChangeEvent(mainCard.getId(), ability.getId(), controllerId, fromZone, Zone.STACK);
|
||||
ZoneChangeInfo.Stack info =
|
||||
new ZoneChangeInfo.Stack(event, new Spell(this, ability.copy(), controllerId, event.getFromZone()));
|
||||
ZoneChangeInfo.Stack info
|
||||
= new ZoneChangeInfo.Stack(event, new Spell(this, ability.copy(), controllerId, event.getFromZone()));
|
||||
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())) {
|
||||
game.getPlayer(ownerId).getSideboard().remove(this.getId());
|
||||
removed = true;
|
||||
} else if (game.getPhase() == null) {
|
||||
// E.g. Commander of commander game
|
||||
removed = true;
|
||||
}
|
||||
break;
|
||||
case BATTLEFIELD: // for sacrificing permanents or putting to library
|
||||
|
@ -461,7 +468,9 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
break;
|
||||
}
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
}
|
||||
if(finalAmount > 0) {
|
||||
if (finalAmount > 0) {
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.COUNTERS_ADDED, objectId, getControllerOrOwner(), counter.getName(), amount));
|
||||
}
|
||||
} else {
|
||||
|
@ -656,7 +665,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
}
|
||||
return super.getColor(game);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<String> getSubtype(Game game) {
|
||||
if (game != null) {
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.filter.predicate.mageobject;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Mode;
|
||||
import mage.filter.predicate.Predicate;
|
||||
|
@ -51,7 +52,8 @@ public class NumberOfTargetsPredicate implements Predicate<MageObject> {
|
|||
StackObject stackObject = game.getState().getStack().getStackObject(input.getId());
|
||||
if (stackObject != null) {
|
||||
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()) {
|
||||
numberOfTargets += target.getTargets().size();
|
||||
}
|
||||
|
|