gerge remote-tracking branch 'upstream/master' into feature/UphillBattle

Merging current Master into branch to make sure everything is "up to
date".
This commit is contained in:
Danny Plenge 2018-03-06 13:31:20 +01:00
commit 21a86b8440
217 changed files with 7964 additions and 1498 deletions

View file

@ -147,14 +147,9 @@
https://stackoverflow.com/questions/714243/sax2-driver-class-org-apache-crimson-parser-xmlreaderimpl-not-found-when-using
-->
<dependency>
<groupId>batik</groupId>
<artifactId>batik-transcoder</artifactId>
<version>1.6-1</version>
</dependency>
<dependency>
<groupId>crimson</groupId>
<artifactId>crimson</artifactId>
<version>1.1.3</version>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-transcoder</artifactId>
<version>1.7</version>
</dependency>
<!-- svg support end -->
<dependency>

View file

@ -645,6 +645,8 @@
<EmptySpace max="-2" attributes="0"/>
<Component id="chkRules" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
<Component id="chkUnique" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
<Component id="cardCountLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cardCount" min="-2" pref="48" max="-2" attributes="0"/>
@ -659,6 +661,7 @@
<Group type="103" groupAlignment="0" attributes="0">
<Component id="chkTypes" max="32767" attributes="0"/>
<Component id="chkRules" alignment="1" max="32767" attributes="0"/>
<Component id="chkUnique" alignment="1" max="32767" attributes="0"/>
<Component id="chkNames" alignment="1" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
@ -846,6 +849,29 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="chkRulesActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="chkUnique">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" value="Unique"/>
<Property name="toolTipText" type="java.lang.String" value="Singleton rules."/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="4"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[69, 16]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[69, 16]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[69, 16]"/>
</Property>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="chkUniqueActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="jButtonSearch">
<Properties>
<Property name="text" type="java.lang.String" value="Search"/>

View file

@ -232,7 +232,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
FilterCard filter = new FilterCard();
String name = jTextFieldSearch.getText().trim();
filter.add(new CardTextPredicate(name, chkNames.isSelected(), chkTypes.isSelected(), chkRules.isSelected()));
filter.add(new CardTextPredicate(name, chkNames.isSelected(), chkTypes.isSelected(), chkRules.isSelected(), chkUnique.isSelected()));
if (limited) {
ArrayList<Predicate<MageObject>> predicates = new ArrayList<>();
@ -543,6 +543,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
chkNames = new javax.swing.JCheckBox();
chkTypes = new javax.swing.JCheckBox();
chkRules = new javax.swing.JCheckBox();
chkUnique = new javax.swing.JCheckBox();
jButtonSearch = new javax.swing.JButton();
jButtonClean = new javax.swing.JButton();
cardCountLabel = new javax.swing.JLabel();
@ -1062,6 +1063,22 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
chkRulesActionPerformed(evt);
}
});
chkUnique.setSelected(true);
chkUnique.setText("Unique");
chkUnique.setToolTipText("Singleton results only.");
chkUnique.setFocusable(false);
chkUnique.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT);
chkUnique.setMaximumSize(new java.awt.Dimension(69, 16));
chkUnique.setMinimumSize(new java.awt.Dimension(69, 16));
chkUnique.setPreferredSize(new java.awt.Dimension(69, 16));
chkUnique.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
chkUnique.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
chkUniqueActionPerformed(evt);
}
});
jButtonSearch.setText("Search");
jButtonSearch.setToolTipText("Performs the search.");
@ -1109,6 +1126,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
.addComponent(chkTypes, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(chkRules, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(chkUnique, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(5, 5, 5)
.addComponent(cardCountLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@ -1122,6 +1141,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
.addGroup(cardSelectorBottomPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(chkTypes, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(chkRules, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(chkUnique, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(chkNames, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(cardSelectorBottomPanelLayout.createSequentialGroup()
.addGroup(cardSelectorBottomPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -1341,6 +1361,10 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
// TODO add your handling code here:
}//GEN-LAST:event_chkRulesActionPerformed
private void chkUniqueActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkRulesActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_chkRulesActionPerformed
private void btnExpansionSearchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnExpansionSearchActionPerformed
FastSearchUtil.showFastSearchForStringComboBox(cbExpansionSet, "Select set or expansion");
}//GEN-LAST:event_btnExpansionSearchActionPerformed
@ -1418,6 +1442,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
private javax.swing.JCheckBox chkPennyDreadful;
private javax.swing.JCheckBox chkPiles;
private javax.swing.JCheckBox chkRules;
private javax.swing.JCheckBox chkUnique;
private javax.swing.JCheckBox chkTypes;
private javax.swing.JButton jButtonAddToMain;
private javax.swing.JButton jButtonAddToSideboard;

View file

@ -64,7 +64,6 @@ public class FeedbackPanel extends javax.swing.JPanel {
private static final Logger LOGGER = Logger.getLogger(FeedbackPanel.class);
public enum FeedbackMode {
INFORM, QUESTION, CONFIRM, CANCEL, SELECT, END
}

View file

@ -394,7 +394,7 @@ public class HelperPanel extends JPanel {
}
} else {
// inform about other players
this.setOpaque(false);
this.mainPanel.setOpaque(false);
}
if (buttons.size() == 0) {

View file

@ -302,7 +302,7 @@ public class CardPanelRenderImpl extends CardPanel {
= new CardPanelAttributes(cardWidth, cardHeight, isChoosable(), isSelected());
// Draw card itself
cardRenderer.draw(g2d, attribs);
cardRenderer.draw(g2d, attribs, image);
// Done
g2d.dispose();

View file

@ -17,10 +17,10 @@ import mage.view.PermanentView;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.RasterFormatException;
import java.util.ArrayList;
import java.util.List;
import java.awt.image.BufferedImage;
/**
* @author stravant@gmail.com
@ -201,7 +201,8 @@ public abstract class CardRenderer {
// The Draw Method
// The draw method takes the information caculated by the constructor
// and uses it to draw to a concrete size of card and graphics.
public void draw(Graphics2D g, CardPanelAttributes attribs) {
public void draw(Graphics2D g, CardPanelAttributes attribs, BufferedImage image) {
// Pre template method layout, to calculate shared layout info
layout(attribs.cardWidth, attribs.cardHeight);
isSelected = attribs.isSelected;
@ -211,7 +212,7 @@ public abstract class CardRenderer {
drawBorder(g);
drawBackground(g);
drawArt(g);
drawFrame(g);
drawFrame(g, image);
if (!cardView.isAbility()) {
drawOverlays(g);
drawCounters(g);
@ -226,7 +227,7 @@ public abstract class CardRenderer {
protected abstract void drawArt(Graphics2D g);
protected abstract void drawFrame(Graphics2D g);
protected abstract void drawFrame(Graphics2D g, BufferedImage image);
// Template methods that are possible to override, but unlikely to be
// overridden.
@ -462,22 +463,44 @@ public abstract class CardRenderer {
}
} else {
StringBuilder sbType = new StringBuilder();
for (SuperType superType : cardView.getSuperTypes()) {
sbType.append(superType).append(' ');
}
for (CardType cardType : cardView.getCardTypes()) {
sbType.append(cardType.toString()).append(' ');
}
if (!cardView.getSubTypes().isEmpty()) {
sbType.append("- ");
for (SubType subType : cardView.getSubTypes()) {
sbType.append(subType).append(' ');
String spType = getCardSuperTypeLine();
String subType = getCardSubTypeLine();
if (spType.equalsIgnoreCase("")) {
sbType.append(subType);
} else {
sbType.append(spType);
if (!subType.equalsIgnoreCase("")) {
sbType.append("- ");
sbType.append(subType);
}
}
return sbType.toString();
}
}
protected String getCardSuperTypeLine() {
StringBuilder spType = new StringBuilder();
for (SuperType superType : cardView.getSuperTypes()) {
spType.append(superType).append(' ');
}
for (CardType cardType : cardView.getCardTypes()) {
spType.append(cardType.toString()).append(' ');
}
return spType.toString();
}
protected String getCardSubTypeLine() {
StringBuilder subType = new StringBuilder();
if (!cardView.getSubTypes().isEmpty()) {
for (SubType sType : cardView.getSubTypes()) {
subType.append(sType).append(' ');
}
}
return subType.toString();
}
// Set the card art image (CardPanel will give it to us when it
// is loaded and ready)
public void setArtImage(Image image) {

View file

@ -51,8 +51,8 @@ public final class CardRendererUtils {
// Return the buffered image
return bimage;
}
private static Color abitbrighter(Color c) {
public static Color abitbrighter(Color c) {
int r = c.getRed();
int g = c.getGreen();
int b = c.getBlue();
@ -68,7 +68,7 @@ public final class CardRendererUtils {
alpha);
}
private static Color abitdarker(Color c) {
public static Color abitdarker(Color c) {
int r = c.getRed();
int g = c.getGreen();
int b = c.getBlue();
@ -108,6 +108,35 @@ public final class CardRendererUtils {
g.drawLine(x + 1 + bevel, y + h - 2, x + 1 + bevel + w - 2 * bevel - 2, y + h - 2);
}
public static void drawZendikarLandBox(Graphics2D g, int x, int y, int w, int h, int bevel, Paint border, Paint fill) {
g.setColor(new Color(0, 0, 0, 150));
g.drawOval(x - 1, y, bevel * 2, h);
g.setPaint(border);
g.drawOval(x, y, bevel * 2 - 1, h - 1);
g.drawOval(x + w - bevel * 2, y, bevel * 2 - 1, h - 1);
g.drawOval(x + 1, y + 1, bevel * 2 - 3, h - 3);
g.drawOval(x + 1 + w - bevel * 2, y + 1, bevel * 2 - 3, h - 3);
// The big circle in the middle.. (diameter=2+1/4 of height) - 3/4 above line, 1/2 below 0.75 + .5 + 1= 2.25 = 9/4
g.drawOval(x + w / 2 - h - h / 8, y - 3 * h / 4, 9 * h / 4, 9 * h / 4);
g.drawRect(x + bevel, y, w - 2 * bevel, h - 1);
g.drawRect(x + 1 + bevel, y + 1, w - 2 * bevel - 2, h - 3);
g.setPaint(fill);
g.setColor(abitbrighter(g.getColor()));
g.drawLine(x + 1 + bevel, y + 1, x + 1 + bevel + w - 2 * bevel - 2, y + 1);
g.setPaint(fill);
g.setColor(abitdarker(g.getColor()));
g.drawLine(x + 1 + bevel, y + h - 2, x + 1 + bevel + w - 2 * bevel - 2, y + h - 2);
g.fillOval(x + 2, y + 2, bevel * 2 - 4, h - 4);
g.fillOval(x + 2 + w - bevel * 2, y + 2, bevel * 2 - 4, h - 4);
g.fillRect(x + bevel, y + 2, w - 2 * bevel, h - 4);
g.fillOval(x + w / 2 - h - h / 8, y - 3 * h / 4, 9 * h / 4, 9 * h / 4);
}
// Get the width of a mana cost rendered with ManaSymbols.draw
public static int getManaCostWidth(String manaCost, int symbolSize) {
int width = 0;

View file

@ -7,7 +7,11 @@ package org.mage.card.arcane;
import java.awt.*;
import java.awt.font.*;
import java.awt.geom.Arc2D;
import java.awt.geom.Area;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
@ -68,6 +72,13 @@ public class ModernCardRenderer extends CardRenderer {
BufferedImage img = CardRendererUtils.toBufferedImage(icon.getImage());
return new TexturePaint(img, new Rectangle(0, 0, img.getWidth(), img.getHeight()));
}
private static BufferedImage loadBackgroundImage(String name) {
URL url = ModernCardRenderer.class.getResource("/cardrender/background_texture_" + name + ".png");
ImageIcon icon = new ImageIcon(url);
BufferedImage img = CardRendererUtils.toBufferedImage(icon.getImage());
return img;
}
private static BufferedImage loadFramePart(String name) {
URL url = ModernCardRenderer.class.getResource("/cardrender/" + name + ".png");
@ -97,7 +108,18 @@ public class ModernCardRenderer extends CardRenderer {
public static final Paint BG_TEXTURE_ARTIFACT = loadBackgroundTexture("artifact");
public static final Paint BG_TEXTURE_LAND = loadBackgroundTexture("land");
public static final Paint BG_TEXTURE_VEHICLE = loadBackgroundTexture("vehicle");
public static final BufferedImage BG_IMG_WHITE = loadBackgroundImage("white");
public static final BufferedImage BG_IMG_BLUE = loadBackgroundImage("blue");
public static final BufferedImage BG_IMG_BLACK = loadBackgroundImage("black");
public static final BufferedImage BG_IMG_RED = loadBackgroundImage("red");
public static final BufferedImage BG_IMG_GREEN = loadBackgroundImage("green");
public static final BufferedImage BG_IMG_GOLD = loadBackgroundImage("gold");
public static final BufferedImage BG_IMG_ARTIFACT = loadBackgroundImage("artifact");
public static final BufferedImage BG_IMG_LAND = loadBackgroundImage("land");
public static final BufferedImage BG_IMG_VEHICLE = loadBackgroundImage("vehicle");
public static final BufferedImage BG_IMG_COLORLESS = loadBackgroundImage("colorless");
public static final BufferedImage FRAME_INVENTION = loadFramePart("invention_frame");
public static final Color BORDER_WHITE = new Color(216, 203, 188);
@ -279,27 +301,30 @@ public class ModernCardRenderer extends CardRenderer {
// Just draw a brown rectangle
drawCardBack(g);
} else {
BufferedImage bufferedImage = new BufferedImage(300, 300, BufferedImage.TYPE_INT_RGB);
// Set texture to paint with
g.setPaint(getBackgroundPaint(cardView.getColor(), cardView.getCardTypes(), cardView.getSubTypes()));
BufferedImage bg = getBackgroundImage(cardView.getColor(), cardView.getCardTypes(), cardView.getSubTypes());
if (bg == null) {
return;
}
int bgw = bg.getWidth();
int bgh = bg.getHeight();
// Draw main part (most of card)
g.fillRoundRect(
borderWidth, borderWidth,
RoundRectangle2D rr = new RoundRectangle2D.Double(borderWidth, borderWidth,
cardWidth - borderWidth * 2, cardHeight - borderWidth * 4 - cornerRadius * 2,
cornerRadius - 1, cornerRadius - 1);
Area a = new Area(rr);
// Draw the M15 rounded "swoosh" at the bottom
g.fillRoundRect(
borderWidth, cardHeight - borderWidth * 4 - cornerRadius * 4,
RoundRectangle2D rr2 = new RoundRectangle2D.Double(borderWidth, cardHeight - borderWidth * 4 - cornerRadius * 4,
cardWidth - borderWidth * 2, cornerRadius * 4,
cornerRadius * 2, cornerRadius * 2);
// Draw the cutout into the "swoosh" for the textbox to lie over
g.fillRect(
borderWidth + contentInset, cardHeight - borderWidth * 5,
cardWidth - borderWidth * 2 - contentInset * 2, borderWidth * 2);
a.add(new Area(rr2));
// Draw the M15 rounded "swoosh" at the bottom
Rectangle r = new Rectangle(borderWidth + contentInset, cardHeight - borderWidth * 5, cardWidth - borderWidth * 2 - contentInset * 2, borderWidth * 2);
a.add(new Area(r));
g.setClip(a);
g.drawImage(bg, 0, 0, cardWidth, cardHeight, 0, 0, bgw, bgh, BOX_BLUE, null);
g.setClip(null);
}
}
@ -312,6 +337,8 @@ public class ModernCardRenderer extends CardRenderer {
Rectangle2D rect;
if (useInventionFrame()) {
rect = new Rectangle2D.Float(0, 0, 1, 1);
} else if (isZendikarFullArtLand()) {
rect = new Rectangle2D.Float(.079f, .11f, .84f, .84f);
} else if (cardView.getFrameStyle().isFullArt() || (cardView.isToken())) {
rect = new Rectangle2D.Float(.079f, .11f, .84f, .63f);
} else {
@ -330,6 +357,10 @@ public class ModernCardRenderer extends CardRenderer {
}
}
private boolean isZendikarFullArtLand() {
return cardView.getFrameStyle() == FrameStyle.BFZ_FULL_ART_BASIC || cardView.getFrameStyle() == FrameStyle.ZEN_FULL_ART_BASIC;
}
protected boolean isSourceArtFullArt() {
int color = artImage.getRGB(0, artImage.getHeight() / 2);
return (((color & 0x00FF0000) > 0x00200000)
@ -352,7 +383,7 @@ public class ModernCardRenderer extends CardRenderer {
if (artImage != null && !cardView.isFaceDown()) {
boolean useFaceArt = false;
if (faceArtImage != null) {
if (faceArtImage != null && !isZendikarFullArtLand()) {
useFaceArt = true;
}
@ -395,7 +426,7 @@ public class ModernCardRenderer extends CardRenderer {
totalContentInset + 1, totalContentInset + boxHeight,
contentWidth - 2, typeLineY - totalContentInset - boxHeight,
sourceRect, shouldPreserveAspect);
} else {
} else if (!isZendikarFullArtLand()) {
drawArtIntoRect(g,
totalContentInset + 1, totalContentInset + boxHeight,
contentWidth - 2, typeLineY - totalContentInset - boxHeight,
@ -405,7 +436,7 @@ public class ModernCardRenderer extends CardRenderer {
}
@Override
protected void drawFrame(Graphics2D g) {
protected void drawFrame(Graphics2D g, BufferedImage image) {
// Get the card colors to base the frame on
ObjectColor frameColors = getFrameObjectColor();
@ -421,12 +452,13 @@ public class ModernCardRenderer extends CardRenderer {
// Draw the main card content border
g.setPaint(borderPaint);
if (cardView.getFrameStyle() == FrameStyle.KLD_INVENTION) {
g.drawImage(FRAME_INVENTION, 0, 0, cardWidth, cardHeight, null);
g.drawRect(
totalContentInset, typeLineY,
contentWidth - 1, cardHeight - borderWidth * 3 - typeLineY - 1);
} else {
} else if (!isZendikarFullArtLand()) {
g.drawRect(
totalContentInset, totalContentInset,
contentWidth - 1, cardHeight - borderWidth * 3 - totalContentInset - 1);
@ -437,11 +469,13 @@ public class ModernCardRenderer extends CardRenderer {
g.setPaint(new Color(255, 255, 255, 150));
} else {
g.setPaint(textboxPaint);
}
g.fillRect(
totalContentInset + 1, typeLineY,
contentWidth - 2, cardHeight - borderWidth * 3 - typeLineY - 1);
if (!isZendikarFullArtLand()) {
g.fillRect(
totalContentInset + 1, typeLineY,
contentWidth - 2, cardHeight - borderWidth * 3 - typeLineY - 1);
}
// If it's a planeswalker, extend the textbox left border by some
if (cardView.isPlanesWalker()) {
@ -451,7 +485,7 @@ public class ModernCardRenderer extends CardRenderer {
cardWidth / 16, cardHeight - typeLineY - boxHeight - borderWidth * 3);
}
if (cardView.getFrameStyle() != FrameStyle.KLD_INVENTION) {
if (cardView.getFrameStyle() != FrameStyle.KLD_INVENTION && !isZendikarFullArtLand()) {
// Draw a shadow highlight at the right edge of the content frame
g.setColor(new Color(0, 0, 0, 100));
g.fillRect(
@ -470,26 +504,31 @@ public class ModernCardRenderer extends CardRenderer {
cardWidth - 2 * borderWidth, boxHeight,
contentInset,
borderPaint, boxColor);
// Draw the type line box
CardRendererUtils.drawRoundedBox(g,
borderWidth, typeLineY,
cardWidth - 2 * borderWidth, boxHeight,
contentInset,
borderPaint, boxColor);
if (!isZendikarFullArtLand()) {
CardRendererUtils.drawRoundedBox(g,
borderWidth, typeLineY,
cardWidth - 2 * borderWidth, boxHeight,
contentInset,
borderPaint, boxColor);
// Draw a small separator between the type line and box, and shadow
// at the left of the texbox, and above the name line
g.setColor(new Color(0, 0, 0, 150));
g.fillRect(
totalContentInset - 1, totalContentInset - 1,
contentWidth + 1, 1);
g.fillRect(
totalContentInset + 1, typeLineY + boxHeight,
contentWidth - 2, 1);
g.fillRect(
cardWidth - totalContentInset - 1, typeLineY + boxHeight,
1, cardHeight - borderWidth * 3 - typeLineY - boxHeight);
// Draw a small separator between the type line and box, and shadow
// at the left of the texbox, and above the name line
g.setColor(new Color(0, 0, 0, 150));
g.fillRect(
totalContentInset - 1, totalContentInset - 1,
contentWidth + 1, 1);
g.fillRect(
totalContentInset + 1, typeLineY + boxHeight,
contentWidth - 2, 1);
g.fillRect(
cardWidth - totalContentInset - 1, typeLineY + boxHeight,
1, cardHeight - borderWidth * 3 - typeLineY - boxHeight);
// Draw the type line
drawTypeLine(g, getCardTypeLine(),
totalContentInset, typeLineY,
contentWidth, boxHeight, true);
}
// Draw the transform circle
int nameOffset = drawTransformationCircle(g, borderPaint);
@ -502,20 +541,163 @@ public class ModernCardRenderer extends CardRenderer {
totalContentInset + nameOffset, totalContentInset,
contentWidth - nameOffset, boxHeight);
// Draw the type line
drawTypeLine(g, getCardTypeLine(),
totalContentInset, typeLineY,
contentWidth, boxHeight);
// Draw the textbox rules
drawRulesText(g, textboxKeywords, textboxRules,
totalContentInset + 2, typeLineY + boxHeight + 2,
contentWidth - 4, cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3);
if (!isZendikarFullArtLand()) {
drawRulesText(g, textboxKeywords, textboxRules,
totalContentInset + 2, typeLineY + boxHeight + 2,
contentWidth - 4, cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3);
} else {
int x = totalContentInset;
int y = typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset;
int w = contentWidth;
int h = boxHeight - 4;
CardRendererUtils.drawZendikarLandBox(g,
x, y, w, h,
contentInset,
borderPaint, boxColor);
drawTypeLine(g, getCardSuperTypeLine(),
totalContentInset + contentInset, typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset,
contentWidth / 2 - boxHeight, boxHeight - 4, false);
drawTypeLine(g, getCardSubTypeLine(),
totalContentInset + 4 * contentWidth / 7 + boxHeight, typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset,
3 * contentWidth / 7 - boxHeight - contentInset, boxHeight - 4, true);
if (cardView.getFrameStyle() == FrameStyle.ZEN_FULL_ART_BASIC) {
// Draw curved lines (old Zendikar land style) - bigger (around 6%) inset on curve on bottom than inset (around 4.5%) on top...
int x2 = x + contentWidth;
int y2 = y;
int thisy = totalContentInset + boxHeight;
drawZendikarCurvedFace(g, image, x, thisy, x2, y2,
boxColor, borderPaint);
} else if (cardView.getFrameStyle() == FrameStyle.BFZ_FULL_ART_BASIC) {
// Draw curved lines (BFZ land style)
int y2 = y;
int yb = totalContentInset + boxHeight;
int topxdelta = 45 * contentWidth / 1000;
int endydelta = 60 * (totalContentInset + y2) / 265;
int x2 = x + contentWidth;
// Curve ends at 60 out of 265
drawBFZCurvedFace(g, image, x, yb, x2, y2,
topxdelta, endydelta,
boxColor, borderPaint);
}
drawRulesText(g, textboxKeywords, textboxRules,
x, y,
w, h);
}
// Draw the bottom right stuff
drawBottomRight(g, borderPaint, boxColor);
}
public void drawZendikarCurvedFace(Graphics2D g2, BufferedImage image, int x, int y, int x2, int y2,
Color boxColor, Paint paint) {
BufferedImage artToUse = faceArtImage;
boolean hadToUseFullArt = false;
if (faceArtImage == null) {
if (artImage == null) {
return;
}
hadToUseFullArt = true;
artToUse = artImage;
}
int srcW = artToUse.getWidth();
int srcH = artToUse.getHeight();
if (hadToUseFullArt) {
// Get a box based on the standard scan from gatherer.
// Width = 185/223 pixels (centered)
// Height = 220/310, 38 pixels from top
int subx = 19 * srcW / 223;
int suby = 38 * srcH / 310;
artToUse = artImage.getSubimage(subx, suby, 185 * srcW / 223, 220 * srcH / 310);
}
Path2D.Double curve = new Path2D.Double();
int ew = x2 - x;
int eh = 700 * (y2 - y) / 335;
Arc2D arc = new Arc2D.Double(x, y - 197 * eh / 700, ew, eh, 0, 360, Arc2D.OPEN);
Arc2D innerarc = new Arc2D.Double(x + 1, y - 197 * eh / 700 + 1, ew - 2, eh - 2, 0, 360, Arc2D.OPEN);
curve.append(new Rectangle2D.Double(x, y, x2 - x, y2 - y), false);
g2.setClip(new Rectangle2D.Double(x, y, x2 - x, y2 - y));
g2.setClip(arc);
Rectangle2D r = curve.getBounds2D();
g2.drawImage(artToUse, x, y, x2 - x, y2 - y, null);
g2.setClip(null);
g2.setClip(new Rectangle2D.Double(x, y, x2 - x, y2 - y));
g2.setColor(CardRendererUtils.abitdarker(boxColor));
g2.draw(arc);
g2.setColor(Color.black);
g2.draw(innerarc);
g2.setClip(null);
}
public void drawBFZCurvedFace(Graphics2D g2, BufferedImage image, int x, int y, int x2, int y2,
int topxdelta, int endydelta,
Color boxColor, Paint paint) {
BufferedImage artToUse = faceArtImage;
boolean hadToUseFullArt = false;
if (faceArtImage == null) {
if (artImage == null) {
return;
}
hadToUseFullArt = true;
artToUse = artImage;
}
int srcW = artToUse.getWidth();
int srcH = artToUse.getHeight();
if (hadToUseFullArt) {
// Get a box based on the standard scan from gatherer.
// Width = 185/223 pixels (centered)
// Height = 220/310, 38 pixels from top
int subx = 19 * srcW / 223;
int suby = 38 * srcH / 310;
artToUse = artImage.getSubimage(subx, suby, 185 * srcW / 223, 220 * srcH / 310);
}
Path2D.Double curve = new Path2D.Double();
curve.moveTo(x + topxdelta, y);
curve.quadTo(x, y + endydelta / 2, x, y + endydelta);
curve.lineTo(x, y2);
curve.lineTo(x2, y2);
curve.lineTo(x2, y + endydelta);
curve.quadTo(x2, y + endydelta / 2, x2 - topxdelta, y);
curve.lineTo(x + topxdelta, y);
Path2D.Double innercurve = new Path2D.Double();
innercurve.moveTo(x + topxdelta, y + 1);
innercurve.quadTo(x + 1, y + endydelta / 2, x + 1, y + endydelta);
innercurve.lineTo(x + 1, y2 - 1);
innercurve.lineTo(x2 - 1, y2 - 1);
innercurve.lineTo(x2 - 1, y + endydelta);
innercurve.quadTo(x2 - 1, y + endydelta / 2, x2 - topxdelta, y + 1);
innercurve.lineTo(x + topxdelta, y + 1);
Rectangle2D r = curve.getBounds2D();
int minX = (int) r.getX();
g2.setClip(curve);
g2.drawImage(artToUse, minX, y, (x2 - x) + (x - minX) * 2, y2 - y, null);
g2.setClip(null);
g2.setColor(CardRendererUtils.abitdarker(boxColor));
g2.setPaint(paint);
g2.draw(curve);
g2.setColor(Color.black);
g2.draw(innercurve);
}
// Draw the name line
protected void drawNameLine(Graphics2D g, String baseName, String manaCost, int x, int y, int w, int h) {
// Width of the mana symbols
@ -566,13 +748,13 @@ public class ModernCardRenderer extends CardRenderer {
}
// Draw the type line (color indicator, types, and expansion symbol)
protected void drawTypeLine(Graphics2D g, String baseTypeLine, int x, int y, int w, int h) {
protected void drawTypeLine(Graphics2D g, String baseTypeLine, int x, int y, int w, int h, boolean withSymbol) {
// Draw expansion symbol
int expansionSymbolWidth;
int expansionSymbolWidth = 0;
if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_RENDERING_SET_SYMBOL, "false").equals("false")) {
if (cardView.isAbility()) {
expansionSymbolWidth = 0;
} else {
} else if (withSymbol) {
expansionSymbolWidth = drawExpansionSymbol(g, x, y, w, h);
}
} else {
@ -792,9 +974,21 @@ public class ModernCardRenderer extends CardRenderer {
}
// Basic mana draw mana symbol in textbox (for basic lands)
if (allRules.size() == 1 && (allRules.get(0) instanceof TextboxBasicManaRule) && cardView.isLand()) {
drawBasicManaTextbox(g, x, y, w, h, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol());
return;
if (allRules.size() == 1 && (allRules.get(0) instanceof TextboxBasicManaRule) && cardView.isLand() || isZendikarFullArtLand()) {
if (!isZendikarFullArtLand()) {
drawBasicManaTextbox(g, x, y, w, h, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol());
return;
} else // Big circle in the middle for Zendikar lands
if (allRules.size() == 1) {
// Size of mana symbol = 9/4 * h, 3/4h above line
drawBasicManaSymbol(g, x + w / 2 - 9 * h / 8 + 1, y - 3 * h / 4, 9 * h / 4, 9 * h / 4, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol());
return;
} else {
if (allRules.size() > 1) {
drawBasicManaSymbol(g, x + w / 2 - h - h / 8, y - 3 * h / 4, 9 * h / 4, 9 * h / 4, cardView.getFrameColor().toString());
}
return;
}
}
// Go through possible font sizes in descending order to find the best fit
@ -847,6 +1041,11 @@ public class ModernCardRenderer extends CardRenderer {
ManaSymbols.draw(g, symbs, x + (w - manaCostWidth) / 2, y + (h - symbHeight) / 2, symbHeight, Color.black, 2);
}
private void drawBasicManaSymbol(Graphics2D g, int x, int y, int w, int h, String symbol) {
String symbs = symbol;
ManaSymbols.draw(g, symbs, x, y, w, Color.black, 2);
}
// Get the first line of the textbox, the keyword string
private static String getKeywordRulesString(ArrayList<TextboxRule> keywords) {
StringBuilder builder = new StringBuilder();
@ -1073,7 +1272,34 @@ public class ModernCardRenderer extends CardRenderer {
return new Color(71, 86, 101);
}
}
// Determine which background image to use from a set of colors
// and the current card.
protected static BufferedImage getBackgroundImage(ObjectColor colors, Collection<CardType> types, SubTypeList subTypes) {
if (subTypes.contains(SubType.VEHICLE)) {
return BG_IMG_VEHICLE;
} else if (types.contains(CardType.LAND)) {
return BG_IMG_LAND;
} else if (types.contains(CardType.ARTIFACT)) {
return BG_IMG_ARTIFACT;
} else if (colors.isMulticolored()) {
return BG_IMG_GOLD;
} else if (colors.isWhite()) {
return BG_IMG_WHITE;
} else if (colors.isBlue()) {
return BG_IMG_BLUE;
} else if (colors.isBlack()) {
return BG_IMG_BLACK;
} else if (colors.isRed()) {
return BG_IMG_RED;
} else if (colors.isGreen()) {
return BG_IMG_GREEN;
} else {
// Colorless
return BG_IMG_COLORLESS;
}
}
// Get the box color for the given colors
protected Color getBoxColor(ObjectColor colors, Collection<CardType> types, boolean isNightCard) {
if (cardView.isAbility()) {

View file

@ -8,6 +8,7 @@ import mage.view.CardView;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
@ -17,6 +18,7 @@ import java.util.List;
public class ModernSplitCardRenderer extends ModernCardRenderer {
private class HalfCardProps {
int x, y, w, h, cw, ch;
String name;
@ -27,7 +29,11 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
ArrayList<TextboxRule> keywords = new ArrayList<>();
}
private static ArrayList<CardType> ONLY_LAND_TYPE = new ArrayList<CardType>() {{add(CardType.LAND);}};
private static ArrayList<CardType> ONLY_LAND_TYPE = new ArrayList<CardType>() {
{
add(CardType.LAND);
}
};
// Right and left halves of the card content
private HalfCardProps rightHalf = new HalfCardProps();
@ -88,20 +94,20 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
// Decide size of divider
if (isAftermath()) {
dividerSize = borderWidth;
dividerAt = (int)(cardHeight*0.54);
dividerAt = (int) (cardHeight * 0.54);
} else {
int availHeight = cardHeight - totalContentInset - 3*borderWidth;
dividerSize = borderWidth*2;
dividerAt = (int)(totalContentInset + availHeight * 0.5 - borderWidth);
int availHeight = cardHeight - totalContentInset - 3 * borderWidth;
dividerSize = borderWidth * 2;
dividerAt = (int) (totalContentInset + availHeight * 0.5 - borderWidth);
}
// Decide size of each halves box
rightHalf.x = leftHalf.x = totalContentInset;
rightHalf.w = leftHalf.w = cardWidth - 2*totalContentInset;
rightHalf.w = leftHalf.w = cardWidth - 2 * totalContentInset;
leftHalf.y = totalContentInset;
leftHalf.h = dividerAt - totalContentInset;
rightHalf.y = dividerAt + dividerSize;
rightHalf.h = cardHeight - rightHalf.y - borderWidth*3;
rightHalf.h = cardHeight - rightHalf.y - borderWidth * 3;
// Content width / height (Exchanged from width / height if the card part is rotated)
if (isAftermath()) {
@ -126,7 +132,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
private ObjectColor getColorFromManaCostHack(ManaCosts costs) {
ObjectColor c = new ObjectColor();
List<String> symbols = costs.getSymbols();
for (String symbol: symbols) {
for (String symbol : symbols) {
if (symbol.contains("W")) {
c.setWhite(true);
} else if (symbol.contains("U")) {
@ -154,18 +160,18 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
// Draw main part (most of card)
g.fillRoundRect(
borderWidth, borderWidth,
cardWidth - 2*borderWidth, leftHalf.h + contentInset - borderWidth - 2*cornerRadius + (cornerRadius - 1),
cardWidth - 2 * borderWidth, leftHalf.h + contentInset - borderWidth - 2 * cornerRadius + (cornerRadius - 1),
cornerRadius - 1, cornerRadius - 1);
// Draw the M15 rounded "swoosh" at the bottom
g.fillRoundRect(
borderWidth, dividerAt - borderWidth - 4*cornerRadius,
cardWidth - 2*borderWidth, cornerRadius * 4,
borderWidth, dividerAt - borderWidth - 4 * cornerRadius,
cardWidth - 2 * borderWidth, cornerRadius * 4,
cornerRadius * 2, cornerRadius * 2);
// Draw the cutout into the "swoosh" for the textbox to lie over
g.fillRect(
borderWidth + contentInset, dividerAt - 2*borderWidth,
borderWidth + contentInset, dividerAt - 2 * borderWidth,
cardWidth - borderWidth * 2 - contentInset * 2, borderWidth * 2);
}
@ -176,8 +182,8 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
// Draw the M15 rounded "swoosh"es at the top and bottom
g.fillRoundRect(
borderWidth, dividerAt + dividerSize + borderWidth,
cardWidth - 2*borderWidth, rightHalf.h - 2*borderWidth,
cornerRadius*2, cornerRadius*2);
cardWidth - 2 * borderWidth, rightHalf.h - 2 * borderWidth,
cornerRadius * 2, cornerRadius * 2);
// Draw the cutout into the "swoosh" for the textbox to lie over
g.fillRect(
@ -236,8 +242,8 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
// Background of textbox
g.setPaint(textboxPaint);
g.fillRect(
1, typeLineY,
half.cw - 2, half.ch - typeLineY - 1);
1, typeLineY,
half.cw - 2, half.ch - typeLineY - 1);
// Draw the name line box
CardRendererUtils.drawRoundedBox(g,
@ -261,7 +267,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
// Draw the type line
drawTypeLine(g, half.typeLineString,
0, typeLineY,
half.cw, boxHeight - 4);
half.cw, boxHeight - 4, true);
// Draw the textbox rules
drawRulesText(g, half.keywords, half.rules,
@ -270,13 +276,13 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
}
private Graphics2D getUnmodifiedHalfContext(Graphics2D g) {
Graphics2D g2 = (Graphics2D)g.create();
Graphics2D g2 = (Graphics2D) g.create();
g2.translate(leftHalf.x, leftHalf.y);
return g2;
}
private Graphics2D getAftermathHalfContext(Graphics2D g) {
Graphics2D g2 = (Graphics2D)g.create();
Graphics2D g2 = (Graphics2D) g.create();
g2.translate(rightHalf.x, rightHalf.y);
g2.rotate(Math.PI / 2);
g2.translate(0, -rightHalf.w);
@ -284,7 +290,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
}
private Graphics2D getLeftHalfContext(Graphics2D g) {
Graphics2D g2 = (Graphics2D)g.create();
Graphics2D g2 = (Graphics2D) g.create();
g2.translate(leftHalf.x, leftHalf.y);
g2.rotate(-Math.PI / 2);
g2.translate(-leftHalf.cw, 0);
@ -292,7 +298,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
}
private Graphics2D getRightHalfContext(Graphics2D g) {
Graphics2D g2 = (Graphics2D)g.create();
Graphics2D g2 = (Graphics2D) g.create();
g2.translate(rightHalf.x, rightHalf.y);
g2.rotate(-Math.PI / 2);
g2.translate(-rightHalf.cw, 0);
@ -300,13 +306,13 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
}
@Override
protected void drawFrame(Graphics2D g) {
protected void drawFrame(Graphics2D g, BufferedImage image) {
if (isAftermath()) {
drawSplitHalfFrame(getUnmodifiedHalfContext(g), leftHalf, (int)(leftHalf.ch * TYPE_LINE_Y_FRAC));
drawSplitHalfFrame(getUnmodifiedHalfContext(g), leftHalf, (int) (leftHalf.ch * TYPE_LINE_Y_FRAC));
drawSplitHalfFrame(getAftermathHalfContext(g), rightHalf, (rightHalf.ch - boxHeight) / 2);
} else {
drawSplitHalfFrame(getLeftHalfContext(g), leftHalf, (int)(leftHalf.ch * TYPE_LINE_Y_FRAC));
drawSplitHalfFrame(getRightHalfContext(g), rightHalf, (int)(rightHalf.ch * TYPE_LINE_Y_FRAC));
drawSplitHalfFrame(getLeftHalfContext(g), leftHalf, (int) (leftHalf.ch * TYPE_LINE_Y_FRAC));
drawSplitHalfFrame(getRightHalfContext(g), rightHalf, (int) (rightHalf.ch * TYPE_LINE_Y_FRAC));
if (isFuse()) {
Graphics2D g2 = getRightHalfContext(g);
int totalFuseBoxWidth = rightHalf.cw * 2 + 2 * borderWidth + dividerSize;
@ -319,7 +325,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
borderPaint, boxColor);
drawNameLine(g2, "Fuse (You may cast both halves from your hand)", "",
0, rightHalf.ch,
totalFuseBoxWidth - 2*borderWidth, boxHeight);
totalFuseBoxWidth - 2 * borderWidth, boxHeight);
}
}
}

View file

@ -66,7 +66,7 @@ public class GathererSets implements Iterable<DownloadJob> {
//"APAC" -- gatherer do not have that set, scrly have PALP
//"ARENA" -- is't many set with different codes, not one
"CLASH", "CP", "DD3GVL", "DPA", "EURO", "FNMP", "GPX", "GRC", "GUR", "H17", "JR", "MBP", "MGDC", "MLP", "MPRP", "MPS-AKH", "PTC", "S00", "S99", "SUS", "SWS", "UGIN", "UGL", "V10", "V17", "WMCQ", // need to fix
"H09", "PD2", "PD3", "UNH", "CM1", "E02", "V11", "M25", "UST", "IMA", "DD2", "EVG", "DDC", "DDE", "DDD", "DDT", "8EB", "9EB", "CHR" // ok
"H09", "PD2", "PD3", "UNH", "CM1", "E02", "V11", "A25", "UST", "IMA", "DD2", "EVG", "DDC", "DDE", "DDD", "DDT", "8EB", "9EB", "CHR" // ok
// current testing
};

View file

@ -208,7 +208,7 @@ public enum ScryfallImageSource implements CardImageSource {
supportedSets.add("RIX");
supportedSets.add("WMCQ");
supportedSets.add("PPRO");
// supportedSets.add("A25");
supportedSets.add("A25");
// supportedSets.add("DOM");
// supportedSets.add("M19");

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 685 B

After

Width:  |  Height:  |  Size: 19 KiB

View file

@ -73,6 +73,6 @@ dd3evg=ddaevg
dd3gvl=ddagvl
dd3jvc=ddajvc
# Remove setname as soon as the images can be downloaded
ignore.urls=TOK,M19,M25,DOM,H17
ignore.urls=TOK,M19,DOM,H17
# sets ordered by release time (newest goes first)
token.lookup.order=M19,M25,DOM,E02,RIX,UST,XLN,IMA,H17,C17,V17,E01,DDT,CMA,HOU,MM3,DDS,AKH,DD3DVD,DD3EVG,DD3GVL,DD3JVC,H09,AER,PCA,C16,V16,MPS,KLD,DDR,CN2,EMN,EMA,SOI,DDQ,CP,CMA,ARENA,SUS,APAC,EURO,UGIN,C15,OGW,EXP,DDP,BFZ,DRB,V09,V10,V11,V12,V13,V14,V15,TPR,MPRP,DD3,DDO,ORI,MM2,PTC,DTK,FRF,KTK,M15,VMA,CNS,JOU,BNG,THS,DDL,M14,MMA,DGM,GTC,RTR,M13,AVR,DDI,DKA,ISD,M12,NPH,MBS,SOM,M11,ROE,DDE,WWK,ZEN,M10,GVL,ARB,DVD,CFX,JVC,ALA,EVE,SHM,EVG,MOR,LRW,10E,CLS,CHK,GRC
token.lookup.order=M19,A25,DOM,E02,RIX,UST,XLN,IMA,H17,C17,V17,E01,DDT,CMA,HOU,MM3,DDS,AKH,DD3DVD,DD3EVG,DD3GVL,DD3JVC,H09,AER,PCA,C16,V16,MPS,KLD,DDR,CN2,EMN,EMA,SOI,DDQ,CP,CMA,ARENA,SUS,APAC,EURO,UGIN,C15,OGW,EXP,DDP,BFZ,DRB,V09,V10,V11,V12,V13,V14,V15,TPR,MPRP,DD3,DDO,ORI,MM2,PTC,DTK,FRF,KTK,M15,VMA,CNS,JOU,BNG,THS,DDL,M14,MMA,DGM,GTC,RTR,M13,AVR,DDI,DKA,ISD,M12,NPH,MBS,SOM,M11,ROE,DDE,WWK,ZEN,M10,GVL,ARB,DVD,CFX,JVC,ALA,EVE,SHM,EVG,MOR,LRW,10E,CLS,CHK,GRC

View file

@ -32,7 +32,6 @@ import java.lang.reflect.UndeclaredThrowableException;
import java.net.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
import javax.swing.*;
import mage.MageException;
import mage.cards.decks.DeckCardLists;
import mage.cards.repository.CardInfo;
@ -1437,12 +1436,9 @@ public class SessionImpl implements Session {
@Override
public boolean endUserSession(String userSessionId) {
try {
if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to end userSessionId " + userSessionId + '?', "WARNING",
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
if (isConnected()) {
server.endUserSession(sessionId, userSessionId);
return true;
}
if (isConnected()) {
server.endUserSession(sessionId, userSessionId);
return true;
}
} catch (MageException ex) {
handleMageException(ex);
@ -1455,12 +1451,9 @@ public class SessionImpl implements Session {
@Override
public boolean muteUserChat(String userName, long durationMinutes) {
try {
if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to mute user " + userName + " for " + durationMinutes + " minutes?", "WARNING",
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
if (isConnected()) {
server.muteUser(sessionId, userName, durationMinutes);
return true;
}
if (isConnected()) {
server.muteUser(sessionId, userName, durationMinutes);
return true;
}
} catch (MageException ex) {
handleMageException(ex);
@ -1473,12 +1466,9 @@ public class SessionImpl implements Session {
@Override
public boolean setActivation(String userName, boolean active) {
try {
if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to set active to " + active + " for user: " + userName + '?', "WARNING",
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
if (isConnected()) {
server.setActivation(sessionId, userName, active);
return true;
}
if (isConnected()) {
server.setActivation(sessionId, userName, active);
return true;
}
} catch (MageException ex) {
handleMageException(ex);
@ -1491,20 +1481,9 @@ public class SessionImpl implements Session {
@Override
public boolean toggleActivation(String userName) {
try {
if (JOptionPane.showConfirmDialog(null, "Did you want to set user: " + userName + " to active?", "WARNING",
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
return setActivation(userName, true);
}
if (JOptionPane.showConfirmDialog(null, "Did you want to set user: " + userName + " to INactive?", "WARNING",
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
return setActivation(userName, false);
}
if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to toggle activation for user: " + userName + '?', "WARNING",
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
if (isConnected()) {
server.toggleActivation(sessionId, userName);
return true;
}
if (isConnected()) {
server.toggleActivation(sessionId, userName);
return true;
}
} catch (MageException ex) {
handleMageException(ex);
@ -1517,12 +1496,9 @@ public class SessionImpl implements Session {
@Override
public boolean lockUser(String userName, long durationMinute) {
try {
if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to lock user: " + userName + " for " + durationMinute + " minutes?", "WARNING",
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
if (isConnected()) {
server.lockUser(sessionId, userName, durationMinute);
return true;
}
if (isConnected()) {
server.lockUser(sessionId, userName, durationMinute);
return true;
}
} catch (MageException ex) {
handleMageException(ex);

View file

@ -345,22 +345,53 @@ public class ConsolePanel extends javax.swing.JPanel {
private void btnEndSessionActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnEndSessionActionPerformed
int row = this.tblUsers.convertRowIndexToModel(tblUsers.getSelectedRow());
ConsoleFrame.getSession().endUserSession((String) tableUserModel.getValueAt(row, TableUserModel.POS_GAME_INFO));
String userSessionId = (String) tableUserModel.getValueAt(row, TableUserModel.POS_GAME_INFO);
if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to end userSessionId " + userSessionId + '?', "WARNING",
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
ConsoleFrame.getSession().endUserSession(userSessionId);
}
}//GEN-LAST:event_btnEndSessionActionPerformed
private void btnMuteUserActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnMuteUserActionPerformed
int row = this.tblUsers.convertRowIndexToModel(tblUsers.getSelectedRow());
ConsoleFrame.getSession().muteUserChat((String) tableUserModel.getValueAt(row, TableUserModel.POS_USER_NAME), ((Number) spinnerMuteDurationMinutes.getValue()).longValue());
int row = this.tblUsers.convertRowIndexToModel(tblUsers.getSelectedRow());
String userName = (String) tableUserModel.getValueAt(row, TableUserModel.POS_USER_NAME);
long durationMinute = ((Number) spinnerMuteDurationMinutes.getValue()).longValue();
if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to mute user: " + userName + " for " + durationMinute + " minutes?", "WARNING",
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
ConsoleFrame.getSession().muteUserChat(userName, durationMinute);
}
}//GEN-LAST:event_btnMuteUserActionPerformed
private void btnDeActivateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDeActivateActionPerformed
int row = this.tblUsers.convertRowIndexToModel(tblUsers.getSelectedRow());
ConsoleFrame.getSession().toggleActivation((String) tableUserModel.getValueAt(row, TableUserModel.POS_USER_NAME));
String userName = (String) tableUserModel.getValueAt(row, TableUserModel.POS_USER_NAME);
if (JOptionPane.showConfirmDialog(null, "Did you want to set user: " + userName + " to active?", "WARNING",
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
ConsoleFrame.getSession().setActivation(userName, true);
return;
}
if (JOptionPane.showConfirmDialog(null, "Did you want to set user: " + userName + " to inactive?", "WARNING",
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
ConsoleFrame.getSession().setActivation(userName, false);
return;
}
if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to toggle activation for user: " + userName + '?', "WARNING",
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
ConsoleFrame.getSession().toggleActivation(userName);
return;
}
}//GEN-LAST:event_btnDeActivateActionPerformed
private void btnLockUserActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnLockUserActionPerformed
int row = this.tblUsers.convertRowIndexToModel(tblUsers.getSelectedRow());
ConsoleFrame.getSession().lockUser((String) tableUserModel.getValueAt(row, TableUserModel.POS_USER_NAME), ((Number) spinnerMuteDurationMinutes.getValue()).longValue());
String userName = (String) tableUserModel.getValueAt(row, TableUserModel.POS_USER_NAME);
long durationMinute = ((Number) spinnerMuteDurationMinutes.getValue()).longValue();
if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to lock user: " + userName + " for " + durationMinute + " minutes?", "WARNING",
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
ConsoleFrame.getSession().lockUser(userName, durationMinute);
}
}//GEN-LAST:event_btnLockUserActionPerformed
private void btnRemoveTableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRemoveTableActionPerformed

View file

@ -28,6 +28,7 @@
package mage.server;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
@ -37,6 +38,8 @@ import java.util.regex.Pattern;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
import mage.server.exceptions.UserNotFoundException;
import mage.server.game.GameController;
import mage.server.game.GameManager;
import mage.server.util.SystemUtil;
import mage.view.ChatMessage.MessageColor;
import mage.view.ChatMessage.MessageType;
@ -220,6 +223,27 @@ public enum ChatManager {
chatSessions.get(chatId).broadcastInfoToUser(user, message);
return true;
}
if (command.startsWith("GAME")) {
message += "<br/>" + GameManager.instance.getChatId(chatId);
ChatSession session = chatSessions.get(chatId);
if (session != null && session.getInfo() != null) {
String gameId = session.getInfo();
if (gameId.startsWith("Game ")) {
UUID id = java.util.UUID.fromString(gameId.substring(5, gameId.length()));
for (Entry<UUID, GameController> entry : GameManager.instance.getGameController().entrySet()) {
if (entry.getKey().equals(id)) {
GameController controller = entry.getValue();
if (controller != null) {
message += controller.getGameStateDebugMessage();
chatSessions.get(chatId).broadcastInfoToUser(user, message);
}
}
}
}
}
return true;
}
if (command.startsWith("CARD ")) {
Matcher matchPattern = getCardTextPattern.matcher(message.toLowerCase());
if (matchPattern.find()) {
@ -289,18 +313,18 @@ public enum ChatManager {
public void sendReconnectMessage(UUID userId) {
UserManager.instance.getUser(userId).ifPresent(user
-> getChatSessions()
.stream()
.filter(chat -> chat.hasUser(userId))
.forEach(chatSession -> chatSession.broadcast(null, user.getName() + " has reconnected", MessageColor.BLUE, true, MessageType.STATUS, null)));
.stream()
.filter(chat -> chat.hasUser(userId))
.forEach(chatSession -> chatSession.broadcast(null, user.getName() + " has reconnected", MessageColor.BLUE, true, MessageType.STATUS, null)));
}
public void sendLostConnectionMessage(UUID userId, DisconnectReason reason) {
UserManager.instance.getUser(userId).ifPresent(user
-> getChatSessions()
.stream()
.filter(chat -> chat.hasUser(userId))
.forEach(chatSession -> chatSession.broadcast(null, user.getName() + reason.getMessage(), MessageColor.BLUE, true, MessageType.STATUS, null)));
.stream()
.filter(chat -> chat.hasUser(userId))
.forEach(chatSession -> chatSession.broadcast(null, user.getName() + reason.getMessage(), MessageColor.BLUE, true, MessageType.STATUS, null)));
}

View file

@ -990,7 +990,7 @@ public class TableController {
|| !match.isDoneSideboarding()
|| (!matchPlayer.hasQuit() && match.getGame() != null && matchPlayer.getPlayer().isInGame())) {
Optional<User> user = UserManager.instance.getUser(userPlayerEntry.getKey());
if (!user.isPresent()) {
if (!user.isPresent() || !user.get().isActive()) {
logger.warn("- Active user of match is missing: " + matchPlayer.getName());
logger.warn("-- matchId:" + match.getId());
logger.warn("-- userId:" + userPlayerEntry.getKey());

View file

@ -50,6 +50,7 @@ import mage.constants.Zone;
import mage.game.Game;
import mage.game.GameException;
import mage.game.GameOptions;
import mage.game.GameState;
import mage.game.Table;
import mage.game.events.Listener;
import mage.game.events.PlayerQueryEvent;
@ -1088,4 +1089,97 @@ public class GameController implements GameCallback {
return false;
}
public String getGameStateDebugMessage() {
if (game == null) {
return "";
}
GameState state = game.getState();
if (state == null) {
return "";
}
StringBuilder sb = new StringBuilder();
sb.append("<br/>Game State:<br/><font size=-2>");
sb.append(state);
sb.append("<br>Active player is: ");
sb.append(game.getPlayer(state.getActivePlayerId()).getName());
sb.append("<br>isGameOver: ");
sb.append(state.isGameOver());
sb.append("<br>Current phase is: ");
sb.append(state.getTurn().getPhase());
sb.append("<br>getBattlefield: ");
sb.append(state.getBattlefield());
sb.append("<br>getChoosingPlayerId: ");
if (state.getChoosingPlayerId() != null) {
sb.append(game.getPlayer(state.getChoosingPlayerId()).getName());
} else {
sb.append("noone!");
}
sb.append("<br>getCombat: ");
sb.append(state.getCombat());
sb.append("<br>getCommand: ");
sb.append(state.getCommand());
sb.append("<br>getContinuousEffects: ");
sb.append(state.getContinuousEffects());
sb.append("<br>getCopiedCards: ");
sb.append(state.getCopiedCards());
sb.append("<br>getDelayed: ");
sb.append(state.getDelayed());
sb.append("<br>getDesignations: ");
sb.append(state.getDesignations());
sb.append("<br>getExile: ");
sb.append(state.getExile());
sb.append("<br>getMonarchId: ");
sb.append(state.getMonarchId());
sb.append("<br>getNextPermanentOrderNumber: ");
sb.append(state.getNextPermanentOrderNumber());
sb.append("<br>getPlayerByOrderId: ");
if (state.getPlayerByOrderId() != null) {
sb.append(game.getPlayer(state.getPlayerByOrderId()).getName());
} else {
sb.append("noone!");
}
sb.append("<br>getPlayerList: ");
sb.append(state.getPlayerList());
sb.append("<br>getPlayers: ");
sb.append(state.getPlayers());
sb.append("<br>Player with Priority is: ");
if (state.getPriorityPlayerId() != null) {
sb.append(game.getPlayer(state.getPriorityPlayerId()).getName());
} else {
sb.append("noone!");
}
sb.append("<br>getRevealed: ");
sb.append(state.getRevealed());
sb.append("<br>getSpecialActions: ");
sb.append(state.getSpecialActions());
sb.append("<br>getStack: ");
sb.append(state.getStack());
sb.append("<br>getStepNum: ");
sb.append(state.getStepNum());
sb.append("<br>getTriggers: ");
sb.append(state.getTriggers());
sb.append("<br>getTurn: ");
sb.append(state.getTurn());
sb.append("<br>getTurnId: ");
sb.append(state.getTurnId());
sb.append("<br>getTurnMods: ");
sb.append(state.getTurnMods());
sb.append("<br>getTurnNum: ");
sb.append(state.getTurnNum());
sb.append("<br>Future Timeout:");
if (futureTimeout != null) {
sb.append("Cancelled?=");
sb.append(futureTimeout.isCancelled());
sb.append(",,,Done?=");
sb.append(futureTimeout.isDone());
sb.append(",,,GetDelay?=");
sb.append((int) futureTimeout.getDelay(TimeUnit.SECONDS));
} else {
sb.append("Not using future Timeout!");
}
sb.append("</font>");
return sb.toString();
}
}

View file

@ -27,6 +27,7 @@
*/
package mage.cards.a;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
@ -44,8 +45,6 @@ import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
*
* @author LevelX2
@ -53,8 +52,7 @@ import java.util.UUID;
public class ActOfAuthority extends CardImpl {
public ActOfAuthority(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{W}{W}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{W}");
// When Act of Authority enters the battlefield, you may exile target artifact or enchantment.
Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetEffect(), true);
@ -96,9 +94,12 @@ class ActOfAuthorityEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Permanent targetPermanent = game.getPermanent(this.getTargetPointer().getFirst(game, source));
if (targetPermanent != null && new ExileTargetEffect().apply(game, source)) {
ContinuousEffect effect = new ActOfAuthorityGainControlEffect(Duration.Custom, targetPermanent.getControllerId());
effect.setTargetPointer(new FixedTarget(source.getSourceId()));
game.addEffect(effect, source);
Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game);
if (sourcePermanent != null) {
ContinuousEffect effect = new ActOfAuthorityGainControlEffect(Duration.Custom, targetPermanent.getControllerId());
effect.setTargetPointer(new FixedTarget(sourcePermanent, game));
game.addEffect(effect, source);
}
return true;
}
return false;

View file

@ -109,7 +109,7 @@ class AdarkarValkyrieEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
DelayedTriggeredAbility delayedAbility = new AdarkarValkyrieDelayedTriggeredAbility(new FixedTarget(this.getTargetPointer().getFirst(game, source)));
DelayedTriggeredAbility delayedAbility = new AdarkarValkyrieDelayedTriggeredAbility(getTargetPointer().getFixedTarget(game, source));
game.addDelayedTriggeredAbility(delayedAbility, source);
return false;
}

View file

@ -51,17 +51,17 @@ import mage.target.targetpointer.FixedTarget;
public class AmbuscadeShaman extends CardImpl {
public AmbuscadeShaman(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}");
this.subtype.add(SubType.ORC);
this.subtype.add(SubType.SHAMAN);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Whenever Ambuscade Shaman or another creature enters the battlefield under your control, that creature gets +2/+2 until end of turn.
Effect effect = new BoostTargetEffect(2,2, Duration.EndOfTurn);
Effect effect = new BoostTargetEffect(2, 2, Duration.EndOfTurn);
effect.setText("that creature gets +2/+2 until end of turn");
this.addAbility(new AmbuscadeShamanTriggeredAbility(effect));
// Dash {3}{B} <i>(You may cast this spell for its dash cost. If you do, it gains haste, and it's returned from the battlefield to its owner's hand at the beginning of the next end step.)</i>);
this.addAbility(new DashAbility(this, "{3}{B}"));
@ -103,9 +103,7 @@ class AmbuscadeShamanTriggeredAbility extends TriggeredAbilityImpl {
Permanent permanent = game.getPermanent(targetId);
if (permanent.getControllerId().equals(this.controllerId)
&& permanent.isCreature()) {
for (Effect effect : this.getEffects()) {
effect.setTargetPointer(new FixedTarget(event.getTargetId()));
}
this.getEffects().setTargetPointer(new FixedTarget(permanent, game));
return true;
}
return false;
@ -115,4 +113,4 @@ class AmbuscadeShamanTriggeredAbility extends TriggeredAbilityImpl {
public String getRule() {
return "Whenever {this} or another creature enters the battlefield under your control, that creature gets +2/+2 until end of turn.";
}
}
}

View file

@ -100,7 +100,7 @@ class AnimateDeadReAttachEffect extends OneShotEffect {
public AnimateDeadReAttachEffect() {
super(Outcome.Benefit);
this.staticText = "Return enchanted creature card to the battlefield under your control and attach {this} to it";
this.staticText = "return enchanted creature card to the battlefield under your control and attach {this} to it";
}
public AnimateDeadReAttachEffect(final AnimateDeadReAttachEffect effect) {

View file

@ -45,16 +45,16 @@ import mage.target.targetpointer.FixedTarget;
/**
*
* @author KholdFuzion
*
*/
public class AnkhOfMishra extends CardImpl {
public AnkhOfMishra(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}");
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
// Whenever a land enters the battlefield, Ankh of Mishra deals 2 damage to that land's controller.
this.addAbility(new AnkhOfMishraAbility());
}
public AnkhOfMishra(final AnkhOfMishra card) {
@ -70,16 +70,16 @@ public class AnkhOfMishra extends CardImpl {
class AnkhOfMishraAbility extends TriggeredAbilityImpl {
public AnkhOfMishraAbility() {
super(Zone.BATTLEFIELD, new DamageTargetEffect(2));
super(Zone.BATTLEFIELD, new DamageTargetEffect(2));
}
AnkhOfMishraAbility(final AnkhOfMishraAbility ability) {
super(ability);
super(ability);
}
@Override
public AnkhOfMishraAbility copy() {
return new AnkhOfMishraAbility(this);
return new AnkhOfMishraAbility(this);
}
@Override
@ -104,6 +104,6 @@ class AnkhOfMishraAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
return "Whenever a land enters the battlefield, Ankh of Mishra deals 2 damage to that land's controller.";
return "Whenever a land enters the battlefield, {this} deals 2 damage to that land's controller.";
}
}
}

View file

@ -29,6 +29,7 @@ package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
@ -53,7 +54,7 @@ import mage.target.targetpointer.FixedTarget;
public class ArbiterOfTheIdeal extends CardImpl {
public ArbiterOfTheIdeal(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}{U}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}");
this.subtype.add(SubType.SPHINX);
this.power = new MageInt(4);
@ -79,6 +80,7 @@ public class ArbiterOfTheIdeal extends CardImpl {
class ArbiterOfTheIdealEffect extends OneShotEffect {
private static final FilterCard filter = new FilterCard();
static {
filter.add(Predicates.or(
new CardTypePredicate(CardType.ARTIFACT),
@ -102,32 +104,25 @@ class ArbiterOfTheIdealEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game);
if (controller == null || sourceObject == null) {
return false;
}
if (player.getLibrary().hasCards()) {
Card card = player.getLibrary().getFromTop(game);
Cards cards = new CardsImpl();
cards.add(card);
player.revealCards("Arbiter of the Ideal", cards, game);
if (card != null) {
if (filter.match(card, game) && player.chooseUse(outcome, new StringBuilder("Put ").append(card.getName()).append("onto battlefield?").toString(), source, game)) {
card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), source.getControllerId());
Permanent permanent = game.getPermanent(card.getId());
if (permanent != null) {
permanent.addCounters(new Counter("Manifestation"), source, game);
ContinuousEffect effect = new AddCardTypeTargetEffect(Duration.Custom, CardType.ENCHANTMENT);
effect.setTargetPointer(new FixedTarget(permanent.getId()));
game.addEffect(effect, source);
}
Card card = controller.getLibrary().getFromTop(game);
if (card != null) {
controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game);
if (filter.match(card, game) && controller.chooseUse(outcome, "Put " + card.getName() + "onto battlefield?", source, game)) {
controller.moveCards(card, Zone.BATTLEFIELD, source, game);
Permanent permanent = game.getPermanent(card.getId());
if (permanent != null) {
permanent.addCounters(new Counter("Manifestation"), source, game);
ContinuousEffect effect = new AddCardTypeTargetEffect(Duration.Custom, CardType.ENCHANTMENT);
effect.setTargetPointer(new FixedTarget(permanent, game));
game.addEffect(effect, source);
}
}
return true;
}
return false;
return true;
}
}

View file

@ -29,23 +29,18 @@ package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
/**
* @author Loki
@ -53,7 +48,7 @@ import mage.target.targetpointer.FixedTarget;
public class ArchonOfRedemption extends CardImpl {
public ArchonOfRedemption(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}{W}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}");
this.subtype.add(SubType.ARCHON);
this.power = new MageInt(3);
@ -75,8 +70,9 @@ public class ArchonOfRedemption extends CardImpl {
}
class ArchonOfRedemptionTriggeredAbility extends TriggeredAbilityImpl {
ArchonOfRedemptionTriggeredAbility() {
super(Zone.BATTLEFIELD, new ArchonOfRedemptionEffect(), true);
super(Zone.BATTLEFIELD, null, true);
}
ArchonOfRedemptionTriggeredAbility(final ArchonOfRedemptionTriggeredAbility ability) {
@ -95,15 +91,13 @@ class ArchonOfRedemptionTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
UUID targetId = event.getTargetId();
Permanent permanent = game.getPermanent(targetId);
if (permanent.getControllerId().equals(this.controllerId)
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent.getControllerId().equals(getControllerId())
&& permanent.isCreature()
&& (targetId.equals(this.getSourceId())
|| (permanent.getAbilities().contains(FlyingAbility.getInstance()) && !targetId.equals(this.getSourceId())))) {
for (Effect effect : this.getEffects()) {
effect.setTargetPointer(new FixedTarget(event.getTargetId()));
}
&& (permanent.getId().equals(getSourceId())
|| (permanent.getAbilities().contains(FlyingAbility.getInstance())))) {
this.getEffects().clear();
this.addEffect(new GainLifeEffect(permanent.getPower().getValue()));
return true;
}
return false;
@ -111,35 +105,6 @@ class ArchonOfRedemptionTriggeredAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
return "Whenever {this} or another creature with flying enters the battlefield under your control, you may gain life equal to that creature's power";
return "Whenever {this} or another creature with flying enters the battlefield under your control, you may gain life equal to that creature's power.";
}
}
class ArchonOfRedemptionEffect extends OneShotEffect {
ArchonOfRedemptionEffect() {
super(Outcome.GainLife);
}
ArchonOfRedemptionEffect(final ArchonOfRedemptionEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent p = game.getPermanent(targetPointer.getFirst(game, source));
Player player = game.getPlayer(source.getControllerId());
if (p == null) {
p = (Permanent) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.BATTLEFIELD);
}
if (p != null && player != null) {
player.gainLife(p.getPower().getValue(), game);
return true;
}
return false;
}
@Override
public ArchonOfRedemptionEffect copy() {
return new ArchonOfRedemptionEffect(this);
}
}

View file

@ -53,7 +53,7 @@ import mage.target.targetpointer.FixedTarget;
public class ArrogantBloodlord extends CardImpl {
public ArrogantBloodlord(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}");
this.subtype.add(SubType.VAMPIRE);
this.subtype.add(SubType.KNIGHT);
@ -104,11 +104,8 @@ class ArrogantBloodlordTriggeredAbility extends TriggeredAbilityImpl {
&& Objects.equals(blocked, arrogantBloodlord)) {
return true;
}
if (blocker != null && Objects.equals(blocker, arrogantBloodlord)
&& game.getPermanent(event.getTargetId()).getPower().getValue() < 2) {
return true;
}
return false;
return blocker != null && Objects.equals(blocker, arrogantBloodlord)
&& game.getPermanent(event.getTargetId()).getPower().getValue() < 2;
}
@Override
@ -133,7 +130,7 @@ class ArrogantBloodlordEffect extends OneShotEffect {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) {
AtTheEndOfCombatDelayedTriggeredAbility delayedAbility = new AtTheEndOfCombatDelayedTriggeredAbility(new DestroyTargetEffect());
delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(source.getSourceId()));
delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(permanent, game));
game.addDelayedTriggeredAbility(delayedAbility, source);
return true;
}

View file

@ -37,16 +37,13 @@ import mage.abilities.effects.common.CounterUnlessPaysEffect;
import mage.abilities.keyword.BandingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AbilityType;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.FilterStackObject;
import mage.filter.predicate.Predicate;
import mage.game.Game;
import mage.game.stack.StackAbility;
import mage.target.common.TargetActivatedOrTriggeredAbility;
import mage.filter.FilterAbility;
import mage.filter.predicate.ability.ArtifactSourcePredicate;
import mage.target.common.TargetActivatedAbility;
/**
*
@ -54,26 +51,26 @@ import mage.target.common.TargetActivatedOrTriggeredAbility;
*/
public class AyeshaTanaka extends CardImpl {
private final static FilterStackObject filter = new FilterStackObject("activated ability from an artifact source");
private final static FilterAbility filter = new FilterAbility("activated ability from an artifact source");
static {
filter.add(new ArtifactSourcePredicate());
}
public AyeshaTanaka(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}{W}{U}{U}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}{U}{U}");
addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.ARTIFICER);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Banding
this.addAbility(BandingAbility.getInstance());
// {T}: Counter target activated ability from an artifact source unless that ability's controller pays {W}.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterUnlessPaysEffect(new ManaCostsImpl("{W}")), new TapSourceCost());
ability.addTarget(new TargetActivatedOrTriggeredAbility(filter));
ability.addTarget(new TargetActivatedAbility(filter));
this.addAbility(ability);
}
@ -86,22 +83,3 @@ public class AyeshaTanaka extends CardImpl {
return new AyeshaTanaka(this);
}
}
class ArtifactSourcePredicate implements Predicate<Ability> {
public ArtifactSourcePredicate() {
}
@Override
public boolean apply(Ability input, Game game) {
if (input instanceof StackAbility) {
return input.getSourceObject(game).isArtifact() && input.getAbilityType() == AbilityType.ACTIVATED;
}
return false;
}
@Override
public String toString() {
return "Source(Artifact)";
}
}

View file

@ -103,7 +103,7 @@ class BackFromTheBrinkCost extends CostImpl {
if (controller != null) {
Card card = controller.getGraveyard().get(targets.getFirstTarget(), game);
if (card != null && controller.moveCards(card, Zone.EXILED, ability, game)) {
ability.getEffects().get(0).setTargetPointer(new FixedTarget(card.getId()));
ability.getEffects().get(0).setTargetPointer(new FixedTarget(card.getId(), game.getState().getZoneChangeCounter(card.getId())));
paid = card.getManaCost().pay(ability, game, sourceId, controllerId, noMana);
}
}

View file

@ -161,14 +161,24 @@ class BalduvianWarlordUnblockEffect extends OneShotEffect {
// Relevant ruling for Balduvian Warlord:
// 7/15/2006 If an attacking creature has an ability that triggers When this creature becomes blocked,
// it triggers when a creature blocks it due to the Warlords ability only if it was unblocked at that point.
boolean notYetBlocked = chosenGroup.getBlockers().isEmpty();
chosenGroup.addBlocker(permanent.getId(), controller.getId(), game);
chosenGroup.addBlockerToGroup(permanent.getId(), controller.getId(), game);
game.getCombat().addBlockingGroup(permanent.getId(), chosenPermanent.getId(), controller.getId(), game); // 702.21h
if (notYetBlocked) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKED, chosenPermanent.getId(), null));
for (UUID bandedId : chosenPermanent.getBandedCards()) {
CombatGroup bandedGroup = game.getCombat().findGroup(bandedId);
if (bandedGroup != null && chosenGroup.getBlockers().size() == 1) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKED, bandedId, null));
}
}
}
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.BLOCKER_DECLARED, chosenPermanent.getId(), permanent.getId(), permanent.getControllerId()));
}
CombatGroup blockGroup = findBlockingGroup(permanent, game); // a new blockingGroup is formed, so it's necessary to find it again
if (blockGroup != null) {
blockGroup.pickAttackerOrder(permanent.getControllerId(), game);
}
}
}
return true;
@ -176,4 +186,15 @@ class BalduvianWarlordUnblockEffect extends OneShotEffect {
}
return false;
}
private CombatGroup findBlockingGroup(Permanent blocker, Game game) {
if (game.getCombat().blockingGroupsContains(blocker.getId())) { // if (blocker.getBlocking() > 1) {
for (CombatGroup group : game.getCombat().getBlockingGroups()) {
if (group.getBlockers().contains(blocker.getId())) {
return group;
}
}
}
return null;
}
}

View file

@ -52,7 +52,7 @@ public class BarrinsUnmaking extends CardImpl {
public BarrinsUnmaking(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}");
// Return target permanent to its owner's hand if that permanent shares a color with the most common color among all permanents or a color tied for most common.
// Return target permanent to its owner's hand if that permanent shares a color with the most common color among all permanents or a color tied for most common.
this.getSpellAbility().addEffect(new BarrinsUnmakingEffect());
this.getSpellAbility().addTarget(new TargetPermanent());
}
@ -85,12 +85,12 @@ class BarrinsUnmakingEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getFirstTarget());
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null) {
Condition condition = new MostCommonColorCondition(permanent.getColor(game));
if (condition.apply(game, source)) {
Effect effect = new ReturnToHandTargetEffect();
effect.setTargetPointer(new FixedTarget(permanent.getId()));
effect.setTargetPointer(new FixedTarget(permanent, game));
return effect.apply(game, source);
}
}

View file

@ -0,0 +1,132 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.b;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.RedirectionEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.game.stack.Spell;
import mage.players.Player;
import mage.target.TargetPermanent;
import mage.target.TargetSource;
/**
*
* @author L_J
*/
public class BeaconOfDestiny extends CardImpl {
public BeaconOfDestiny(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.CLERIC);
this.power = new MageInt(1);
this.toughness = new MageInt(3);
// {T}: The next time a source of your choice would deal damage to you this turn, that damage is dealt to Beacon of Destiny instead.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BeaconOfDestinyEffect(), new TapSourceCost()));
}
public BeaconOfDestiny(final BeaconOfDestiny card) {
super(card);
}
@Override
public BeaconOfDestiny copy() {
return new BeaconOfDestiny(this);
}
}
class BeaconOfDestinyEffect extends RedirectionEffect {
private final TargetSource damageSource;
public BeaconOfDestinyEffect() {
super(Duration.EndOfTurn, Integer.MAX_VALUE, true);
staticText = "The next time a source of your choice would deal damage to you this turn, that damage is dealt to {this} instead";
this.damageSource = new TargetSource();
}
public BeaconOfDestinyEffect(final BeaconOfDestinyEffect effect) {
super(effect);
this.damageSource = effect.damageSource.copy();
}
@Override
public BeaconOfDestinyEffect copy() {
return new BeaconOfDestinyEffect(this);
}
@Override
public void init(Ability source, Game game) {
this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game);
super.init(source, game);
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
// check source
MageObject object = game.getObject(event.getSourceId());
if (object == null) {
game.informPlayers("Couldn't find source of damage");
return false;
}
if (!object.getId().equals(damageSource.getFirstTarget())
&& (!(object instanceof Spell) || !((Spell) object).getSourceId().equals(damageSource.getFirstTarget()))) {
return false;
}
TargetPermanent target = new TargetPermanent();
target.add(source.getSourceId(), game);
this.redirectTarget = target;
// check player
Player player = game.getPlayer(event.getTargetId());
if (player != null) {
if (player.getId().equals(source.getControllerId())) {
return true;
}
}
return false;
}
}

View file

@ -0,0 +1,127 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.b;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility;
import mage.abilities.condition.common.BeforeBlockersAreDeclaredCondition;
import mage.abilities.effects.RequirementEffect;
import mage.abilities.effects.common.combat.CanBlockAdditionalCreatureTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.TurnPhase;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.ObjectPlayer;
import mage.filter.predicate.ObjectPlayerPredicate;
import mage.game.Controllable;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author L_J
*/
public class BlazeOfGlory extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls");
static {
filter.add(new BlazeOfGloryDefendingPlayerControlsPredicate());
}
public BlazeOfGlory(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}");
// Cast Blaze of Glory only during combat before blockers are declared.
this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(TurnPhase.COMBAT, BeforeBlockersAreDeclaredCondition.instance));
// Target creature defending player controls can block any number of creatures this turn. It blocks each attacking creature this turn if able.
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter));
this.getSpellAbility().addEffect(new CanBlockAdditionalCreatureTargetEffect(Duration.EndOfTurn, 0));
this.getSpellAbility().addEffect(new BlazeOfGloryRequirementEffect());
}
public BlazeOfGlory(final BlazeOfGlory card) {
super(card);
}
@Override
public BlazeOfGlory copy() {
return new BlazeOfGlory(this);
}
}
class BlazeOfGloryDefendingPlayerControlsPredicate implements ObjectPlayerPredicate<ObjectPlayer<Controllable>> {
@Override
public boolean apply(ObjectPlayer<Controllable> input, Game game) {
return game.getCombat().getPlayerDefenders(game).contains(input.getObject().getControllerId());
}
}
class BlazeOfGloryRequirementEffect extends RequirementEffect {
public BlazeOfGloryRequirementEffect() {
super(Duration.EndOfTurn);
this.staticText = "It blocks each attacking creature this turn if able";
}
public BlazeOfGloryRequirementEffect(final BlazeOfGloryRequirementEffect effect) {
super(effect);
}
@Override
public boolean applies(Permanent permanent, Ability source, Game game) {
return permanent.getId().equals(targetPointer.getFirst(game, source));
}
@Override
public boolean mustAttack(Game game) {
return false;
}
@Override
public boolean mustBlock(Game game) {
return true;
}
@Override
public boolean mustBlockAllAttackers(Game game) {
return true;
}
@Override
public BlazeOfGloryRequirementEffect copy() {
return new BlazeOfGloryRequirementEffect(this);
}
}

View file

@ -53,7 +53,7 @@ import java.util.UUID;
*/
public class BrassTalonChimera extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Chimera creature you control");
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Chimera creature");
static {
filter.add(new SubtypePredicate(SubType.CHIMERA));

View file

@ -27,6 +27,7 @@
*/
package mage.cards.b;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
@ -35,17 +36,12 @@ import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.CounterTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AbilityType;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterStackObject;
import mage.filter.predicate.Predicate;
import mage.game.Game;
import mage.game.stack.StackAbility;
import mage.target.common.TargetActivatedOrTriggeredAbility;
import java.util.UUID;
import mage.filter.FilterAbility;
import mage.filter.predicate.ability.ArtifactSourcePredicate;
import mage.target.common.TargetActivatedAbility;
/**
*
@ -53,7 +49,7 @@ import java.util.UUID;
*/
public class BrownOuphe extends CardImpl {
private final static FilterStackObject filter = new FilterStackObject("activated ability from an artifact source");
private final static FilterAbility filter = new FilterAbility("activated ability from an artifact source");
static {
filter.add(new ArtifactSourcePredicate());
@ -69,7 +65,7 @@ public class BrownOuphe extends CardImpl {
// {1}{G}, {tap}: Counter target activated ability from an artifact source.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterTargetEffect(), new ManaCostsImpl<>("{1}{G}"));
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetActivatedOrTriggeredAbility(filter));
ability.addTarget(new TargetActivatedAbility(filter));
this.addAbility(ability);
}
@ -82,22 +78,3 @@ public class BrownOuphe extends CardImpl {
return new BrownOuphe(this);
}
}
class ArtifactSourcePredicate implements Predicate<Ability> {
public ArtifactSourcePredicate() {
}
@Override
public boolean apply(Ability input, Game game) {
if (input instanceof StackAbility) {
return input.getSourceObject(game).isArtifact() && input.getAbilityType() == AbilityType.ACTIVATED;
}
return false;
}
@Override
public String toString() {
return "Source(Artifact)";
}
}

View file

@ -28,21 +28,16 @@
package mage.cards.c;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.UntapAllEffect;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
/**
* @author Loki
@ -57,8 +52,9 @@ public class CallToGlory extends CardImpl {
public CallToGlory(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}");
this.getSpellAbility().addEffect(new CalltoGloryFirstEffect());
//Untap all creatures you control. Samurai creatures you control get +1/+1 until end of turn.
this.getSpellAbility().addEffect(new UntapAllEffect(StaticFilters.FILTER_CONTROLLED_CREATURE));
this.getSpellAbility().addEffect(new BoostControlledEffect(1, 1, Duration.EndOfTurn, filter, false));
}
@ -70,35 +66,4 @@ public class CallToGlory extends CardImpl {
public CallToGlory copy() {
return new CallToGlory(this);
}
}
class CalltoGloryFirstEffect extends OneShotEffect {
public CalltoGloryFirstEffect() {
super(Outcome.Untap);
staticText = "Untap all creatures you control";
}
public CalltoGloryFirstEffect(final CalltoGloryFirstEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, player.getId(), game)) {
creature.untap(game);
}
return true;
}
return false;
}
@Override
public CalltoGloryFirstEffect copy() {
return new CalltoGloryFirstEffect(this);
}
}

View file

@ -28,6 +28,7 @@
package mage.cards.c;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
@ -48,7 +49,7 @@ import mage.game.events.GameEvent.EventType;
public class CityOfSolitude extends CardImpl {
public CityOfSolitude(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{G}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}");
// Players can cast spells and activate abilities only during their own turns.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CityOfSolitudeEffect()));
@ -74,12 +75,22 @@ class CityOfSolitudeEffect extends ContinuousRuleModifyingEffectImpl {
CityOfSolitudeEffect(final CityOfSolitudeEffect effect) {
super(effect);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == EventType.CAST_SPELL || event.getType() == EventType.ACTIVATE_ABILITY;
}
@Override
public String getInfoMessage(Ability source, GameEvent event, Game game) {
MageObject sourceObject = game.getObject(source.getSourceId());
MageObject eventObject = game.getObject(event.getSourceId());
if (sourceObject != null && eventObject != null) {
return "You can cast or activate anability of " + eventObject.getIdName() + " only during your own turns (" + sourceObject.getIdName() + "). ";
}
return null;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
return !game.getActivePlayerId().equals(event.getPlayerId());
@ -89,4 +100,4 @@ class CityOfSolitudeEffect extends ContinuousRuleModifyingEffectImpl {
public CityOfSolitudeEffect copy() {
return new CityOfSolitudeEffect(this);
}
}
}

View file

@ -41,9 +41,9 @@ import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffec
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.common.FilterCreatureCard;
import mage.game.Game;
@ -60,7 +60,7 @@ import mage.target.targetpointer.FixedTarget;
public class CoffinQueen extends CardImpl {
public CoffinQueen(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}");
this.subtype.add(SubType.ZOMBIE);
this.subtype.add(SubType.WIZARD);
this.power = new MageInt(1);
@ -68,14 +68,14 @@ public class CoffinQueen extends CardImpl {
// You may choose not to untap Coffin Queen during your untap step.
this.addAbility(new SkipUntapOptionalAbility());
// {2}{B}, {tap}: Put target creature card from a graveyard onto the battlefield under your control. When Coffin Queen becomes untapped or you lose control of Coffin Queen, exile that creature.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect(), new ManaCostsImpl("{2}{B}"));
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card from a graveyard")));
ability.addEffect(new CoffinQueenCreateDelayedTriggerEffect());
ability.addEffect(new CoffinQueenCreateDelayedTriggerEffect());
this.addAbility(ability);
}
public CoffinQueen(final CoffinQueen card) {
@ -87,33 +87,30 @@ public class CoffinQueen extends CardImpl {
return new CoffinQueen(this);
}
}
class CoffinQueenCreateDelayedTriggerEffect extends OneShotEffect {
public CoffinQueenCreateDelayedTriggerEffect() {
super(Outcome.Detriment);
this.staticText = "When Coffin Queen becomes untapped or you lose control of Coffin Queen, exile that creature";
this.staticText = "When {this} becomes untapped or you lose control of {this}, exile that creature.";
}
public CoffinQueenCreateDelayedTriggerEffect(final CoffinQueenCreateDelayedTriggerEffect effect) {
super(effect);
}
@Override
public CoffinQueenCreateDelayedTriggerEffect copy() {
return new CoffinQueenCreateDelayedTriggerEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent controlledCreature = game.getPermanent(source.getFirstTarget());
if (controlledCreature != null) {
DelayedTriggeredAbility delayedAbility = new CoffinQueenDelayedTriggeredAbility();
delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(controlledCreature.getId()));
delayedAbility.setSourceId(source.getSourceId());
delayedAbility.setControllerId(source.getControllerId());
delayedAbility.setSourceObject(source.getSourceObject(game), game);
delayedAbility.init(game);
game.addDelayedTriggeredAbility(delayedAbility);
delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(controlledCreature, game));
game.addDelayedTriggeredAbility(delayedAbility, source);
return true;
}
return false;
@ -123,7 +120,7 @@ class CoffinQueenCreateDelayedTriggerEffect extends OneShotEffect {
class CoffinQueenDelayedTriggeredAbility extends DelayedTriggeredAbility {
CoffinQueenDelayedTriggeredAbility() {
super(new ExileTargetEffect(), Duration.EndOfGame, true);
super(new ExileTargetEffect(), Duration.EndOfGame, true);
}
CoffinQueenDelayedTriggeredAbility(CoffinQueenDelayedTriggeredAbility ability) {
@ -136,7 +133,6 @@ class CoffinQueenDelayedTriggeredAbility extends DelayedTriggeredAbility {
|| event.getType() == EventType.UNTAPPED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (EventType.LOST_CONTROL == event.getType()
@ -146,14 +142,14 @@ class CoffinQueenDelayedTriggeredAbility extends DelayedTriggeredAbility {
return EventType.UNTAPPED == event.getType()
&& event.getTargetId() != null && event.getTargetId().equals(getSourceId());
}
@Override
public CoffinQueenDelayedTriggeredAbility copy() {
return new CoffinQueenDelayedTriggeredAbility(this);
}
@Override
public String getRule() {
return "When {this} becomes untapped or you lose control of {this}, exile that creature";
return "When {this} becomes untapped or you lose control of {this}, exile that creature.";
}
}

View file

@ -81,7 +81,7 @@ public class ConduitOfRuin extends CardImpl {
// The first creature spell you cast each turn costs {2} less to cast.
Effect effect = new SpellsCostReductionControllerEffect(filterCost, 2);
effect.setText("The first creature spell you cast each turn costs {2} less to cast");
effect.setText("The first creature spell you cast each turn costs {2} less to cast.");
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect), new ConduitOfRuinWatcher());
}

View file

@ -30,7 +30,6 @@ package mage.cards.c;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.costs.Cost;
import mage.abilities.costs.common.DiscardTargetCost;
import mage.abilities.costs.common.DiscardXTargetCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.DynamicValue;
@ -82,8 +81,8 @@ class ConflagrateVariableValue implements DynamicValue {
public int calculate(Game game, Ability sourceAbility, Effect effect) {
int xValue = sourceAbility.getManaCostsToPay().getX();
for (Cost cost : sourceAbility.getCosts()) {
if (cost instanceof DiscardTargetCost) {
xValue = ((DiscardTargetCost) cost).getCards().size();
if (cost instanceof DiscardXTargetCost) {
xValue = ((DiscardXTargetCost) cost).getAmount();
}
}
return xValue;

View file

@ -0,0 +1,142 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.c;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetOpponent;
/**
*
* @author TheElk801 & L_J
*/
public class CruelFate extends CardImpl {
public CruelFate(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{U}");
// Look at the top five cards of target opponent's library. Put one of those cards into that player's graveyard and the rest on top of his or her library in any order.
this.getSpellAbility().addEffect(new CruelFateEffect());
this.getSpellAbility().addTarget(new TargetOpponent());
}
public CruelFate(final CruelFate card) {
super(card);
}
@Override
public CruelFate copy() {
return new CruelFate(this);
}
}
class CruelFateEffect extends OneShotEffect {
public CruelFateEffect() {
super(Outcome.DrawCard);
this.staticText = "Look at the top five cards of target opponent's library. Put one of those cards into that player's graveyard and the rest on top of his or her library in any order";
}
public CruelFateEffect(final CruelFateEffect effect) {
super(effect);
}
@Override
public CruelFateEffect copy() {
return new CruelFateEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Card sourceCard = game.getCard(source.getSourceId());
if (sourceCard != null) {
Player you = game.getPlayer(source.getControllerId());
Player player = game.getPlayer(source.getFirstTarget());
if (player != null && you != null) {
Cards cards = new CardsImpl();
int count = Math.min(player.getLibrary().size(), 5);
for (int i = 0; i < count; i++) {
Card card = player.getLibrary().removeFromTop(game);
if (card != null) {
cards.add(card);
}
}
you.lookAtCards(sourceCard.getIdName(), cards, game);
// card to put into opponent's graveyard
TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put into target opponent's graveyard"));
if (player.canRespond()) {
if (cards.size() > 1) {
you.choose(Outcome.Detriment, cards, target, game);
Card card = cards.get(target.getFirstTarget(), game);
if (card != null) {
cards.remove(card);
card.moveToZone(Zone.GRAVEYARD, source.getSourceId(), game, true);
}
}
else if (cards.size() == 1) {
Card card = cards.get(cards.iterator().next(), game);
card.moveToZone(Zone.GRAVEYARD, source.getSourceId(), game, true);
}
}
// cards to put on the top of opponent's library
TargetCard target2 = new TargetCard(Zone.LIBRARY, new FilterCard("card to put on the top of target opponent's library"));
while (player.canRespond() && cards.size() > 1) {
you.choose(Outcome.Neutral, cards, target2, game);
Card card = cards.get(target2.getFirstTarget(), game);
if (card != null) {
cards.remove(card);
card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true);
}
target2.clearChosen();
}
if (cards.size() == 1) {
Card card = cards.get(cards.iterator().next(), game);
card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true);
}
return true;
}
}
return false;
}
}

View file

@ -0,0 +1,110 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.d;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility;
import mage.abilities.condition.common.AttackedThisStepCondition;
import mage.abilities.effects.PreventionEffectImpl;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.PhaseStep;
import mage.constants.TurnPhase;
import mage.filter.common.FilterAttackingCreature;
import mage.game.Game;
import mage.game.events.DamagePlayerEvent;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.watchers.common.PlayerAttackedStepWatcher;
/**
*
* @author L_J
*/
public class DeepWood extends CardImpl {
public DeepWood(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}");
// Cast Deep Wood only during the declare attackers step and only if you've been attacked this step.
Ability ability = new CastOnlyDuringPhaseStepSourceAbility(
TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance,
"Cast {this} only during the declare attackers step and only if you've been attacked this step."
);
ability.addWatcher(new PlayerAttackedStepWatcher());
this.addAbility(ability);
// Prevent all damage that would be dealt to you this turn by attacking creatures.
this.getSpellAbility().addEffect(new DeepWoodEffect());
}
public DeepWood(final DeepWood card) {
super(card);
}
@Override
public DeepWood copy() {
return new DeepWood(this);
}
}
class DeepWoodEffect extends PreventionEffectImpl {
private static final FilterAttackingCreature filter = new FilterAttackingCreature();
DeepWoodEffect() {
super(Duration.EndOfTurn, Integer.MAX_VALUE, false);
staticText = "Prevent all damage that would be dealt to you this turn by attacking creatures";
}
DeepWoodEffect(final DeepWoodEffect effect) {
super(effect);
}
@Override
public DeepWoodEffect copy() {
return new DeepWoodEffect(this);
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (super.applies(event, source, game) && event instanceof DamagePlayerEvent && event.getAmount() > 0) {
DamagePlayerEvent damageEvent = (DamagePlayerEvent) event;
if (event.getTargetId().equals(source.getControllerId())) {
Permanent permanent = game.getPermanentOrLKIBattlefield(damageEvent.getSourceId());
if (permanent != null && filter.match(permanent, game)) {
return true;
}
}
}
return false;
}
}

View file

@ -124,7 +124,7 @@ class DefiantVanguardEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent thisCreature = game.getPermanentOrLKIBattlefield(source.getId());
Permanent thisCreature = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (controller != null && thisCreature != null) {
BlockedAttackerWatcher watcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName());
if (watcher != null) {
@ -136,10 +136,10 @@ class DefiantVanguardEffect extends OneShotEffect {
}
}
}
thisCreature.destroy(source.getSourceId(), game, false);
for (Permanent creature : toDestroy) {
creature.destroy(source.getSourceId(), game, false);
}
thisCreature.destroy(source.getSourceId(), game, false);
return true;
}
}

View file

@ -68,8 +68,7 @@ public class DiamondKaleidoscope extends CardImpl {
this.addAbility(ability);
// Sacrifice a Prism token: Add one mana of any color to your mana pool.
ability = new AnyColorManaAbility();
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter)));
ability = new AnyColorManaAbility(new SacrificeTargetCost(new TargetControlledPermanent(filter)));
this.addAbility(ability);
}

View file

@ -28,17 +28,14 @@
package mage.cards.d;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.common.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.common.*;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.filter.predicate.permanent.AnotherPredicate;
import mage.game.Game;
import mage.game.events.DamageEvent;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.targetpointer.FixedTarget;
@ -48,12 +45,6 @@ import mage.target.targetpointer.FixedTarget;
*/
public class DinosaurHunter extends CardImpl {
private static final FilterControlledCreaturePermanent filterAnotherDino = new FilterControlledCreaturePermanent();
static {
filterAnotherDino.add(new AnotherPredicate());
filterAnotherDino.add(new SubtypePredicate(SubType.DINOSAUR));
}
public DinosaurHunter(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}");
@ -78,11 +69,6 @@ public class DinosaurHunter extends CardImpl {
class DinosaurHunterAbility extends TriggeredAbilityImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent();
static {
filter.add(new SubtypePredicate(SubType.DINOSAUR));
}
DinosaurHunterAbility() {
super(Zone.BATTLEFIELD, new DestroyTargetEffect());
}
@ -103,11 +89,13 @@ class DinosaurHunterAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Permanent sourcePermanet = game.getPermanent(event.getSourceId());
Permanent targetPermanet = game.getPermanent(event.getTargetId());
if (sourcePermanet != null && targetPermanet != null && event.getSourceId().equals(sourceId) && filter.match(targetPermanet, game)) {
getEffects().get(0).setTargetPointer(new FixedTarget(event.getTargetId()));
return true;
if (((DamageEvent) event).isCombatDamage()
&& event.getSourceId().equals(getSourceId())) {
Permanent targetPermanet = game.getPermanentOrLKIBattlefield(event.getTargetId());
if (targetPermanet.hasSubtype(SubType.DINOSAUR, game)) {
getEffects().get(0).setTargetPointer(new FixedTarget(targetPermanet, game));
return true;
}
}
return false;
}
@ -116,4 +104,4 @@ class DinosaurHunterAbility extends TriggeredAbilityImpl {
public String getRule() {
return "Whenever {this} deals combat damage to a Dinosaur, destroy that creature.";
}
}
}

View file

@ -108,7 +108,8 @@ class DjinnIlluminatusGainReplicateEffect extends ContinuousEffectImpl {
if ((stackObject instanceof Spell)
&& !stackObject.isCopy()
&& stackObject.getControllerId().equals(source.getControllerId())
&& djinn.getControllerId().equals(source.getControllerId())) { // verify that the controller of the djinn cast that spell
&& djinn.getControllerId().equals(source.getControllerId()) // verify that the controller of the djinn cast that spell
&& !stackObject.getManaCost().isEmpty()) { //handle cases like Ancestral Vision
Spell spell = (Spell) stackObject;
if (filter.match(stackObject, game)) {
ReplicateAbility replicateAbility = replicateAbilities.computeIfAbsent(spell.getId(), k -> new ReplicateAbility(spell.getCard(), spell.getSpellAbility().getManaCosts().getText()));

View file

@ -0,0 +1,73 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.d;
import java.util.UUID;
import mage.ObjectColor;
import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesAllEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.TargetController;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.filter.predicate.permanent.ControllerPredicate;
/**
*
* @author L_J
*/
public class DreadCharge extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Black creatures you control");
private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("except by black creatures");
static {
filter.add(new ColorPredicate(ObjectColor.BLACK));
filter2.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK)));
filter.add(new ControllerPredicate(TargetController.YOU));
}
public DreadCharge(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}");
// Black creatures you control can't be blocked this turn except by black creatures.
this.getSpellAbility().addEffect(new CantBeBlockedByCreaturesAllEffect(filter, filter2, Duration.EndOfTurn));
}
public DreadCharge(final DreadCharge card) {
super(card);
}
@Override
public DreadCharge copy() {
return new DreadCharge(this);
}
}

View file

@ -27,6 +27,7 @@
*/
package mage.cards.d;
import java.util.List;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
@ -52,7 +53,7 @@ public class DreamThief extends CardImpl {
private static final String rule = "draw a card if you've cast another blue spell this turn";
public DreamThief(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}");
this.subtype.add(SubType.FAERIE);
this.subtype.add(SubType.ROGUE);
@ -84,9 +85,12 @@ class CastBlueSpellThisTurnCondition implements Condition {
public boolean apply(Game game, Ability source) {
SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName());
if (watcher != null) {
for (Spell spell : watcher.getSpellsCastThisTurn(source.getControllerId())) {
if (!spell.getSourceId().equals(source.getSourceId()) && spell.getColor(game).isBlue()) {
return true;
List<Spell> spells = watcher.getSpellsCastThisTurn(source.getControllerId());
if (spells != null) {
for (Spell spell : spells) {
if (!spell.getSourceId().equals(source.getSourceId()) && spell.getColor(game).isBlue()) {
return true;
}
}
}
}

View file

@ -0,0 +1,145 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.e;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.RestrictionEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetPermanent;
import mage.target.common.TargetOpponent;
/**
*
* @author TheElk801 & L_J
*/
public class EunuchsIntrigues extends CardImpl {
public EunuchsIntrigues(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}");
// Target opponent chooses a creature he or she controls. Other creatures he or she controls can't block this turn.
this.getSpellAbility().addEffect(new EunuchsIntriguesEffect());
this.getSpellAbility().addTarget(new TargetOpponent());
}
public EunuchsIntrigues(final EunuchsIntrigues card) {
super(card);
}
@Override
public EunuchsIntrigues copy() {
return new EunuchsIntrigues(this);
}
}
class EunuchsIntriguesEffect extends OneShotEffect {
EunuchsIntriguesEffect() {
super(Outcome.Benefit);
this.staticText = "Target opponent chooses a creature he or she controls. Other creatures he or she controls can't block this turn.";
}
EunuchsIntriguesEffect(final EunuchsIntriguesEffect effect) {
super(effect);
}
@Override
public EunuchsIntriguesEffect copy() {
return new EunuchsIntriguesEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getFirstTarget());
if (player == null) {
return false;
}
FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control");
filter.add(new ControllerIdPredicate(player.getId()));
Target target = new TargetPermanent(1, 1, filter, true);
if (target.canChoose(source.getSourceId(), player.getId(), game)) {
while (!target.isChosen() && target.canChoose(player.getId(), game) && player.canRespond()) {
player.chooseTarget(Outcome.DestroyPermanent, target, source, game);
}
Permanent permanent = game.getPermanent(target.getFirstTarget());
if (permanent != null) {
game.informPlayers(player.getLogName() + " has chosen " + permanent.getLogName() + " as his only creature able to block this turn");
}
}
game.addEffect(new EunuchsIntriguesRestrictionEffect(target.getFirstTarget()), source);
return true;
}
}
class EunuchsIntriguesRestrictionEffect extends RestrictionEffect {
protected UUID targetId;
public EunuchsIntriguesRestrictionEffect(UUID targetId) {
super(Duration.EndOfTurn);
this.targetId = targetId;
}
public EunuchsIntriguesRestrictionEffect(final EunuchsIntriguesRestrictionEffect effect) {
super(effect);
targetId = effect.targetId;
}
@Override
public EunuchsIntriguesRestrictionEffect copy() {
return new EunuchsIntriguesRestrictionEffect(this);
}
@Override
public boolean applies(Permanent permanent, Ability source, Game game) {
if (permanent.getControllerId().equals(source.getFirstTarget())) {
return true;
}
return false;
}
@Override
public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) {
if (targetId != null && blocker.getId().equals(targetId)) {
return true;
}
return false;
}
}

View file

@ -80,7 +80,7 @@ class ExaltedDragonCostToAttackBlockEffect extends PayCostToAttackBlockEffectImp
ExaltedDragonCostToAttackBlockEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment, RestrictType.ATTACK,
new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledLandPermanent("a land"))));
staticText = "{this} can't attack unless you sacrifice a land <i>(This cost is paid as attackers are declared.)</i>";
staticText = "{this} can't attack unless you sacrifice a land. <i>(This cost is paid as attackers are declared.)</i>";
}
ExaltedDragonCostToAttackBlockEffect(ExaltedDragonCostToAttackBlockEffect effect) {

View file

@ -28,24 +28,22 @@
package mage.cards.e;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.DamageEvent;
import mage.game.events.GameEvent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
import mage.target.TargetSource;
/**
*
* @author MarcoMarin
*
* @author L_J
*/
public class EyeForAnEye extends CardImpl {
@ -53,8 +51,7 @@ public class EyeForAnEye extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{W}{W}");
// The next time a source of your choice would deal damage to you this turn, instead that source deals that much damage to you and Eye for an Eye deals that much damage to that source's controller.
this.addAbility(new EyeForAnEyeTriggeredAbility(new EyeForAnEyeEffect()));
this.getSpellAbility().addEffect(new EyeForAnEyeEffect());
}
public EyeForAnEye(final EyeForAnEye card) {
@ -67,48 +64,19 @@ public class EyeForAnEye extends CardImpl {
}
}
class EyeForAnEyeTriggeredAbility extends TriggeredAbilityImpl {
class EyeForAnEyeEffect extends ReplacementEffectImpl {
public EyeForAnEyeTriggeredAbility(Effect effect) {
super(Zone.BATTLEFIELD, effect);
}
public EyeForAnEyeTriggeredAbility(final EyeForAnEyeTriggeredAbility ability) {
super(ability);
}
@Override
public EyeForAnEyeTriggeredAbility copy() {
return new EyeForAnEyeTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DAMAGED_PLAYER;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
MageObject sourceObject = game.getObject(event.getSourceId());
this.getEffects().get(0).setValue("damageAmount", event.getAmount());
this.getEffects().get(0).setTargetPointer(new FixedTarget(game.getControllerId(sourceObject.getId())));
return true;
}
@Override
public String getRule() {
return "The next time a source of your choice would deal damage to you this turn, instead that source deals that much damage to you and {this} deals that much damage to that source's controller.";
}
}
class EyeForAnEyeEffect extends OneShotEffect {
private final TargetSource damageSource;
public EyeForAnEyeEffect() {
super(Outcome.Damage);
super(Duration.EndOfTurn, Outcome.RedirectDamage);
staticText = "The next time a source of your choice would deal damage to you this turn, instead that source deals that much damage to you and {this} deals that much damage to that source's controller";
this.damageSource = new TargetSource();
}
public EyeForAnEyeEffect(final EyeForAnEyeEffect effect) {
super(effect);
this.damageSource = effect.damageSource.copy();
}
@Override
@ -116,15 +84,48 @@ class EyeForAnEyeEffect extends OneShotEffect {
return new EyeForAnEyeEffect(this);
}
@Override
public void init(Ability source, Game game) {
this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game);
super.init(source, game);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DAMAGE_PLAYER;
}
@Override
public boolean apply(Game game, Ability source) {
Integer damageAmount = (Integer) this.getValue("damageAmount");
UUID targetId = this.targetPointer.getFirst(game, source);
if (damageAmount != null && targetId != null) {
Player player = game.getPlayer(targetId);
if (player != null) {
player.damage(damageAmount, targetId, game, false, true);
return true;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
DamageEvent damageEvent = (DamageEvent) event;
if (controller != null) {
controller.damage(damageEvent.getAmount(), damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), damageEvent.getAppliedEffects());
UUID sourceControllerId = game.getControllerId(damageEvent.getSourceId());
if (sourceControllerId != null) {
Player sourceController = game.getPlayer(sourceControllerId);
if (sourceController != null) {
sourceController.damage(damageEvent.getAmount(), source.getSourceId(), game, false, true);
return true;
}
}
}
return false;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
DamageEvent damageEvent = (DamageEvent) event;
if (controller != null) {
if (controller.getId() == damageEvent.getTargetId() && damageEvent.getSourceId().equals(damageSource.getFirstTarget())) {
this.discard();
return true;
}
}
return false;

View file

@ -175,20 +175,41 @@ class FalseOrdersUnblockEffect extends OneShotEffect {
// Relevant ruling for Balduvian Warlord:
// 7/15/2006 If an attacking creature has an ability that triggers When this creature becomes blocked,
// it triggers when a creature blocks it due to the Warlords ability only if it was unblocked at that point.
boolean notYetBlocked = chosenGroup.getBlockers().isEmpty();
chosenGroup.addBlocker(permanent.getId(), controller.getId(), game);
chosenGroup.addBlockerToGroup(permanent.getId(), controller.getId(), game);
game.getCombat().addBlockingGroup(permanent.getId(), chosenPermanent.getId(), controller.getId(), game); // 702.21h
if (notYetBlocked) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKED, chosenPermanent.getId(), null));
for (UUID bandedId : chosenPermanent.getBandedCards()) {
CombatGroup bandedGroup = game.getCombat().findGroup(bandedId);
if (bandedGroup != null && chosenGroup.getBlockers().size() == 1) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKED, bandedId, null));
}
}
}
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.BLOCKER_DECLARED, chosenPermanent.getId(), permanent.getId(), permanent.getControllerId()));
}
CombatGroup blockGroup = findBlockingGroup(permanent, game); // a new blockingGroup is formed, so it's necessary to find it again
if (blockGroup != null) {
blockGroup.pickAttackerOrder(permanent.getControllerId(), game);
}
}
}
}
}
return true;
}
}
return false;
}
private CombatGroup findBlockingGroup(Permanent blocker, Game game) {
if (game.getCombat().blockingGroupsContains(blocker.getId())) { // if (blocker.getBlocking() > 1) {
for (CombatGroup group : game.getCombat().getBlockingGroups()) {
if (group.getBlockers().contains(blocker.getId())) {
return group;
}
}
}
return null;
}
}

View file

@ -0,0 +1,110 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.f;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.NameACardEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetOpponent;
/**
*
* @author Quercitron & L_J
*/
public class Foreshadow extends CardImpl {
public Foreshadow(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}");
// Choose a card name, then target opponent puts the top card of his or her library into his or her graveyard. If that card has the chosen name, you draw a card.
this.getSpellAbility().addEffect(new NameACardEffect(NameACardEffect.TypeOfName.ALL));
this.getSpellAbility().addEffect(new ForeshadowEffect());
this.getSpellAbility().addTarget(new TargetOpponent());
// Draw a card at the beginning of the next turn's upkeep.
this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(
new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false));
}
public Foreshadow(final Foreshadow card) {
super(card);
}
@Override
public Foreshadow copy() {
return new Foreshadow(this);
}
}
class ForeshadowEffect extends OneShotEffect {
public ForeshadowEffect() {
super(Outcome.DrawCard);
this.staticText = ", then target opponent puts the top card of his or her library into his or her graveyard. If that card has the chosen name, you draw a card";
}
public ForeshadowEffect(final ForeshadowEffect effect) {
super(effect);
}
@Override
public ForeshadowEffect copy() {
return new ForeshadowEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Player targetPlayer = game.getPlayer(source.getFirstTarget());
String cardName = (String) game.getState().getValue(source.getSourceId().toString() + NameACardEffect.INFO_KEY);
if (controller != null && targetPlayer != null && cardName != null && !cardName.isEmpty()) {
Card card = targetPlayer.getLibrary().getFromTop(game);
if (card != null) {
controller.moveCards(card, Zone.GRAVEYARD, source, game);
if (card.getName().equals(cardName)) {
controller.drawCards(1, game);
}
}
return true;
}
return false;
}
}

View file

@ -27,10 +27,13 @@
*/
package mage.cards.g;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.RegenerateTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -43,10 +46,6 @@ import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
import mage.watchers.common.BlockedAttackerWatcher;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
*
* @author LevelX2
@ -60,8 +59,7 @@ public class GazeOfTheGorgon extends CardImpl {
// Regenerate target creature. At end of combat, destroy all creatures that blocked or were blocked by that creature this turn.
this.getSpellAbility().addEffect(new RegenerateTargetEffect());
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(
new AtTheEndOfCombatDelayedTriggeredAbility(new GazeOfTheGorgonEffect())));
this.getSpellAbility().addEffect(new GazeOfTheGorgonCreateDelayedTriggeredAbilityEffect());
this.getSpellAbility().addWatcher(new BlockedAttackerWatcher());
}
@ -75,15 +73,46 @@ public class GazeOfTheGorgon extends CardImpl {
}
}
class GazeOfTheGorgonEffect extends OneShotEffect {
class GazeOfTheGorgonCreateDelayedTriggeredAbilityEffect extends OneShotEffect {
public GazeOfTheGorgonEffect() {
public GazeOfTheGorgonCreateDelayedTriggeredAbilityEffect() {
super(Outcome.Benefit);
this.staticText = "At this turn's next end of combat, destroy all creatures that blocked or were blocked by it this turn";
}
public GazeOfTheGorgonCreateDelayedTriggeredAbilityEffect(final GazeOfTheGorgonCreateDelayedTriggeredAbilityEffect effect) {
super(effect);
}
@Override
public GazeOfTheGorgonCreateDelayedTriggeredAbilityEffect copy() {
return new GazeOfTheGorgonCreateDelayedTriggeredAbilityEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
if (!source.getTargets().isEmpty() && source.getFirstTarget() != null) {
MageObjectReference mor = new MageObjectReference(source.getFirstTarget(), game);
AtTheEndOfCombatDelayedTriggeredAbility delayedAbility = new AtTheEndOfCombatDelayedTriggeredAbility(new GazeOfTheGorgonEffect(mor));
game.addDelayedTriggeredAbility(delayedAbility, source);
return true;
}
return false;
}
}
class GazeOfTheGorgonEffect extends OneShotEffect {
MageObjectReference targetCreature;
public GazeOfTheGorgonEffect(MageObjectReference targetCreature) {
super(Outcome.DestroyPermanent);
this.staticText = "destroy all creatures that blocked or were blocked by that creature this turn";
this.targetCreature = targetCreature;
}
public GazeOfTheGorgonEffect(final GazeOfTheGorgonEffect effect) {
super(effect);
targetCreature = effect.targetCreature;
}
@Override
@ -94,14 +123,13 @@ class GazeOfTheGorgonEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent targetCreature = game.getPermanentOrLKIBattlefield(source.getTargets().getFirstTarget());
if (controller != null && targetCreature != null) {
BlockedAttackerWatcher watcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName());
if (watcher != null) {
List<Permanent> toDestroy = new ArrayList<>();
for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) {
if (!creature.getId().equals(targetCreature.getId())) {
if (watcher.creatureHasBlockedAttacker(creature, targetCreature, game) || watcher.creatureHasBlockedAttacker(targetCreature, creature, game)) {
if (!creature.getId().equals(targetCreature.getSourceId())) {
if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), targetCreature, game) || watcher.creatureHasBlockedAttacker(targetCreature, new MageObjectReference(creature, game), game)) {
toDestroy.add(creature);
}
}

View file

@ -0,0 +1,153 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.g;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.InfoEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
import mage.watchers.common.BlockedAttackerWatcher;
/**
*
* @author LevelX2 & L_J
*/
public class GlyphOfDoom extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Wall creature");
static {
filter.add(new SubtypePredicate(SubType.WALL));
}
public GlyphOfDoom(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}");
// Choose target Wall creature. At this turn's next end of combat, destroy all creatures that were blocked by that creature this turn.
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter));
this.getSpellAbility().addEffect(new InfoEffect("Choose target Wall creature"));
this.getSpellAbility().addEffect(new GlyphOfDoomCreateDelayedTriggeredAbilityEffect());
this.getSpellAbility().addWatcher(new BlockedAttackerWatcher());
}
public GlyphOfDoom(final GlyphOfDoom card) {
super(card);
}
@Override
public GlyphOfDoom copy() {
return new GlyphOfDoom(this);
}
}
class GlyphOfDoomCreateDelayedTriggeredAbilityEffect extends OneShotEffect {
public GlyphOfDoomCreateDelayedTriggeredAbilityEffect() {
super(Outcome.Benefit);
this.staticText = "At this turn's next end of combat, destroy all creatures that were blocked by that creature this turn";
}
public GlyphOfDoomCreateDelayedTriggeredAbilityEffect(final GlyphOfDoomCreateDelayedTriggeredAbilityEffect effect) {
super(effect);
}
@Override
public GlyphOfDoomCreateDelayedTriggeredAbilityEffect copy() {
return new GlyphOfDoomCreateDelayedTriggeredAbilityEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
if (!source.getTargets().isEmpty() && source.getFirstTarget() != null) {
MageObjectReference mor = new MageObjectReference(source.getFirstTarget(), game);
AtTheEndOfCombatDelayedTriggeredAbility delayedAbility = new AtTheEndOfCombatDelayedTriggeredAbility(new GlyphOfDoomEffect(mor));
game.addDelayedTriggeredAbility(delayedAbility, source);
return true;
}
return false;
}
}
class GlyphOfDoomEffect extends OneShotEffect {
MageObjectReference targetCreature;
public GlyphOfDoomEffect(MageObjectReference targetCreature) {
super(Outcome.DestroyPermanent);
this.targetCreature = targetCreature;
}
public GlyphOfDoomEffect(final GlyphOfDoomEffect effect) {
super(effect);
targetCreature = effect.targetCreature;
}
@Override
public GlyphOfDoomEffect copy() {
return new GlyphOfDoomEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && targetCreature != null) {
BlockedAttackerWatcher watcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName());
if (watcher != null) {
List<Permanent> toDestroy = new ArrayList<>();
for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) {
if (!creature.getId().equals(targetCreature.getSourceId())) {
if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), targetCreature, game)) {
toDestroy.add(creature);
}
}
}
for (Permanent creature : toDestroy) {
creature.destroy(source.getSourceId(), game, false);
}
return true;
}
}
return false;
}
}

View file

@ -0,0 +1,145 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.g;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.RestrictionEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetPermanent;
import mage.target.common.TargetOpponent;
/**
*
* @author TheElk801 & L_J
*/
public class GoblinWarCry extends CardImpl {
public GoblinWarCry(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}");
// Target opponent chooses a creature he or she controls. Other creatures he or she controls can't block this turn.
this.getSpellAbility().addEffect(new GoblinWarCryEffect());
this.getSpellAbility().addTarget(new TargetOpponent());
}
public GoblinWarCry(final GoblinWarCry card) {
super(card);
}
@Override
public GoblinWarCry copy() {
return new GoblinWarCry(this);
}
}
class GoblinWarCryEffect extends OneShotEffect {
GoblinWarCryEffect() {
super(Outcome.Benefit);
this.staticText = "Target opponent chooses a creature he or she controls. Other creatures he or she controls can't block this turn.";
}
GoblinWarCryEffect(final GoblinWarCryEffect effect) {
super(effect);
}
@Override
public GoblinWarCryEffect copy() {
return new GoblinWarCryEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getFirstTarget());
if (player == null) {
return false;
}
FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control");
filter.add(new ControllerIdPredicate(player.getId()));
Target target = new TargetPermanent(1, 1, filter, true);
if (target.canChoose(source.getSourceId(), player.getId(), game)) {
while (!target.isChosen() && target.canChoose(player.getId(), game) && player.canRespond()) {
player.chooseTarget(Outcome.DestroyPermanent, target, source, game);
}
Permanent permanent = game.getPermanent(target.getFirstTarget());
if (permanent != null) {
game.informPlayers(player.getLogName() + " has chosen " + permanent.getLogName() + " as his only creature able to block this turn");
}
}
game.addEffect(new GoblinWarCryRestrictionEffect(target.getFirstTarget()), source);
return true;
}
}
class GoblinWarCryRestrictionEffect extends RestrictionEffect {
protected UUID targetId;
public GoblinWarCryRestrictionEffect(UUID targetId) {
super(Duration.EndOfTurn);
this.targetId = targetId;
}
public GoblinWarCryRestrictionEffect(final GoblinWarCryRestrictionEffect effect) {
super(effect);
targetId = effect.targetId;
}
@Override
public GoblinWarCryRestrictionEffect copy() {
return new GoblinWarCryRestrictionEffect(this);
}
@Override
public boolean applies(Permanent permanent, Ability source, Game game) {
if (permanent.getControllerId().equals(source.getFirstTarget())) {
return true;
}
return false;
}
@Override
public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) {
if (targetId != null && blocker.getId().equals(targetId)) {
return true;
}
return false;
}
}

View file

@ -0,0 +1,170 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.h;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility;
import mage.abilities.condition.common.AttackedThisStepCondition;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.PhaseStep;
import mage.constants.TurnPhase;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.AttackingPredicate;
import mage.game.Game;
import mage.game.events.DamagedPlayerEvent;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.watchers.common.PlayerAttackedStepWatcher;
/**
*
* @author LevelX2 & L_J
*/
public class HarshJustice extends CardImpl {
public HarshJustice(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}");
// Cast Harsh Justice only during the declare attackers step and only if you've been attacked this step.
Ability ability = new CastOnlyDuringPhaseStepSourceAbility(
TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance,
"Cast {this} only during the declare attackers step and only if you've been attacked this step."
);
ability.addWatcher(new PlayerAttackedStepWatcher());
this.addAbility(ability);
// This turn, whenever an attacking creature deals combat damage to you, it deals that much damage to its controller.
this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new HarshJusticeTriggeredAbility()));
}
public HarshJustice(final HarshJustice card) {
super(card);
}
@Override
public HarshJustice copy() {
return new HarshJustice(this);
}
}
class HarshJusticeTriggeredAbility extends DelayedTriggeredAbility {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking creature");
static {
filter.add(new AttackingPredicate());
}
public HarshJusticeTriggeredAbility() {
super(new HarshJusticeEffect(), Duration.EndOfTurn, false);
}
public HarshJusticeTriggeredAbility(final HarshJusticeTriggeredAbility ability) {
super(ability);
}
@Override
public HarshJusticeTriggeredAbility copy() {
return new HarshJusticeTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == EventType.DAMAGED_PLAYER;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Player controller = game.getPlayer(this.getControllerId());
DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event;
Permanent damagePermanent = game.getPermanentOrLKIBattlefield(damageEvent.getSourceId());
if (controller != null && damagePermanent != null) {
if (damageEvent.isCombatDamage() && controller.getId().equals(damageEvent.getTargetId()) && filter.match(damagePermanent, game)) {
for (Effect effect : this.getEffects()) {
effect.setValue("damage", damageEvent.getAmount());
effect.setValue("sourceId", damageEvent.getSourceId());
}
return true;
}
}
return false;
}
@Override
public String getRule() {
return "This turn, whenever an attacking creature deals combat damage to you, " + super.getRule();
}
}
class HarshJusticeEffect extends OneShotEffect {
public HarshJusticeEffect() {
super(Outcome.Benefit);
this.staticText = "it deals that much damage to its controller";
}
public HarshJusticeEffect(final HarshJusticeEffect effect) {
super(effect);
}
@Override
public HarshJusticeEffect copy() {
return new HarshJusticeEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
int damage = (Integer) this.getValue("damage");
UUID sourceId = (UUID) this.getValue("sourceId");
MageObject sourceObject = game.getObject(source.getSourceId());
if (sourceObject != null && damage > 0 && sourceId != null) {
Permanent targetObject = game.getPermanentOrLKIBattlefield(sourceId);
if (targetObject != null) {
Player controller = game.getPlayer(targetObject.getControllerId());
if (controller != null) {
game.informPlayers(sourceObject.getLogName() + ": " + targetObject.getLogName() + " deals " + damage + " damage to " + controller.getLogName());
controller.damage(damage, sourceId, game, false, true);
return true;
}
}
}
return false;
}
}

View file

@ -0,0 +1,110 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.h;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility;
import mage.abilities.condition.common.AttackedThisStepCondition;
import mage.abilities.effects.PreventionEffectImpl;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.PhaseStep;
import mage.constants.TurnPhase;
import mage.filter.common.FilterAttackingCreature;
import mage.game.Game;
import mage.game.events.DamagePlayerEvent;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.watchers.common.PlayerAttackedStepWatcher;
/**
*
* @author L_J
*/
public class HeavyFog extends CardImpl {
public HeavyFog(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}");
// Cast Deep Wood only during the declare attackers step and only if you've been attacked this step.
Ability ability = new CastOnlyDuringPhaseStepSourceAbility(
TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance,
"Cast {this} only during the declare attackers step and only if you've been attacked this step."
);
ability.addWatcher(new PlayerAttackedStepWatcher());
this.addAbility(ability);
// Prevent all damage that would be dealt to you this turn by attacking creatures.
this.getSpellAbility().addEffect(new HeavyFogEffect());
}
public HeavyFog(final HeavyFog card) {
super(card);
}
@Override
public HeavyFog copy() {
return new HeavyFog(this);
}
}
class HeavyFogEffect extends PreventionEffectImpl {
private static final FilterAttackingCreature filter = new FilterAttackingCreature();
HeavyFogEffect() {
super(Duration.EndOfTurn, Integer.MAX_VALUE, false);
staticText = "Prevent all damage that would be dealt to you this turn by attacking creatures";
}
HeavyFogEffect(final HeavyFogEffect effect) {
super(effect);
}
@Override
public HeavyFogEffect copy() {
return new HeavyFogEffect(this);
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (super.applies(event, source, game) && event instanceof DamagePlayerEvent && event.getAmount() > 0) {
DamagePlayerEvent damageEvent = (DamagePlayerEvent) event;
if (event.getTargetId().equals(source.getControllerId())) {
Permanent permanent = game.getPermanentOrLKIBattlefield(damageEvent.getSourceId());
if (permanent != null && filter.match(permanent, game)) {
return true;
}
}
}
return false;
}
}

View file

@ -27,35 +27,34 @@
*/
package mage.cards.h;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.cards.CardSetInfo;
import mage.constants.AsThoughEffectType;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.common.FilterNonlandCard;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCardInExile;
import mage.target.targetpointer.FixedTarget;
import mage.target.TargetCard;
/**
*
* @author jeffwadsworth
* @author jeffwadsworth & L_J
*/
public class HellcarverDemon extends CardImpl {
@ -84,9 +83,6 @@ public class HellcarverDemon extends CardImpl {
class HellcarverDemonEffect extends OneShotEffect {
private static final FilterControlledPermanent filterPermanents = new FilterControlledPermanent("Permanent");
private static FilterNonlandCard filter = new FilterNonlandCard("nonland card exiled with Hellcarver Demon");
public HellcarverDemonEffect() {
super(Outcome.PlayForFree);
staticText = "sacrifice all other permanents you control and discard your hand. Exile the top six cards of your library. You may cast any number of nonland cards exiled this way without paying their mana costs.";
@ -99,41 +95,43 @@ class HellcarverDemonEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent hellcarverDemon = game.getPermanent(source.getSourceId());
for (Permanent permanent : game.getBattlefield().getActivePermanents(filterPermanents, source.getControllerId(), game)) {
if (!Objects.equals(permanent, hellcarverDemon)) {
permanent.sacrifice(source.getSourceId(), game);
}
}
if (controller != null && !controller.getHand().isEmpty()) {
int cardsInHand = controller.getHand().size();
controller.discard(cardsInHand, false, source, game);
}
for (int i = 0; i < 6; i++) {
if (controller != null
&& controller.getLibrary().hasCards()) {
Card topCard = controller.getLibrary().getFromTop(game);
topCard.moveToExile(source.getSourceId(), "Cards exiled by Hellcarver Demon", source.getSourceId(), game);
}
}
while (controller != null
&& controller.canRespond()
&& controller.chooseUse(Outcome.PlayForFree, controller.getLogName() + " can cast another nonland card exiled with Hellcarver Demon without paying that card's mana cost.", source, game)) {
TargetCardInExile target = new TargetCardInExile(filter, source.getSourceId());
while (controller.chooseUse(Outcome.PlayForFree, "Cast another spell exiled by Hellcarver Demon?", source, game)) {
controller.choose(Outcome.PlayForFree, game.getExile().getExileZone(source.getSourceId()), target, game);
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
ContinuousEffect effect = new HellcarverDemonCastFromExileEffect();
effect.setTargetPointer(new FixedTarget(card.getId()));
game.addEffect(effect, source);
controller.cast(card.getSpellAbility(), game, true);
Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (controller != null && sourceObject != null) {
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) {
if (!Objects.equals(permanent, sourceObject)) {
permanent.sacrifice(source.getSourceId(), game);
}
}
if (!controller.getHand().isEmpty()) {
int cardsInHand = controller.getHand().size();
controller.discard(cardsInHand, false, source, game);
}
// move cards from library to exile
Set<Card> currentExiledCards = new HashSet<>();
currentExiledCards.addAll(controller.getLibrary().getTopCards(game, 6));
controller.moveCardsToExile(currentExiledCards, source, game, true, source.getSourceId(), sourceObject.getIdName());
// cast the possible cards without paying the mana
Cards cardsToCast = new CardsImpl();
cardsToCast.addAll(currentExiledCards);
boolean alreadyCast = false;
while (!cardsToCast.isEmpty()
&& controller.canRespond()) {
if (!controller.chooseUse(outcome, "Cast a" + (alreadyCast ? "nother" : "" ) + " card exiled with " + sourceObject.getLogName() + " without paying its mana cost?", source, game)) {
break;
}
TargetCard targetCard = new TargetCard(1, Zone.EXILED, new FilterCard("nonland card to cast for free"));
if (controller.choose(Outcome.PlayForFree, cardsToCast, targetCard, game)) {
alreadyCast = true;
Card card = game.getCard(targetCard.getFirstTarget());
if (card != null) {
if (controller.cast(card.getSpellAbility(), game, true)) {
cardsToCast.remove(card);
} else {
game.informPlayer(controller, "You're not able to cast " + card.getIdName() + " or you canceled the casting.");
}
}
}
target.clearChosen();
}
return true;
}
@ -145,33 +143,3 @@ class HellcarverDemonEffect extends OneShotEffect {
return new HellcarverDemonEffect(this);
}
}
class HellcarverDemonCastFromExileEffect extends AsThoughEffectImpl {
public HellcarverDemonCastFromExileEffect() {
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit);
staticText = "You may play the card from exile without paying its mana cost";
}
public HellcarverDemonCastFromExileEffect(final HellcarverDemonCastFromExileEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public HellcarverDemonCastFromExileEffect copy() {
return new HellcarverDemonCastFromExileEffect(this);
}
@Override
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
if (targetPointer.getTargets(game, source).contains(sourceId)) {
return game.getState().getZone(sourceId) == Zone.EXILED;
}
return false;
}
}

View file

@ -48,7 +48,7 @@ import mage.filter.predicate.mageobject.CardTypePredicate;
*/
public class HeraldOfThePantheon extends CardImpl {
private static final FilterCard filter = new FilterCard("enchantment spells");
private static final FilterCard filter = new FilterCard("Enchantment spells");
private static final FilterSpell filter2 = new FilterSpell("an enchantment spell");
static {

View file

@ -0,0 +1,108 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.h;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.PreventionEffectData;
import mage.abilities.effects.common.PreventNextDamageFromChosenSourceToTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.Player;
import mage.target.common.TargetCreatureOrPlayer;
/**
*
* @author L_J
*/
public class HonorablePassage extends CardImpl {
public HonorablePassage(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}");
// The next time a source of your choice would deal damage to target creature or player this turn, prevent that damage. If damage from a red source is prevented this way, Honorable Passage deals that much damage to the source's controller.
this.getSpellAbility().addEffect(new HonorablePassageEffect());
this.getSpellAbility().addTarget(new TargetCreatureOrPlayer());
}
public HonorablePassage(final HonorablePassage card) {
super(card);
}
@Override
public HonorablePassage copy() {
return new HonorablePassage(this);
}
}
class HonorablePassageEffect extends PreventNextDamageFromChosenSourceToTargetEffect {
public HonorablePassageEffect() {
super(Duration.EndOfTurn);
}
public HonorablePassageEffect(final HonorablePassageEffect effect) {
super(effect);
}
@Override
public HonorablePassageEffect copy() {
return new HonorablePassageEffect(this);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
int damage = event.getAmount();
PreventionEffectData preventEffectData = preventDamageAction(event, source, game);
if (preventEffectData.getPreventedDamage() > 0) {
MageObject sourceObject = game.getObject(event.getSourceId());
if (sourceObject != null && sourceObject.getColor(game).isRed()) {
UUID sourceControllerId = game.getControllerId(event.getSourceId());
if (sourceControllerId != null) {
Player sourceController = game.getPlayer(sourceControllerId);
if (sourceController != null) {
sourceController.damage(damage, source.getSourceId(), game, false, true);
}
}
}
this.used = true;
}
return false;
}
@Override
public String getText(Mode mode) {
return "The next time a source of your choice would deal damage to target creature or player this turn, prevent that damage. If damage from a red source is prevented this way, {this} deals that much damage to the source's controller";
}
}

View file

@ -41,10 +41,10 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AsThoughEffectType;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.ManaType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates;
@ -118,8 +118,8 @@ class HostageTakerExileEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent card = game.getPermanent(targetPointer.getFirst(game, source));
Permanent permanent = game.getPermanent(source.getSourceId());
Permanent card = game.getPermanent(getTargetPointer().getFirst(game, source));
Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (permanent != null && card != null) {
Player controller = game.getPlayer(card.getControllerId());
if (controller != null) {

View file

@ -31,6 +31,7 @@ import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.keyword.FlashAbility;
@ -39,9 +40,9 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AbilityType;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.EntersTheBattlefieldEvent;
@ -55,7 +56,7 @@ import mage.game.permanent.Permanent;
public class HushwingGryff extends CardImpl {
public HushwingGryff(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}");
this.subtype.add(SubType.HIPPOGRIFF);
this.power = new MageInt(2);
@ -92,10 +93,15 @@ class HushwingGryffEffect extends ContinuousRuleModifyingEffectImpl {
@Override
public String getInfoMessage(Ability source, GameEvent event, Game game) {
MageObject mageObject = game.getObject(event.getSourceId());
MageObject enteringObject = game.getObject(event.getSourceId());
MageObject sourceObject = game.getObject(source.getSourceId());
if (mageObject != null && sourceObject != null) {
return sourceObject.getLogName() + " prevented ability of " + mageObject.getLogName() + " to trigger";
Ability ability = (Ability) getValue("targetAbility");
if (enteringObject != null && sourceObject != null && ability != null) {
MageObject abilitObject = game.getObject(ability.getSourceId());
if (abilitObject != null) {
return sourceObject.getLogName() + " prevented ability of " + abilitObject.getLogName()
+ " to trigger for " + enteringObject.getLogName() + " entering the battlefield.";
}
}
return null;
}
@ -111,7 +117,7 @@ class HushwingGryffEffect extends ContinuousRuleModifyingEffectImpl {
if (ability != null && ability.getAbilityType() == AbilityType.TRIGGERED) {
Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget();
if (permanent != null && permanent.isCreature()) {
return true;
return (((TriggeredAbility) ability).checkTrigger(event, game));
}
}
return false;

View file

@ -28,6 +28,7 @@
package mage.cards.i;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.RestrictionEffect;
@ -88,7 +89,7 @@ class InterdictPredicate implements Predicate<Ability> {
@Override
public boolean apply(Ability input, Game game) {
if (input instanceof StackAbility && input.getAbilityType() == AbilityType.ACTIVATED) {
Permanent sourceObject = game.getPermanentOrLKIBattlefield(input.getSourceId());
MageObject sourceObject = input.getSourceObject(game);
if (sourceObject != null) {
return (sourceObject.isArtifact()
|| sourceObject.isEnchantment()
@ -120,9 +121,12 @@ class InterdictCounterEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
StackObject stackObject = game.getStack().getStackObject(source.getFirstTarget());
if (stackObject != null && game.getStack().counter(source.getFirstTarget(), source.getSourceId(), game)) {
InterdictCantActivateEffect effect = new InterdictCantActivateEffect();
effect.setTargetPointer(new FixedTarget(stackObject.getSourceId()));
game.getContinuousEffects().addEffect(effect, source);
Permanent sourcePermanent = stackObject.getStackAbility().getSourcePermanentIfItStillExists(game);
if (sourcePermanent != null) {
InterdictCantActivateEffect effect = new InterdictCantActivateEffect();
effect.setTargetPointer(new FixedTarget(sourcePermanent, game));
game.getContinuousEffects().addEffect(effect, source);
}
return true;
}
return false;
@ -143,7 +147,7 @@ class InterdictCantActivateEffect extends RestrictionEffect {
@Override
public boolean applies(Permanent permanent, Ability source, Game game) {
return getTargetPointer().getFirst(game, source).equals(permanent.getId());
return permanent.getId().equals(getTargetPointer().getFirst(game, source));
}
@Override

View file

@ -48,7 +48,7 @@ import mage.filter.predicate.mageobject.CardTypePredicate;
public class JacesSanctum extends CardImpl {
private static final FilterCard filter = new FilterCard("instant and sorcery spells");
private static final FilterCard filter = new FilterCard("Instant and sorcery spells");
private static final FilterSpell filter2 = new FilterSpell("an instant or sorcery spell");

View file

@ -0,0 +1,73 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.j;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility;
import mage.abilities.condition.common.AttackedThisStepCondition;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.PhaseStep;
import mage.constants.TurnPhase;
import mage.target.common.TargetAttackingCreature;
import mage.watchers.common.PlayerAttackedStepWatcher;
/**
*
* @author TheElk801
*/
public class JustFate extends CardImpl {
public JustFate(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}");
// Cast Just Fate only during the declare attackers step and only if you've been attacked this step.
Ability ability = new CastOnlyDuringPhaseStepSourceAbility(
TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance,
"Cast {this} only during the declare attackers step and only if you've been attacked this step."
);
ability.addWatcher(new PlayerAttackedStepWatcher());
this.addAbility(ability);
// Destroy target attacking creature.
this.getSpellAbility().addEffect(new DestroyTargetEffect());
this.getSpellAbility().addTarget(new TargetAttackingCreature());
}
public JustFate(final JustFate card) {
super(card);
}
@Override
public JustFate copy() {
return new JustFate(this);
}
}

View file

@ -12,25 +12,24 @@ import mage.filter.common.FilterControlledPermanent;
public class KaerveksSpite extends CardImpl {
private FilterControlledPermanent permanentsYouControl = new FilterControlledPermanent("all permanents you control");
public KaerveksSpite(UUID ownerId, CardSetInfo cardSetInfo) {
super(ownerId, cardSetInfo, new CardType[]{CardType.INSTANT}, "{B}{B}{B}");
//As an additional cost to cast Kaervek's Spite, sacrifice all permanents you control and discard your hand.
this.getSpellAbility().addCost(new SacrificeAllCost(permanentsYouControl));
// As an additional cost to cast Kaervek's Spite, sacrifice all permanents you control and discard your hand.
this.getSpellAbility().addCost(new SacrificeAllCost(new FilterControlledPermanent("permanents you control")));
this.getSpellAbility().addCost(new DiscardHandCost());
//Target player loses 5 life.
// Target player loses 5 life.
Effect effect = new LoseLifeTargetEffect(5);
this.getSpellAbility().addEffect(effect);
}
public KaerveksSpite(final KaerveksSpite other){
public KaerveksSpite(final KaerveksSpite other) {
super(other);
}
public KaerveksSpite copy(){
@Override
public KaerveksSpite copy() {
return new KaerveksSpite(this);
}
}

View file

@ -0,0 +1,75 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.k;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.TurnedFaceUpSourceTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.RedirectDamageFromSourceToTargetEffect;
import mage.abilities.keyword.MorphAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author L_J
*/
public class KaronasZealot extends CardImpl {
public KaronasZealot(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.CLERIC);
this.power = new MageInt(2);
this.toughness = new MageInt(5);
// Morph {3}{W}{W}
this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{W}{W}")));
// When Karona's Zealot is turned face up, all damage that would be dealt to it this turn is dealt to target creature instead.
Ability ability = new TurnedFaceUpSourceTriggeredAbility(new RedirectDamageFromSourceToTargetEffect(Duration.EndOfTurn, Integer.MAX_VALUE, false)
.setText("all damage that would be dealt to it this turn is dealt to target creature instead"));
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
public KaronasZealot(final KaronasZealot card) {
super(card);
}
@Override
public KaronasZealot copy() {
return new KaronasZealot(this);
}
}

View file

@ -0,0 +1,80 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.k;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.condition.CompoundCondition;
import mage.abilities.condition.common.AttackedThisStepCondition;
import mage.abilities.condition.common.IsStepCondition;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.decorator.ConditionalActivatedAbility;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.filter.common.FilterAttackingCreature;
import mage.target.TargetPermanent;
import mage.watchers.common.PlayerAttackedStepWatcher;
/**
*
* @author L_J
*/
public class KongmingsContraptions extends CardImpl {
public KongmingsContraptions(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.SOLDIER);
this.power = new MageInt(2);
this.toughness = new MageInt(4);
// {T}: Kongming's Contraptions deals 2 damage to target attacking creature. Activate this ability only during the declare attackers step and only if you've been attacked this step.
Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new TapSourceCost(),
new CompoundCondition("during the declare attackers step and only if you've been attacked this step",
new IsStepCondition(PhaseStep.DECLARE_ATTACKERS, false), AttackedThisStepCondition.instance)
);
ability.addTarget(new TargetPermanent(new FilterAttackingCreature()));
this.addAbility(ability, new PlayerAttackedStepWatcher());
}
public KongmingsContraptions(final KongmingsContraptions card) {
super(card);
}
@Override
public KongmingsContraptions copy() {
return new KongmingsContraptions(this);
}
}

View file

@ -30,6 +30,7 @@ package mage.cards.k;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -61,7 +62,9 @@ public class KrosanDrover extends CardImpl {
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)));
Effect effect = new SpellsCostReductionControllerEffect(filter, 2);
effect.setText("Creature spells you cast with converted mana cost 6 or greater cost {2} less to cast.");
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
}
public KrosanDrover(final KrosanDrover card) {

View file

@ -35,7 +35,6 @@ import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.AdjustingSourceCosts;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.GainLifeTargetEffect;
import mage.abilities.effects.common.LoseLifeTargetEffect;
import mage.abilities.effects.common.RegenerateSourceEffect;
@ -58,7 +57,7 @@ import mage.util.CardUtil;
public class LaquatussChampion extends CardImpl {
public LaquatussChampion(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}");
this.subtype.add(SubType.NIGHTMARE);
this.subtype.add(SubType.HORROR);
@ -126,9 +125,7 @@ class LaquatussChampionLeavesBattlefieldTriggeredAbility extends LeavesBattlefie
String key = CardUtil.getCardZoneString("targetPlayer", this.getSourceId(), game, true);
Object object = game.getState().getValue(key);
if (object instanceof UUID) {
for (Effect effect : this.getEffects()) {
effect.setTargetPointer(new FixedTarget((UUID) object));
}
this.getEffects().setTargetPointer(new FixedTarget((UUID) object));
return true;
}
}

View file

@ -118,7 +118,7 @@ class LeviathanCostToAttackBlockEffect extends PayCostToAttackBlockEffectImpl {
LeviathanCostToAttackBlockEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment, RestrictType.ATTACK,
new SacrificeTargetCost(new TargetControlledPermanent(2, 2, filter, false)));
staticText = "{this} can't attack unless you sacrifice two Islands <i>(This cost is paid as attackers are declared.)</i>";
staticText = "{this} can't attack unless you sacrifice two Islands. <i>(This cost is paid as attackers are declared.)</i>";
}
LeviathanCostToAttackBlockEffect(LeviathanCostToAttackBlockEffect effect) {

View file

@ -47,7 +47,7 @@ import mage.target.common.TargetCreaturePermanent;
public class LyevDecree extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponent controls");
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponents control");
static {
filter.add(new ControllerPredicate(TargetController.OPPONENT));
}
@ -56,7 +56,7 @@ public class LyevDecree extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{W}");
// Detain up to two target creatures your opponent controls.
// Detain up to two target creatures your opponents control.
this.getSpellAbility().addEffect(new DetainTargetEffect());
Target target = new TargetCreaturePermanent(0,2,filter,false);
this.getSpellAbility().addTarget(target);

View file

@ -44,7 +44,7 @@ import mage.filter.predicate.mageobject.CardTypePredicate;
*/
public class ManaMatrix extends CardImpl {
private static final FilterCard filter = new FilterCard("instant and enchantment spells");
private static final FilterCard filter = new FilterCard("Instant and enchantment spells");
static {
filter.add(Predicates.or(

View file

@ -0,0 +1,112 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.m;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.continuous.BoostAllEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SuperType;
import mage.filter.common.FilterAttackingCreature;
import mage.filter.common.FilterLandPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.SupertypePredicate;
import mage.game.Game;
import mage.game.combat.CombatGroup;
import mage.game.permanent.Permanent;
/**
*
* @author jeffwadsworth
*/
public class MercadiasDownfall extends CardImpl {
private static String rule = "Each attacking creature gets +1/+0 until end of turn for each nonbasic land defending player controls";
public MercadiasDownfall(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}");
// Each attacking creature gets +1/+0 until end of turn for each nonbasic land defending player controls.
this.getSpellAbility().addEffect(new BoostAllEffect(new DefendersNonBasicLandCount(), new StaticValue(0), Duration.EndOfTurn, new FilterAttackingCreature(), true, rule));
}
public MercadiasDownfall(final MercadiasDownfall card) {
super(card);
}
@Override
public MercadiasDownfall copy() {
return new MercadiasDownfall(this);
}
class DefendersNonBasicLandCount implements DynamicValue {
UUID defenderId;
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
for (CombatGroup group : game.getCombat().getGroups()) {
defenderId = group.getDefenderId();
if (group.isDefenderIsPlaneswalker()) {
Permanent permanent = game.getPermanent(defenderId);
if (permanent != null) {
defenderId = permanent.getControllerId();
}
}
FilterLandPermanent filter = new FilterLandPermanent("nonbasic land");
filter.add(Predicates.not(new SupertypePredicate(SuperType.BASIC)));
System.out.println("The number of nonbasic lands is " + game.getBattlefield().countAll(filter, defenderId, game));
return game.getBattlefield().countAll(filter, defenderId, game);
}
return 0;
}
@Override
public DynamicValue copy() {
return new DefendersNonBasicLandCount();
}
@Override
public String toString() {
return "X";
}
@Override
public String getMessage() {
return "the number of nonbasic lands defending player controls";
}
}
}

View file

@ -50,10 +50,10 @@ public class MerfolkRaiders extends CardImpl {
this.power = new MageInt(2);
this.toughness = new MageInt(3);
// Phasing
this.addAbility(PhasingAbility.getInstance());
// Islandwalk
this.addAbility(new IslandwalkAbility());
// Phasing
this.addAbility(PhasingAbility.getInstance());
}
public MerfolkRaiders(final MerfolkRaiders card) {

View file

@ -49,7 +49,7 @@ import mage.filter.predicate.mageobject.SubtypePredicate;
*/
public class MilitantInquisitor extends CardImpl {
private static final FilterControlledPermanent filter = new FilterControlledPermanent("equipment you control");
private static final FilterControlledPermanent filter = new FilterControlledPermanent("Equipment you control");
static {
filter.add(new CardTypePredicate(CardType.ARTIFACT));

View file

@ -38,8 +38,8 @@ import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbil
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.abilities.effects.common.CreateTokenCopyTargetEffect;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -122,7 +122,7 @@ class MimicVatTriggeredAbility extends TriggeredAbilityImpl {
&& !(permanent instanceof PermanentToken)
&& permanent.isCreature()) {
getEffects().get(0).setTargetPointer(new FixedTarget(permanent.getId()));
getEffects().get(0).setTargetPointer(new FixedTarget(permanent.getId(), game));
return true;
}
return false;
@ -152,22 +152,22 @@ class MimicVatEffect extends OneShotEffect {
if (controller == null || permanent == null) {
return false;
}
// return older cards to graveyard
Set<Card> toGraveyard = new HashSet<>();
for (UUID imprintedId : permanent.getImprinted()) {
Card card = game.getCard(imprintedId);
if (card != null) {
toGraveyard.add(card);
}
}
controller.moveCards(toGraveyard, Zone.GRAVEYARD, source, game);
permanent.clearImprinted(game);
// Imprint a new one
Card card = game.getCard(getTargetPointer().getFirst(game, source));
if (card != null) {
controller.moveCardsToExile(card, source, game, true, source.getSourceId(), permanent.getName() + " (Imprint)");
permanent.imprint(card.getId(), game);
Card newCard = game.getCard(getTargetPointer().getFirst(game, source));
if (newCard != null) {
// return older cards to graveyard
Set<Card> toGraveyard = new HashSet<>();
for (UUID imprintedId : permanent.getImprinted()) {
Card card = game.getCard(imprintedId);
if (card != null) {
toGraveyard.add(card);
}
}
controller.moveCards(toGraveyard, Zone.GRAVEYARD, source, game);
permanent.clearImprinted(game);
controller.moveCardsToExile(newCard, source, game, true, source.getSourceId(), permanent.getName() + " (Imprint)");
permanent.imprint(newCard.getId(), game);
}
return true;

View file

@ -0,0 +1,113 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.m;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AsEntersBattlefieldAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.InfoEffect;
import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubLayer;
import mage.constants.Zone;
import mage.game.Game;
import mage.players.Player;
/**
*
* @author L_J
*/
public class MinionOfTheWastes extends CardImpl {
public MinionOfTheWastes(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}{B}");
this.subtype.add(SubType.MINION);
this.power = new MageInt(0);
this.toughness = new MageInt(0);
// Trample
this.addAbility(TrampleAbility.getInstance());
// As Minion of the Wastes enters the battlefield, pay any amount of life. The amount you pay can't be more than the total number of white nontoken permanents your opponents control plus the total number of white cards in their graveyards.
this.addAbility(new AsEntersBattlefieldAbility(new MinionOfTheWastesEffect()));
// Minion of the Wastes's power and toughness are each equal to the life paid as it entered the battlefield.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("{this}'s power and toughness are each equal to the life paid as it entered the battlefield")));
}
public MinionOfTheWastes(final MinionOfTheWastes card) {
super(card);
}
@Override
public MinionOfTheWastes copy() {
return new MinionOfTheWastes(this);
}
}
class MinionOfTheWastesEffect extends OneShotEffect {
public MinionOfTheWastesEffect() {
super(Outcome.LoseLife);
staticText = "pay any amount of life";
}
public MinionOfTheWastesEffect(final MinionOfTheWastesEffect effect) {
super(effect);
}
@Override
public MinionOfTheWastesEffect copy() {
return new MinionOfTheWastesEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Card sourceCard = game.getCard(source.getSourceId());
int payAmount = controller.getAmount(0, controller.getLife(), "Pay any amount of life", game);
controller.loseLife(payAmount, game, false);
game.informPlayers(new StringBuilder(sourceCard.getLogName()).append(": ").append(controller.getLogName())
.append(" pays ").append(payAmount).append(" life").toString());
game.addEffect(new SetPowerToughnessSourceEffect(payAmount, payAmount, Duration.Custom, SubLayer.SetPT_7b), source);
return true;
}
return false;
}
}

View file

@ -0,0 +1,137 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.m;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.BecomesChosenCreatureTypeSourceEffect;
import mage.abilities.effects.common.continuous.BecomesCreatureTypeTargetEffect;
import mage.constants.SubType;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.choices.Choice;
import mage.choices.ChoiceCreatureType;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
/**
*
* @author L_J
*/
public class MistformWakecaster extends CardImpl {
public MistformWakecaster(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}");
this.subtype.add(SubType.ILLUSION);
this.power = new MageInt(2);
this.toughness = new MageInt(3);
// Flying
this.addAbility(FlyingAbility.getInstance());
// {1}: Mistform Wakecaster becomes the creature type of your choice until end of turn.
this.addAbility(new SimpleActivatedAbility(new BecomesChosenCreatureTypeSourceEffect(), new ManaCostsImpl("{1}")));
// {2}{U}{U}, {T}: Choose a creature type. Each creature you control becomes that type until end of turn.
Ability ability = new SimpleActivatedAbility(new BecomesChosenCreatureTypeControlledEffect(), new ManaCostsImpl("{2}{U}{U}"));
ability.addCost(new TapSourceCost());
this.addAbility(ability);
}
public MistformWakecaster(final MistformWakecaster card) {
super(card);
}
@Override
public MistformWakecaster copy() {
return new MistformWakecaster(this);
}
}
class BecomesChosenCreatureTypeControlledEffect extends OneShotEffect {
public BecomesChosenCreatureTypeControlledEffect() {
super(Outcome.BoostCreature);
staticText = "Choose a creature type. Each creature you control becomes that type until end of turn";
}
public BecomesChosenCreatureTypeControlledEffect(final BecomesChosenCreatureTypeControlledEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
Card card = game.getCard(source.getSourceId());
String chosenType = "";
if (player != null && card != null) {
Choice typeChoice = new ChoiceCreatureType();
String msg = "Choose a creature type";
typeChoice.setMessage(msg);
while (!player.choose(Outcome.BoostCreature, typeChoice, game)) {
if (!player.canRespond()) {
return false;
}
}
game.informPlayers(card.getName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoice());
chosenType = typeChoice.getChoice();
if (chosenType != null && !chosenType.isEmpty()) {
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), player.getId(), game)) {
ContinuousEffect effect = new BecomesCreatureTypeTargetEffect(Duration.EndOfTurn, SubType.byDescription(chosenType));
effect.setTargetPointer(new FixedTarget(permanent.getId()));
game.addEffect(effect, source);
}
return true;
}
}
return false;
}
@Override
public Effect copy() {
return new BecomesChosenCreatureTypeControlledEffect(this);
}
}

View file

@ -25,7 +25,6 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.m;
import java.io.Serializable;
@ -50,9 +49,11 @@ import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.filter.predicate.permanent.TappedPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.MyrToken;
import mage.players.Player;
import mage.target.TargetPermanent;
import mage.watchers.common.CreatureAttackedWhichPlayerWatcher;
/**
*
@ -61,7 +62,7 @@ import mage.target.TargetPermanent;
public class MyrBattlesphere extends CardImpl {
public MyrBattlesphere(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{7}");
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{7}");
this.subtype.add(SubType.MYR);
this.subtype.add(SubType.CONSTRUCT);
this.power = new MageInt(4);
@ -71,7 +72,8 @@ public class MyrBattlesphere extends CardImpl {
this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new MyrToken(), 4), false));
// Whenever Myr Battlesphere attacks, you may tap X untapped Myr you control. If you do, Myr Battlesphere gets +X/+0 until end of turn and deals X damage to defending player.
this.addAbility(new AttacksTriggeredAbility(new MyrBattlesphereEffect(), true));
this.addAbility(new AttacksTriggeredAbility(new MyrBattlesphereEffect(), true), new CreatureAttackedWhichPlayerWatcher());
}
public MyrBattlesphere(final MyrBattlesphere card) {
@ -107,42 +109,46 @@ class MyrBattlesphereEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
int tappedAmount = 0;
TargetPermanent target = new TargetPermanent(0,1,filter, false);
while (true && controller.canRespond()) {
target.clearChosen();
if (target.canChoose(source.getControllerId(), game)) {
Map<String, Serializable> options = new HashMap<>();
options.put("UI.right.btn.text", "Myr tapping complete");
controller.choose(outcome, target, source.getControllerId(), game, options);
if (!target.getTargets().isEmpty()) {
UUID creature = target.getFirstTarget();
if (creature != null) {
game.getPermanent(creature).tap(game);
tappedAmount++;
CreatureAttackedWhichPlayerWatcher watcher = (CreatureAttackedWhichPlayerWatcher) game.getState().getWatchers().get(CreatureAttackedWhichPlayerWatcher.class.getSimpleName());
if (watcher != null) {
// even if the Myr Battlesphere is off the battlefield, it still does damage to the defender
Permanent myr = game.getPermanentOrLKIBattlefield(source.getSourceId());
UUID defenderId = watcher.getPlayerAttackedThisTurnByCreature(myr.getId());
Player defender = game.getPlayer(defenderId);
int tappedAmount = 0;
TargetPermanent target = new TargetPermanent(0, 1, filter, false);
while (true && controller.canRespond()) {
target.clearChosen();
if (target.canChoose(source.getControllerId(), game)) {
Map<String, Serializable> options = new HashMap<>();
options.put("UI.right.btn.text", "Myr tapping complete");
controller.choose(outcome, target, source.getControllerId(), game, options);
if (!target.getTargets().isEmpty()) {
UUID creature = target.getFirstTarget();
if (creature != null) {
game.getPermanent(creature).tap(game);
tappedAmount++;
}
} else {
break;
}
} else {
break;
}
}
else {
break;
}
}
if (tappedAmount > 0) {
game.informPlayers(new StringBuilder(controller.getLogName()).append(" taps ").append(tappedAmount).append(" Myrs").toString());
// boost effect
game.addEffect(new BoostSourceEffect(tappedAmount, 0, Duration.EndOfTurn), source);
// damage to defender
UUID defenderId = game.getCombat().getDefendingPlayerId(source.getSourceId(), game);
Player defender = game.getPlayer(defenderId);
if (defender != null) {
defender.damage(tappedAmount, source.getSourceId(), game, false, true);
return true;
}
if (tappedAmount > 0) {
game.informPlayers(new StringBuilder(controller.getLogName()).append(" taps ").append(tappedAmount).append(" Myrs").toString());
// boost effect
game.addEffect(new BoostSourceEffect(tappedAmount, 0, Duration.EndOfTurn), source);
// damage to defender
if (defender != null) {
defender.damage(tappedAmount, myr.getId(), game, false, true);
return true;
}
}
return true;
}
return true;
}
return false;
}

View file

@ -0,0 +1,136 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.n;
import java.util.UUID;
import mage.MageInt;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.AsEntersBattlefieldAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.InfoEffect;
import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubLayer;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.filter.predicate.other.OwnerPredicate;
import mage.filter.predicate.permanent.ControllerPredicate;
import mage.filter.predicate.permanent.TokenPredicate;
import mage.game.Game;
import mage.players.Player;
/**
*
* @author L_J
*/
public class NamelessRace extends CardImpl {
public NamelessRace(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}");
this.power = new MageInt(0);
this.toughness = new MageInt(0);
// Trample
this.addAbility(TrampleAbility.getInstance());
// As Nameless Race enters the battlefield, pay any amount of life. The amount you pay can't be more than the total number of white nontoken permanents your opponents control plus the total number of white cards in their graveyards.
this.addAbility(new AsEntersBattlefieldAbility(new NamelessRaceEffect()));
// Nameless Race's power and toughness are each equal to the life paid as it entered the battlefield.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("{this}'s power and toughness are each equal to the life paid as it entered the battlefield")));
}
public NamelessRace(final NamelessRace card) {
super(card);
}
@Override
public NamelessRace copy() {
return new NamelessRace(this);
}
}
class NamelessRaceEffect extends OneShotEffect {
private static final FilterPermanent filter = new FilterPermanent("white nontoken permanents your opponents control");
private static final FilterCard filter2 = new FilterCard("white cards in their graveyards");
static {
filter.add(new ColorPredicate(ObjectColor.WHITE));
filter.add(Predicates.not(new TokenPredicate()));
filter.add(new ControllerPredicate(TargetController.OPPONENT));
filter2.add(new ColorPredicate(ObjectColor.WHITE));
filter2.add(new OwnerPredicate(TargetController.OPPONENT));
}
public NamelessRaceEffect() {
super(Outcome.LoseLife);
staticText = "pay any amount of life. The amount you pay can't be more than the total number of white nontoken permanents your opponents control plus the total number of white cards in their graveyards";
}
public NamelessRaceEffect(final NamelessRaceEffect effect) {
super(effect);
}
@Override
public NamelessRaceEffect copy() {
return new NamelessRaceEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Card sourceCard = game.getCard(source.getSourceId());
int permanentsInPlay = new PermanentsOnBattlefieldCount(filter).calculate(game, source, null);
int cardsInGraveyards = new CardsInAllGraveyardsCount(filter2).calculate(game, source, null);
int maxAmount = Math.min(permanentsInPlay + cardsInGraveyards, controller.getLife());
int payAmount = controller.getAmount(0, maxAmount, "Pay up to " + maxAmount + " life", game);
controller.loseLife(payAmount, game, false);
game.informPlayers(new StringBuilder(sourceCard.getLogName()).append(": ").append(controller.getLogName())
.append(" pays ").append(payAmount).append(" life").toString());
game.addEffect(new SetPowerToughnessSourceEffect(payAmount, payAmount, Duration.Custom, SubLayer.SetPT_7b), source);
return true;
}
return false;
}
}

View file

@ -51,18 +51,23 @@ import mage.target.common.TargetCreatureOrPlayer;
public class NivMizzetTheFiremind extends CardImpl {
public NivMizzetTheFiremind(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}{U}{R}{R}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}{R}{R}");
addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.DRAGON);
this.subtype.add(SubType.WIZARD);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
// Flying
this.addAbility(FlyingAbility.getInstance());
// Whenever you draw a card, Niv-Mizzet, the Firemind deals 1 damage to target creature or player.
Ability ability = new DrawCardControllerTriggeredAbility(new DamageTargetEffect(1), false);
ability.addTarget(new TargetCreatureOrPlayer());
this.addAbility(ability);
// {T}: Draw a card.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new TapSourceCost()));
}

View file

@ -0,0 +1,94 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.o;
import java.util.UUID;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.dynamicvalue.common.AttackingCreatureCount;
import mage.abilities.effects.common.GainLifeEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
/**
*
* @author L_J
*/
public class OrimsPrayer extends CardImpl {
public OrimsPrayer(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{W}");
// Whenever one or more creatures attack you, you gain 1 life for each attacking creature.
this.addAbility(new OrimsPrayerTriggeredAbility());
}
public OrimsPrayer(final OrimsPrayer card) {
super(card);
}
@Override
public OrimsPrayer copy() {
return new OrimsPrayer(this);
}
}
class OrimsPrayerTriggeredAbility extends TriggeredAbilityImpl {
public OrimsPrayerTriggeredAbility() {
super(Zone.BATTLEFIELD, new GainLifeEffect(new AttackingCreatureCount()));
}
public OrimsPrayerTriggeredAbility(final OrimsPrayerTriggeredAbility ability) {
super(ability);
}
@Override
public OrimsPrayerTriggeredAbility copy() {
return new OrimsPrayerTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == EventType.DECLARED_ATTACKERS;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return game.getCombat().getDefenders().contains(getControllerId());
}
@Override
public String getRule() {
return "Whenever one or more creatures attack you, " + super.getRule();
}
}

View file

@ -50,7 +50,7 @@ import mage.game.events.NumberOfTriggersEvent;
public class Panharmonicon extends CardImpl {
public Panharmonicon(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}");
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
// 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.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PanharmoniconEffect()));
@ -95,7 +95,9 @@ class PanharmoniconEffect extends ReplacementEffectImpl {
if (source.getControllerId().equals(event.getPlayerId())) {
GameEvent sourceEvent = numberOfTriggersEvent.getSourceEvent();
// Only EtB triggers
if (sourceEvent.getType() == EventType.ENTERS_THE_BATTLEFIELD && sourceEvent instanceof EntersTheBattlefieldEvent) {
if (sourceEvent != null
&& sourceEvent.getType() == EventType.ENTERS_THE_BATTLEFIELD
&& sourceEvent instanceof EntersTheBattlefieldEvent) {
EntersTheBattlefieldEvent entersTheBattlefieldEvent = (EntersTheBattlefieldEvent) sourceEvent;
// Only for entering artifacts or creatures
if (entersTheBattlefieldEvent.getTarget().isArtifact()
@ -116,4 +118,4 @@ class PanharmoniconEffect extends ReplacementEffectImpl {
event.setAmount(event.getAmount() + 1);
return false;
}
}
}

View file

@ -0,0 +1,181 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.p;
import java.util.Arrays;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCardInLibrary;
import mage.util.CardUtil;
import mage.util.RandomUtil;
/**
*
* @author jeffwadsworth
*/
public class ParallelThoughts extends CardImpl {
public ParallelThoughts(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}");
// When Parallel Thoughts enters the battlefield, search your library for seven cards, exile them in a face-down pile, and shuffle that pile. Then shuffle your library.
this.addAbility(new EntersBattlefieldTriggeredAbility(new ParallelThoughtsSearchEffect()));
// If you would draw a card, you may instead put the top card of the pile you exiled into your hand.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ParallelThoughtsReplacementEffect()));
}
public ParallelThoughts(final ParallelThoughts card) {
super(card);
}
@Override
public ParallelThoughts copy() {
return new ParallelThoughts(this);
}
}
class ParallelThoughtsSearchEffect extends OneShotEffect {
ParallelThoughtsSearchEffect() {
super(Outcome.Neutral);
this.staticText = "search your library for seven cards, exile them in a face-down pile, and shuffle that pile. Then shuffle your library";
}
ParallelThoughtsSearchEffect(final ParallelThoughtsSearchEffect effect) {
super(effect);
}
@Override
public ParallelThoughtsSearchEffect copy() {
return new ParallelThoughtsSearchEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
Cards cardsInExilePile = new CardsImpl();
if (controller != null
&& permanent != null) {
TargetCardInLibrary target = new TargetCardInLibrary(7, new FilterCard());
if (controller.searchLibrary(target, game)) {
for (UUID targetId : target.getTargets()) {
Card card = controller.getLibrary().getCard(targetId, game);
if (card != null) {
cardsInExilePile.add(card);
}
}
// shuffle that exiled pile
UUID[] shuffled = cardsInExilePile.toArray(new UUID[0]);
for (int n = shuffled.length - 1; n > 0; n--) {
int r = RandomUtil.nextInt(n + 1);
UUID temp = shuffled[n];
shuffled[n] = shuffled[r];
shuffled[r] = temp;
}
cardsInExilePile.clear();
cardsInExilePile.addAll(Arrays.asList(shuffled));
// move to exile zone and turn face down
for (Card card : cardsInExilePile.getCards(game)) {
controller.moveCardsToExile(card, source, game, false, CardUtil.getCardExileZoneId(game, source), permanent.getLogName());
card.setFaceDown(true, game);
}
// shuffle controller library
controller.shuffleLibrary(source, game);
}
return true;
}
return false;
}
}
class ParallelThoughtsReplacementEffect extends ReplacementEffectImpl {
ParallelThoughtsReplacementEffect() {
super(Duration.WhileOnBattlefield, Outcome.DrawCard);
staticText = "If you would draw a card, you may instead put the top card of the pile you exiled with Parallel Thoughts into your hand";
}
ParallelThoughtsReplacementEffect(final ParallelThoughtsReplacementEffect effect) {
super(effect);
}
@Override
public ParallelThoughtsReplacementEffect copy() {
return new ParallelThoughtsReplacementEffect(this);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null
&& !game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)).getCards(game).isEmpty()) {
Card card = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)).getCards(game).iterator().next();
if (card != null) {
controller.moveCards(card, Zone.HAND, source, game);
}
}
return true;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == EventType.DRAW_CARD;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
return source.getControllerId().equals(event.getPlayerId());
}
}

View file

@ -0,0 +1,115 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.p;
import java.util.UUID;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.PutCardFromHandOnTopOfLibraryCost;
import mage.abilities.effects.PreventionEffectImpl;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.target.TargetSource;
/**
*
* @author jeffwadsworth
*/
public class Penance extends CardImpl {
public Penance(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}");
// Put a card from your hand on top of your library: The next time a black or red source of your choice would deal damage this turn, prevent that damage.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new PenanceEffect(), new PutCardFromHandOnTopOfLibraryCost()));
}
public Penance(final Penance card) {
super(card);
}
@Override
public Penance copy() {
return new Penance(this);
}
}
class PenanceEffect extends PreventionEffectImpl {
private final TargetSource target;
public PenanceEffect() {
super(Duration.EndOfTurn, Integer.MAX_VALUE, false, false);
this.staticText = "The next time a black or red source of your choice would deal damage to you this turn, prevent that damage.";
this.target = new TargetSource();
}
public PenanceEffect(final PenanceEffect effect) {
super(effect);
this.target = effect.target.copy();
}
@Override
public PenanceEffect copy() {
return new PenanceEffect(this);
}
@Override
public void init(Ability source, Game game) {
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game);
super.init(source, game);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
this.used = true;
this.discard(); // only one use
return true;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (!this.used
&& super.applies(event, source, game)) {
if (event.getTargetId().equals(source.getControllerId())
&& event.getSourceId().equals(target.getFirstTarget())) {
return (game.getObject(target.getFirstTarget()).getColor(game).contains(ObjectColor.BLACK)
|| game.getObject(target.getFirstTarget()).getColor(game).contains(ObjectColor.RED));
}
}
return false;
}
}

View file

@ -46,7 +46,7 @@ public class PlanarGate extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{6}");
// Creature spells you cast cost up to {2} less to cast.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(new FilterCreatureCard("creature spells"), 2, true)));
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(new FilterCreatureCard("Creature spells"), 2, true)));
}
public PlanarGate(final PlanarGate card) {

View file

@ -0,0 +1,133 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.p;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.PreventDamageByTargetEffect;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPermanent;
import mage.target.common.TargetEnchantmentPermanent;
import mage.target.targetpointer.FixedTarget;
/**
*
* @author L_J
*/
public class PowerLeak extends CardImpl {
public PowerLeak(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{U}");
this.subtype.add(SubType.AURA);
// Enchant enchantment
TargetPermanent auraTarget = new TargetEnchantmentPermanent();
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment));
this.addAbility(new EnchantAbility(auraTarget.getTargetName()));
// At the beginning of the upkeep of enchanted enchantment's controller, that player may pay any amount of mana. Power Leak deals 2 damage to that player. Prevent X of that damage, where X is the amount of mana that player paid this way.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new PowerLeakEffect(), TargetController.CONTROLLER_ATTACHED_TO, false, true, "At the beginning of the upkeep of enchanted enchantment's controller, "));
}
public PowerLeak(final PowerLeak card) {
super(card);
}
@Override
public PowerLeak copy() {
return new PowerLeak(this);
}
}
class PowerLeakEffect extends OneShotEffect {
public PowerLeakEffect() {
super(Outcome.Detriment);
this.staticText = "that player may pay any amount of mana. {this} deals 2 damage to that player. Prevent X of that damage, where X is the amount of mana that player paid this way";
}
public PowerLeakEffect(final PowerLeakEffect effect) {
super(effect);
}
@Override
public PowerLeakEffect copy() {
return new PowerLeakEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(game.getActivePlayerId());
Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (player != null && permanent != null) {
ManaCosts<ManaCost> cost = new ManaCostsImpl<>("{X}");
String message = "Pay {X} to prevent X damage from " + permanent.getLogName() + "?";
int xValue = 0;
if (player != null && player.chooseUse(Outcome.Neutral, message, source, game)) {
xValue = player.announceXMana(0, Integer.MAX_VALUE, "Choose the amount of mana to pay", game, source);
cost.add(new GenericManaCost(xValue));
if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) {
game.informPlayers(player.getLogName() + " paid {" + xValue + "} for " + permanent.getLogName());
} else {
game.informPlayers(player.getLogName() + " didn't pay {X} for " + permanent.getLogName());
}
} else {
game.informPlayers(player.getLogName() + " didn't pay {X} for " + permanent.getLogName());
}
PreventDamageByTargetEffect effect = new PreventDamageByTargetEffect(Duration.OneUse, xValue, false);
if (xValue != 0 && cost.isPaid()) {
effect.setTargetPointer(new FixedTarget(permanent.getId()));
game.addEffect(effect, source);
}
player.damage(2, source.getSourceId(), game, false, true);
effect.discard();
return true;
}
return false;
}
}

View file

@ -93,11 +93,6 @@ class ProgenitusProtectionAbility extends ProtectionAbility {
return new ProgenitusProtectionAbility(this);
}
@Override
public String getRule() {
return "Protection from everything";
}
@Override
public boolean canTarget(MageObject source, Game game) {
return false;

View file

@ -0,0 +1,134 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.p;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.Mana;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.PayLifeCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.PreventionEffectImpl;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetSource;
import mage.util.CardUtil;
/**
*
* @author jeffwadsworth
*/
public class ProtectiveSphere extends CardImpl {
public ProtectiveSphere(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}");
// {1}, Pay 1 life: Prevent all damage that would be dealt to you this turn by a source of your choice that shares a color with the mana spent on this activation cost.
Ability ability = new SimpleActivatedAbility(new ProtectiveSphereEffect(), new ManaCostsImpl("{1}"));
ability.addCost(new PayLifeCost(1));
this.addAbility(ability);
}
public ProtectiveSphere(final ProtectiveSphere card) {
super(card);
}
@Override
public ProtectiveSphere copy() {
return new ProtectiveSphere(this);
}
}
class ProtectiveSphereEffect extends PreventionEffectImpl {
private final TargetSource target;
private static Mana manaUsed;
private static List<ObjectColor> colorsOfChosenSource = new ArrayList<>();
public ProtectiveSphereEffect() {
super(Duration.EndOfTurn, Integer.MAX_VALUE, false, false);
this.staticText = "Prevent all damage that would be dealt to you this turn by a source of your choice that shares a color with the mana spent on this activation cost.";
this.target = new TargetSource();
}
public ProtectiveSphereEffect(final ProtectiveSphereEffect effect) {
super(effect);
this.target = effect.target.copy();
}
@Override
public ProtectiveSphereEffect copy() {
return new ProtectiveSphereEffect(this);
}
@Override
public void init(Ability source, Game game) {
target.setNotTarget(true);
target.setRequired(false);
Player controller = game.getPlayer(source.getControllerId());
Permanent protectiveSphere = game.getPermanent(source.getSourceId());
if (controller != null
&& protectiveSphere != null) {
game.getState().setValue("ProtectiveSphere" + source.getSourceId().toString(), source.getManaCostsToPay().getUsedManaToPay()); //store the mana used to pay
protectiveSphere.addInfo("MANA USED", CardUtil.addToolTipMarkTags("Last mana used for protective ability: " + source.getManaCostsToPay().getUsedManaToPay()), game);
}
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game);
super.init(source, game);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
return true;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
manaUsed = (Mana) game.getState().getValue("ProtectiveSphere" + source.getSourceId().toString());
if (super.applies(event, source, game)) {
if (event.getTargetId().equals(source.getControllerId())
&& event.getSourceId().equals(target.getFirstTarget())) {
colorsOfChosenSource = game.getObject(target.getFirstTarget()).getColor(game).getColors();
if (colorsOfChosenSource.stream().anyMatch((c) -> (manaUsed.getColor(c.getColoredManaSymbol()) > 0))) {
return true;
}
}
}
return false;
}
}

View file

@ -0,0 +1,70 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.p;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.TurnedFaceUpSourceTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.continuous.BecomesChosenCreatureTypeSourceEffect;
import mage.abilities.keyword.MorphAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.SubType;
/**
*
* @author L_J
*/
public class ProteusMachine extends CardImpl {
public ProteusMachine(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}");
this.subtype.add(SubType.SHAPESHIFTER);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Morph {0}
this.addAbility(new MorphAbility(this, new ManaCostsImpl("{0}")));
// When Proteus Machine is turned face up, it becomes the creature type of your choice. (This effect lasts indefinitely.)
this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new BecomesChosenCreatureTypeSourceEffect(false, Duration.Custom)));
}
public ProteusMachine(final ProteusMachine card) {
super(card);
}
@Override
public ProteusMachine copy() {
return new ProteusMachine(this);
}
}

View file

@ -0,0 +1,112 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.p;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.effects.keyword.ScryEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.game.Game;
import mage.players.Player;
/**
*
* @author LevelX2
*/
public class PutridCyclops extends CardImpl {
public PutridCyclops(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}");
this.subtype.add(SubType.ZOMBIE);
this.subtype.add(SubType.CYCLOPS);
this.power = new MageInt(3);
this.toughness = new MageInt(3);
// When Putrid Cyclops enters the battlefield, scry 1, then reveal the top card of your library. Putrid Cyclops gets -X/-X until end of turn, where X is that card's converted mana cost.
this.addAbility(new EntersBattlefieldTriggeredAbility(new PutridCyclopEffect()));
}
public PutridCyclops(final PutridCyclops card) {
super(card);
}
@Override
public PutridCyclops copy() {
return new PutridCyclops(this);
}
}
class PutridCyclopEffect extends OneShotEffect {
public PutridCyclopEffect() {
super(Outcome.Detriment);
this.staticText = "scry 1, then reveal the top card of your library. {this} gets -X/-X until end of turn, where X is that card's converted mana cost"
+ " <i>(To scry 1, look at the top card of your library, then you may put that card on the bottom of your library.)</i>";
}
public PutridCyclopEffect(final PutridCyclopEffect effect) {
super(effect);
}
@Override
public PutridCyclopEffect copy() {
return new PutridCyclopEffect(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) {
new ScryEffect(1).apply(game, source);
Card card = controller.getLibrary().getFromTop(game);
if (card != null) {
controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game);
int unboost = card.getConvertedManaCost() * -1;
ContinuousEffect effect = new BoostSourceEffect(unboost, unboost, Duration.EndOfTurn);
game.addEffect(effect, source);
}
return true;
}
return false;
}
}

View file

@ -0,0 +1,135 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.r;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.WatcherScope;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.watchers.Watcher;
/**
*
* @author jeffwadsworth, MTGFan & L_J
*/
public class ReversePolarity extends CardImpl {
public ReversePolarity(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}{W}");
// You gain X life, where X is twice the damage dealt to you so far this turn by artifacts.
this.getSpellAbility().addEffect(new GainLifeEffect(new ReversePolarityAmount(), "You gain X life, where X is twice the damage dealt to you so far this turn by artifacts"));
this.getSpellAbility().addWatcher(new ReversePolarityWatcher());
}
public ReversePolarity(final ReversePolarity card) {
super(card);
}
@Override
public ReversePolarity copy() {
return new ReversePolarity(this);
}
}
class ReversePolarityAmount implements DynamicValue {
@Override
public int calculate(Game game, Ability source, Effect effect) {
ReversePolarityWatcher watcher = (ReversePolarityWatcher) game.getState().getWatchers().get(ReversePolarityWatcher.class.getSimpleName());
if(watcher != null) {
return watcher.getArtifactDamageReceivedThisTurn(source.getControllerId()) * 2;
}
return 0;
}
@Override
public ReversePolarityAmount copy() {
return new ReversePolarityAmount();
}
@Override
public String getMessage() {
return "";
}
}
class ReversePolarityWatcher extends Watcher {
private final Map<UUID, Integer> artifactDamageReceivedThisTurn = new HashMap<>();
public ReversePolarityWatcher() {
super(ReversePolarityWatcher.class.getSimpleName(), WatcherScope.GAME);
}
public ReversePolarityWatcher(final ReversePolarityWatcher watcher) {
super(watcher);
for (Entry<UUID, Integer> entry : watcher.artifactDamageReceivedThisTurn.entrySet()) {
artifactDamageReceivedThisTurn.put(entry.getKey(), entry.getValue());
}
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.DAMAGED_PLAYER) {
UUID playerId = event.getTargetId();
if (playerId != null) {
Permanent permanent = game.getPermanent(event.getSourceId());
if (permanent != null && permanent.isArtifact()) {
artifactDamageReceivedThisTurn.putIfAbsent(playerId, 0);
artifactDamageReceivedThisTurn.compute(playerId, (k, v) -> v + event.getAmount());
}
}
}
}
public int getArtifactDamageReceivedThisTurn(UUID playerId) {
return artifactDamageReceivedThisTurn.getOrDefault(playerId, 0);
}
@Override
public void reset() {
artifactDamageReceivedThisTurn.clear();
}
@Override
public ReversePolarityWatcher copy() {
return new ReversePolarityWatcher(this);
}
}

View file

@ -0,0 +1,173 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.r;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.SacrificeTargetEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.replacement.DealtDamageToCreatureBySourceDies;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
import mage.target.common.TargetAttackingCreature;
import mage.target.targetpointer.FixedTarget;
import mage.watchers.common.DamagedByWatcher;
/**
*
* @author L_J
*/
public class Runesword extends CardImpl {
public Runesword(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{6}");
// {3}, {T}: Target attacking creature gets +2/+0 until end of turn.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(2, 0, Duration.EndOfTurn), new GenericManaCost(3));
// When that creature leaves the battlefield this turn, sacrifice Runesword.
ability.addEffect(new RuneswordCreateTriggeredAbilityEffect());
// If the creature deals damage to a creature this turn, the creature dealt damage can't be regenerated this turn.
ability.addEffect(new RuneswordCantBeRegeneratedEffect());
// If a creature dealt damage by the targeted creature would die this turn, exile that creature instead.
SimpleStaticAbility ability2 = new SimpleStaticAbility(Zone.BATTLEFIELD, new DealtDamageToCreatureBySourceDies(this, Duration.Custom));
ability2.addWatcher(new DamagedByWatcher());
ability2.setRuleVisible(false);
ability.addEffect(new GainAbilityTargetEffect(ability2, Duration.EndOfTurn, null, false).setText(
"If a creature dealt damage by the targeted creature would die this turn, exile that creature instead"));
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetAttackingCreature());
this.addAbility(ability);
}
public Runesword(final Runesword card) {
super(card);
}
@Override
public Runesword copy() {
return new Runesword(this);
}
}
class RuneswordCreateTriggeredAbilityEffect extends OneShotEffect {
public RuneswordCreateTriggeredAbilityEffect() {
super(Outcome.PutCreatureInPlay);
staticText = "When that creature leaves the battlefield this turn, sacrifice {this}";
}
public RuneswordCreateTriggeredAbilityEffect(final RuneswordCreateTriggeredAbilityEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId());
Permanent targetObject = game.getPermanent(this.getTargetPointer().getFirst(game, source));
if (sourceObject != null && targetObject != null) {
Effect sacrificeEffect = new SacrificeTargetEffect("sacrifice " + sourceObject.getName());
sacrificeEffect.setTargetPointer(new FixedTarget(sourceObject, game));
LeavesBattlefieldTriggeredAbility triggerAbility = new LeavesBattlefieldTriggeredAbility(sacrificeEffect, false);
triggerAbility.setRuleVisible(false);
ContinuousEffect continuousEffect = new GainAbilityTargetEffect(triggerAbility, Duration.EndOfTurn);
continuousEffect.setTargetPointer(new FixedTarget(targetObject, game));
game.addEffect(continuousEffect, source);
return true;
}
return false;
}
@Override
public RuneswordCreateTriggeredAbilityEffect copy() {
return new RuneswordCreateTriggeredAbilityEffect(this);
}
}
class RuneswordCantBeRegeneratedEffect extends ContinuousRuleModifyingEffectImpl {
private UUID targetCreatureId;
public RuneswordCantBeRegeneratedEffect() {
super(Duration.EndOfTurn, Outcome.Benefit, false, false);
this.staticText = "If the creature deals damage to a creature this turn, the creature dealt damage can't be regenerated this turn";
}
public RuneswordCantBeRegeneratedEffect(final RuneswordCantBeRegeneratedEffect effect) {
super(effect);
targetCreatureId = effect.targetCreatureId;
}
@Override
public RuneswordCantBeRegeneratedEffect copy() {
return new RuneswordCantBeRegeneratedEffect(this);
}
public void init(Ability source, Game game) {
targetCreatureId = getTargetPointer().getFirst(game, source);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == EventType.REGENERATE;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (targetCreatureId != null) {
DamagedByWatcher watcher = (DamagedByWatcher) game.getState().getWatchers().get(DamagedByWatcher.class.getSimpleName(), targetCreatureId);
if (watcher != null) {
return watcher.wasDamaged(event.getTargetId(), game);
}
}
return false;
}
}

View file

@ -28,17 +28,13 @@
package mage.cards.r;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.common.CounterTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AbilityType;
import mage.constants.CardType;
import mage.filter.FilterStackObject;
import mage.filter.predicate.Predicate;
import mage.game.Game;
import mage.game.stack.StackAbility;
import mage.target.common.TargetActivatedOrTriggeredAbility;
import mage.filter.FilterAbility;
import mage.filter.predicate.ability.ArtifactSourcePredicate;
import mage.target.common.TargetActivatedAbility;
/**
*
@ -46,7 +42,7 @@ import mage.target.common.TargetActivatedOrTriggeredAbility;
*/
public class Rust extends CardImpl {
private final static FilterStackObject filter = new FilterStackObject("activated ability from an artifact source");
private final static FilterAbility filter = new FilterAbility("activated ability from an artifact source");
static {
filter.add(new ArtifactSourcePredicate());
@ -57,7 +53,7 @@ public class Rust extends CardImpl {
// Counter target activated ability from an artifact source.
this.getSpellAbility().addEffect(new CounterTargetEffect());
this.getSpellAbility().addTarget(new TargetActivatedOrTriggeredAbility(filter));
this.getSpellAbility().addTarget(new TargetActivatedAbility(filter));
}
public Rust(final Rust card) {
@ -69,22 +65,3 @@ public class Rust extends CardImpl {
return new Rust(this);
}
}
class ArtifactSourcePredicate implements Predicate<Ability> {
public ArtifactSourcePredicate() {
}
@Override
public boolean apply(Ability input, Game game) {
if (input instanceof StackAbility) {
return input.getSourceObject(game).isArtifact() && input.getAbilityType() == AbilityType.ACTIVATED;
}
return false;
}
@Override
public String toString() {
return "Source(Artifact)";
}
}

View file

@ -0,0 +1,142 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.s;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.EchoAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.Player;
/**
*
* @author LevelX2
*/
public class ShahOfNaarIsle extends CardImpl {
public ShahOfNaarIsle(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}");
this.subtype.add(SubType.EFREET);
this.power = new MageInt(6);
this.toughness = new MageInt(6);
// Trample
this.addAbility(TrampleAbility.getInstance());
// Echo {0}
this.addAbility(new EchoAbility("{0}"));
// When Shah of Naar Isle's echo cost is paid, each opponent may draw up to three cards.
this.addAbility(new ShahOfNaarIsleTriggeredAbility());
}
public ShahOfNaarIsle(final ShahOfNaarIsle card) {
super(card);
}
@Override
public ShahOfNaarIsle copy() {
return new ShahOfNaarIsle(this);
}
}
class ShahOfNaarIsleTriggeredAbility extends TriggeredAbilityImpl {
public ShahOfNaarIsleTriggeredAbility() {
super(Zone.BATTLEFIELD, new ShahOfNaarIsleEffect(), false);
}
public ShahOfNaarIsleTriggeredAbility(final ShahOfNaarIsleTriggeredAbility effect) {
super(effect);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ECHO_PAID;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return getSourceId().equals(event.getSourceId());
}
@Override
public ShahOfNaarIsleTriggeredAbility copy() {
return new ShahOfNaarIsleTriggeredAbility(this);
}
@Override
public String getRule() {
return "When {this}'s echo cost is paid, " + super.getRule();
}
}
class ShahOfNaarIsleEffect extends OneShotEffect {
public ShahOfNaarIsleEffect() {
super(Outcome.DrawCard);
this.staticText = "each opponent may draw up to three cards";
}
public ShahOfNaarIsleEffect(final ShahOfNaarIsleEffect effect) {
super(effect);
}
@Override
public ShahOfNaarIsleEffect copy() {
return new ShahOfNaarIsleEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
for (UUID playerId : game.getOpponents(controller.getId())) {
Player opponent = game.getPlayer(playerId);
if (opponent != null) {
int number = opponent.getAmount(0, 3, "Draw how many cards?", game);
opponent.drawCards(number, game);
}
}
return true;
}
return false;
}
}

View file

@ -36,7 +36,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
@ -48,14 +48,12 @@ import mage.target.common.TargetCreatureOrPlayer;
*/
public class Soulblast extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures you control");
public Soulblast(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{R}{R}{R}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}{R}{R}");
// As an additional cost to cast Soulblast, sacrifice all creatures you control.
this.getSpellAbility().addCost(new SacrificeAllCost(filter));
this.getSpellAbility().addCost(new SacrificeAllCost(StaticFilters.FILTER_PERMANENT_CREATURES_CONTROLLED));
// Soulblast deals damage to target creature or player equal to the total power of the sacrificed creatures.
this.getSpellAbility().addEffect(new SoulblastEffect());
this.getSpellAbility().addTarget(new TargetCreatureOrPlayer());
@ -90,7 +88,7 @@ class SoulblastEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
int power = 0;
for (Cost cost :source.getCosts()) {
for (Cost cost : source.getCosts()) {
if (cost instanceof SacrificeAllCost) {
for (Permanent permanent : ((SacrificeAllCost) cost).getPermanents()) {
power += permanent.getPower().getValue();

View file

@ -76,7 +76,7 @@ class CantBeBlockedExceptByCreaturesWithFlyingOrReachEffect extends RestrictionE
public CantBeBlockedExceptByCreaturesWithFlyingOrReachEffect() {
super(Duration.WhileOnBattlefield);
staticText = "Can't be blocked except by creatures with flying or reach";
staticText = "{this} can't be blocked except by creatures with flying or reach";
}
public CantBeBlockedExceptByCreaturesWithFlyingOrReachEffect(final CantBeBlockedExceptByCreaturesWithFlyingOrReachEffect effect) {

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