mirror of
https://github.com/correl/mage.git
synced 2024-12-24 11:50:45 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
659e3d7015
27 changed files with 764 additions and 187 deletions
|
@ -27,9 +27,7 @@
|
|||
*/
|
||||
package mage.client.deckeditor.collection.viewer;
|
||||
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardDimensions;
|
||||
import mage.cards.MageCard;
|
||||
import mage.cards.*;
|
||||
import mage.cards.repository.CardCriteria;
|
||||
import mage.cards.repository.CardInfo;
|
||||
import mage.cards.repository.CardRepository;
|
||||
|
@ -38,9 +36,7 @@ import mage.client.MageFrame;
|
|||
import mage.client.cards.BigCard;
|
||||
import mage.client.components.HoverButton;
|
||||
import mage.client.plugins.impl.Plugins;
|
||||
import mage.client.util.Config;
|
||||
import mage.client.util.ImageHelper;
|
||||
import mage.client.util.NaturalOrderCardNumberComparator;
|
||||
import mage.client.util.*;
|
||||
import mage.client.util.audio.AudioManager;
|
||||
import mage.client.util.sets.ConstructedFormats;
|
||||
import mage.components.ImagePanel;
|
||||
|
@ -48,7 +44,6 @@ import mage.components.ImagePanelStyle;
|
|||
import mage.constants.Rarity;
|
||||
import mage.view.CardView;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.mage.card.arcane.GlowText;
|
||||
import org.mage.card.arcane.ManaSymbols;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
@ -59,17 +54,17 @@ import java.io.FileNotFoundException;
|
|||
import java.io.InputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import mage.client.util.CardsViewUtil;
|
||||
|
||||
import mage.game.command.Emblem;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.view.EmblemView;
|
||||
import mage.view.PermanentView;
|
||||
import org.mage.plugins.card.images.CardDownloadData;
|
||||
|
||||
import static java.lang.Math.min;
|
||||
import static org.mage.plugins.card.images.DownloadPictures.getTokenCardUrls;
|
||||
|
||||
/**
|
||||
|
@ -115,6 +110,7 @@ public class MageBook extends JComponent {
|
|||
|
||||
Image image = ImageHelper.loadImage(LEFT_PAGE_BUTTON_IMAGE_PATH);
|
||||
pageLeft = new HoverButton(null, image, image, image, new Rectangle(64, 64));
|
||||
//pageLeft.setBorder(BorderFactory.createLineBorder(new Color(180, 50, 0), 3, true)); //debug
|
||||
pageLeft.setBounds(0, 0, 64, 64);
|
||||
pageLeft.setVisible(false);
|
||||
pageLeft.setObserver(() -> {
|
||||
|
@ -146,12 +142,46 @@ public class MageBook extends JComponent {
|
|||
add(jPanelCenter, BorderLayout.CENTER);
|
||||
add(jPanelRight, BorderLayout.LINE_END);
|
||||
|
||||
cardDimensions = new CardDimensions(0.45d);
|
||||
}
|
||||
int captionHeight = Math.max(30, pageLeft.getHeight()); // caption size = next-prev images
|
||||
|
||||
private void addLeftRightPageButtons() {
|
||||
jLayeredPane.add(pageLeft, JLayeredPane.DEFAULT_LAYER, 0);
|
||||
jLayeredPane.add(pageRight, JLayeredPane.DEFAULT_LAYER, 1);
|
||||
|
||||
// Top Panel (left page + (caption / stats) + right page
|
||||
jPanelTop = new JPanel();
|
||||
jPanelTop.setLayout(new BorderLayout());
|
||||
// jPanelTop.setBorder(BorderFactory.createLineBorder(new Color(180, 50, 150), 3, true)); // debug
|
||||
jPanelTop.setPreferredSize(new Dimension(captionHeight, captionHeight));
|
||||
jPanelCenter.add(jPanelTop, BorderLayout.NORTH);
|
||||
|
||||
// page left
|
||||
pageRight.setPreferredSize(new Dimension(pageRight.getWidth(), pageRight.getHeight()));
|
||||
jPanelTop.add(pageRight, BorderLayout.EAST);
|
||||
// page right
|
||||
pageLeft.setPreferredSize(new Dimension(pageLeft.getWidth(), pageLeft.getHeight()));
|
||||
jPanelTop.add(pageLeft, BorderLayout.WEST);
|
||||
|
||||
// Caption Panel
|
||||
jPanelCaption = new JPanel();
|
||||
jPanelCaption.setLayout(new BorderLayout());
|
||||
jPanelCaption.setOpaque(false);
|
||||
jPanelTop.add(jPanelCaption, BorderLayout.CENTER);
|
||||
|
||||
// set's caption
|
||||
setCaption = new JLabel();
|
||||
setCaption.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
//setCaption.setBorder(BorderFactory.createLineBorder(new Color(180, 50, 150), 3, true)); // debug
|
||||
setCaption.setFont(jLayeredPane.getFont().deriveFont(25f));
|
||||
setCaption.setText("EMPTY CAPTION");
|
||||
jPanelCaption.add(setCaption, BorderLayout.NORTH);
|
||||
|
||||
// set's info
|
||||
setInfo = new JLabel();
|
||||
setInfo.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
//setCaption.setBorder(BorderFactory.createLineBorder(new Color(180, 50, 150), 3, true)); // debug
|
||||
setInfo.setFont(jLayeredPane.getFont().deriveFont(17f));
|
||||
setInfo.setText("EMPTY STATS");
|
||||
jPanelCaption.add(setInfo, BorderLayout.SOUTH);
|
||||
|
||||
cardDimensions = new CardDimensions(0.45d);
|
||||
}
|
||||
|
||||
private void addSetTabs() {
|
||||
|
@ -174,7 +204,7 @@ public class MageBook extends JComponent {
|
|||
if (setImage != null) {
|
||||
tab.setOverlayImage(setImage);
|
||||
} else {
|
||||
System.out.println("Couldn't find: " + "/plugins/images/sets/" + set + "-C.jpg");
|
||||
System.out.println("Couldn't find symbol image: " + "/plugins/images/sets/" + set + "-C.jpg");
|
||||
}
|
||||
tab.setSet(set);
|
||||
tab.setBounds(0, y, 39, 120);
|
||||
|
@ -217,8 +247,10 @@ public class MageBook extends JComponent {
|
|||
private void showCardsOrTokens() {
|
||||
stateChanged = false;
|
||||
if (showCardsOrTokens) {
|
||||
updateCardStats(currentSet, true);
|
||||
showCards();
|
||||
} else {
|
||||
updateCardStats(currentSet, false);
|
||||
int numTokens = showTokens();
|
||||
showEmblems(numTokens);
|
||||
}
|
||||
|
@ -226,14 +258,16 @@ public class MageBook extends JComponent {
|
|||
|
||||
public void showCards() {
|
||||
jLayeredPane.removeAll();
|
||||
addLeftRightPageButtons();
|
||||
|
||||
// stats info
|
||||
updateCardStats(currentSet, true);
|
||||
|
||||
List<CardInfo> cards = getCards(currentPage, currentSet);
|
||||
int size = cards.size();
|
||||
|
||||
Rectangle rectangle = new Rectangle();
|
||||
rectangle.translate(OFFSET_X, OFFSET_Y);
|
||||
for (int i = 0; i < Math.min(conf.CARDS_PER_PAGE / 2, size); i++) {
|
||||
for (int i = 0; i < min(conf.CARDS_PER_PAGE / 2, size); i++) {
|
||||
Card card = cards.get(i).getMockCard();
|
||||
addCard(new CardView(card), bigCard, null, rectangle);
|
||||
|
||||
|
@ -245,7 +279,7 @@ public class MageBook extends JComponent {
|
|||
- (cardDimensions.frameWidth + CardPosition.GAP_X) * conf.CARD_COLUMNS + CardPosition.GAP_X - OFFSET_X;
|
||||
|
||||
rectangle.setLocation(second_page_x, OFFSET_Y);
|
||||
for (int i = conf.CARDS_PER_PAGE / 2; i < Math.min(conf.CARDS_PER_PAGE, size); i++) {
|
||||
for (int i = conf.CARDS_PER_PAGE / 2; i < min(conf.CARDS_PER_PAGE, size); i++) {
|
||||
Card card = cards.get(i).getMockCard();
|
||||
addCard(new CardView(card), bigCard, null, rectangle);
|
||||
rectangle = CardPosition.translatePosition(i - conf.CARDS_PER_PAGE / 2, rectangle, conf);
|
||||
|
@ -256,7 +290,6 @@ public class MageBook extends JComponent {
|
|||
|
||||
public int showTokens() {
|
||||
jLayeredPane.removeAll();
|
||||
addLeftRightPageButtons();
|
||||
|
||||
List<Token> tokens = getTokens(currentPage, currentSet);
|
||||
int size = tokens.size();
|
||||
|
@ -264,7 +297,7 @@ public class MageBook extends JComponent {
|
|||
if (tokens != null && tokens.size() > 0) {
|
||||
Rectangle rectangle = new Rectangle();
|
||||
rectangle.translate(OFFSET_X, OFFSET_Y);
|
||||
for (int i = 0; i < Math.min(conf.CARDS_PER_PAGE / 2, size); i++) {
|
||||
for (int i = 0; i < min(conf.CARDS_PER_PAGE / 2, size); i++) {
|
||||
Token token = tokens.get(i);
|
||||
addToken(token, bigCard, null, rectangle);
|
||||
rectangle = CardPosition.translatePosition(i, rectangle, conf);
|
||||
|
@ -275,7 +308,7 @@ public class MageBook extends JComponent {
|
|||
- (cardDimensions.frameWidth + CardPosition.GAP_X) * conf.CARD_COLUMNS + CardPosition.GAP_X - OFFSET_X;
|
||||
|
||||
rectangle.setLocation(second_page_x, OFFSET_Y);
|
||||
for (int i = conf.CARDS_PER_PAGE / 2; i < Math.min(conf.CARDS_PER_PAGE, size); i++) {
|
||||
for (int i = conf.CARDS_PER_PAGE / 2; i < min(conf.CARDS_PER_PAGE, size); i++) {
|
||||
Token token = tokens.get(i);
|
||||
addToken(token, bigCard, null, rectangle);
|
||||
rectangle = CardPosition.translatePosition(i - conf.CARDS_PER_PAGE / 2, rectangle, conf);
|
||||
|
@ -346,12 +379,26 @@ public class MageBook extends JComponent {
|
|||
|
||||
boolean implemented = card.getRarity() != Rarity.NA;
|
||||
|
||||
// implemented label
|
||||
// old code, nowadays app load only implemented cards (JayDi85, 23.11.2017)
|
||||
/*
|
||||
GlowText label = new GlowText();
|
||||
label.setGlow(implemented ? Color.green : NOT_IMPLEMENTED, 12, 0.0f);
|
||||
label.setText(implemented ? "Implemented" : "Not implemented");
|
||||
int dx = implemented ? 15 : 5;
|
||||
label.setBounds(rectangle.x + dx, rectangle.y + cardDimensions.frameHeight + 7, 110, 30);
|
||||
jLayeredPane.add(label);
|
||||
*/
|
||||
|
||||
// card number label
|
||||
JLabel cardNumber = new JLabel();
|
||||
int dy = -5; // image panel have empty space in bottom (bug?), need to move label up
|
||||
cardNumber.setBounds(rectangle.x, rectangle.y + cardImg.getHeight() + dy, cardDimensions.frameWidth, 20);
|
||||
cardNumber.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
//cardNumber.setBorder(BorderFactory.createLineBorder(new Color(180, 50, 150), 3, true));
|
||||
cardNumber.setFont(jLayeredPane.getFont().deriveFont(jLayeredPane.getFont().getStyle() | Font.BOLD));
|
||||
cardNumber.setText(card.getCardNumber());
|
||||
jLayeredPane.add(cardNumber);
|
||||
}
|
||||
|
||||
private void addToken(Token token, BigCard bigCard, UUID gameId, Rectangle rectangle) {
|
||||
|
@ -389,6 +436,60 @@ public class MageBook extends JComponent {
|
|||
return cards.subList(start, end);
|
||||
}
|
||||
|
||||
private void updateCardStats(String setCode, boolean isCardsShow){
|
||||
// sets do not have total cards number, it's a workaround
|
||||
|
||||
ExpansionSet set = Sets.findSet(setCode);
|
||||
if (set != null){
|
||||
setCaption.setText(set.getCode() + " - " + set.getName());
|
||||
}else{
|
||||
setCaption.setText("ERROR");
|
||||
setInfo.setText("ERROR");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isCardsShow){
|
||||
// tokens or emblems, stats not need
|
||||
setInfo.setText("");
|
||||
return;
|
||||
}
|
||||
|
||||
// cards stats
|
||||
|
||||
int startNumber = 9999;
|
||||
int endNumber = 0;
|
||||
|
||||
List<ExpansionSet.SetCardInfo> cards = set.getSetCardInfo();
|
||||
|
||||
// first run for numbers list
|
||||
LinkedList<Integer> haveNumbers = new LinkedList<>();
|
||||
for (ExpansionSet.SetCardInfo card: cards){
|
||||
int cardNumber = Integer.parseInt(card.getCardNumber());
|
||||
startNumber = min(startNumber, cardNumber);
|
||||
endNumber = Math.max(endNumber, cardNumber);
|
||||
haveNumbers.add(cardNumber);
|
||||
}
|
||||
|
||||
// second run for empty numbers
|
||||
int countHave = haveNumbers.size();
|
||||
int countNotHave = 0;
|
||||
if (cards.size() > 0){
|
||||
for(int i = startNumber; i <= endNumber; i++){
|
||||
if(!haveNumbers.contains(i)){
|
||||
countNotHave++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// result
|
||||
setInfo.setText(String.format("Have %d cards of %d", countHave, countHave + countNotHave));
|
||||
if (countNotHave > 0) {
|
||||
setInfo.setForeground(new Color(150, 0, 0));
|
||||
}else{
|
||||
setInfo.setForeground(jLayeredPane.getForeground());
|
||||
}
|
||||
}
|
||||
|
||||
private List<Token> getTokens(int page, String set) {
|
||||
ArrayList<CardDownloadData> allTokens = getTokenCardUrls();
|
||||
ArrayList<Token> tokens = new ArrayList<>();
|
||||
|
@ -576,7 +677,6 @@ public class MageBook extends JComponent {
|
|||
setSize(conf.WIDTH, conf.HEIGHT);
|
||||
setPreferredSize(new Dimension(conf.WIDTH, conf.HEIGHT));
|
||||
setMinimumSize(new Dimension(conf.WIDTH, conf.HEIGHT));
|
||||
pageRight.setBounds(conf.WIDTH - 2 * LEFT_RIGHT_PAGES_WIDTH - 64, 0, 64, 64);
|
||||
addSetTabs();
|
||||
showCards();
|
||||
}
|
||||
|
@ -616,7 +716,7 @@ public class MageBook extends JComponent {
|
|||
|
||||
_3x3Configuration() {
|
||||
this.WIDTH = 950;
|
||||
this.HEIGHT = 650;
|
||||
this.HEIGHT = 650 + 50; // + for caption
|
||||
CARD_ROWS = 3;
|
||||
CARD_COLUMNS = 3;
|
||||
this.CARDS_PER_PAGE = 18;
|
||||
|
@ -629,7 +729,7 @@ public class MageBook extends JComponent {
|
|||
|
||||
_4x4Configuration() {
|
||||
this.WIDTH = 1250;
|
||||
this.HEIGHT = 850;
|
||||
this.HEIGHT = 850 + 50; // + for caption
|
||||
CARD_ROWS = 4;
|
||||
CARD_COLUMNS = 4;
|
||||
this.CARDS_PER_PAGE = 32;
|
||||
|
@ -638,6 +738,10 @@ public class MageBook extends JComponent {
|
|||
}
|
||||
}
|
||||
|
||||
private JPanel jPanelTop;
|
||||
private JPanel jPanelCaption;
|
||||
private JLabel setCaption;
|
||||
private JLabel setInfo;
|
||||
private JPanel jPanelLeft;
|
||||
private ImagePanel jPanelCenter;
|
||||
private JPanel jPanelRight;
|
||||
|
@ -648,6 +752,8 @@ public class MageBook extends JComponent {
|
|||
|
||||
private int currentPage = 0;
|
||||
private String currentSet = "RTR";
|
||||
private int currentCardsInSet = 0;
|
||||
private int currentCardsNotInSet = 0;
|
||||
|
||||
private static CardDimensions cardDimensions = new CardDimensions(1.2d);
|
||||
private static final Logger log = Logger.getLogger(MageBook.class);
|
||||
|
|
|
@ -560,7 +560,7 @@ public class TablesPanel extends javax.swing.JPanel {
|
|||
formatFilterList.add(RowFilter.regexFilter("^Constructed - Vintage", TableTableModel.COLUMN_DECK_TYPE));
|
||||
}
|
||||
if (btnFormatCommander.isSelected()) {
|
||||
formatFilterList.add(RowFilter.regexFilter("^Commander|^Duel Commander|^Penny Dreadful Commander", TableTableModel.COLUMN_DECK_TYPE));
|
||||
formatFilterList.add(RowFilter.regexFilter("^Commander|^Duel Commander|^Penny Dreadful Commander|^Freeform Commander", TableTableModel.COLUMN_DECK_TYPE));
|
||||
}
|
||||
if (btnFormatTinyLeader.isSelected()) {
|
||||
formatFilterList.add(RowFilter.regexFilter("^Tiny", TableTableModel.COLUMN_DECK_TYPE));
|
||||
|
|
|
@ -16,8 +16,8 @@ import java.util.regex.Pattern;
|
|||
|
||||
/**
|
||||
* @author stravant@gmail.com
|
||||
* <p>
|
||||
* Various static utilities for use in the card renderer
|
||||
* <p>
|
||||
* Various static utilities for use in the card renderer
|
||||
*/
|
||||
public final class CardRendererUtils {
|
||||
|
||||
|
@ -51,6 +51,38 @@ public final class CardRendererUtils {
|
|||
// Return the buffered image
|
||||
return bimage;
|
||||
}
|
||||
|
||||
private static Color abitbrighter(Color c) {
|
||||
int r = c.getRed();
|
||||
int g = c.getGreen();
|
||||
int b = c.getBlue();
|
||||
int alpha = c.getAlpha();
|
||||
|
||||
int plus_r = (int) ((255 - r) / 2);
|
||||
int plus_g = (int) ((255 - g) / 2);
|
||||
int plus_b = (int) ((255 - b) / 2);
|
||||
|
||||
return new Color(r + plus_r,
|
||||
g + plus_g,
|
||||
b + plus_b,
|
||||
alpha);
|
||||
}
|
||||
|
||||
private static Color abitdarker(Color c) {
|
||||
int r = c.getRed();
|
||||
int g = c.getGreen();
|
||||
int b = c.getBlue();
|
||||
int alpha = c.getAlpha();
|
||||
|
||||
int plus_r = (int) (Math.min (255 - r, r) / 2);
|
||||
int plus_g = (int) (Math.min (255 - g, g) / 2);
|
||||
int plus_b = (int) (Math.min (255 - b, b) / 2);
|
||||
|
||||
return new Color(r - plus_r,
|
||||
g - plus_g,
|
||||
b - plus_b,
|
||||
alpha);
|
||||
}
|
||||
|
||||
// Draw a rounded box with a 2-pixel border
|
||||
// Used on various card parts.
|
||||
|
@ -68,6 +100,12 @@ public final class CardRendererUtils {
|
|||
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.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);
|
||||
}
|
||||
|
||||
// Get the width of a mana cost rendered with ManaSymbols.draw
|
||||
|
|
|
@ -106,7 +106,7 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
public static final Color BORDER_RED = new Color(201, 71, 58);
|
||||
public static final Color BORDER_GREEN = new Color(4, 136, 69);
|
||||
public static final Color BORDER_GOLD = new Color(255, 228, 124);
|
||||
public static final Color BORDER_COLORLESS = new Color(238, 242, 242);
|
||||
public static final Color BORDER_COLORLESS = new Color(208, 212, 212);
|
||||
public static final Color BORDER_LAND = new Color(190, 173, 115);
|
||||
|
||||
public static final Color BOX_WHITE = new Color(244, 245, 239);
|
||||
|
@ -115,7 +115,7 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
public static final Color BOX_RED = new Color(246, 208, 185);
|
||||
public static final Color BOX_GREEN = new Color(205, 221, 213);
|
||||
public static final Color BOX_GOLD = new Color(223, 195, 136);
|
||||
public static final Color BOX_COLORLESS = new Color(220, 228, 232);
|
||||
public static final Color BOX_COLORLESS = new Color(200, 208, 212);
|
||||
public static final Color BOX_LAND = new Color(220, 215, 213);
|
||||
public static final Color BOX_INVENTION = new Color(209, 97, 33);
|
||||
public static final Color BOX_VEHICLE = new Color(155, 105, 60);
|
||||
|
@ -128,21 +128,21 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
public static final Color BOX_GOLD_NIGHT = new Color(171, 134, 70);
|
||||
public static final Color BOX_COLORLESS_NIGHT = new Color(118, 147, 158);
|
||||
|
||||
public static final Color LAND_TEXTBOX_WHITE = new Color(248, 232, 188, 244);
|
||||
public static final Color LAND_TEXTBOX_BLUE = new Color(189, 212, 236, 244);
|
||||
public static final Color LAND_TEXTBOX_BLACK = new Color(174, 164, 162, 244);
|
||||
public static final Color LAND_TEXTBOX_RED = new Color(242, 168, 133, 244);
|
||||
public static final Color LAND_TEXTBOX_GREEN = new Color(198, 220, 198, 244);
|
||||
public static final Color LAND_TEXTBOX_GOLD = new Color(236, 229, 207, 244);
|
||||
public static final Color LAND_TEXTBOX_WHITE = new Color(248, 232, 188, 234);
|
||||
public static final Color LAND_TEXTBOX_BLUE = new Color(189, 212, 236, 234);
|
||||
public static final Color LAND_TEXTBOX_BLACK = new Color(174, 164, 162, 234);
|
||||
public static final Color LAND_TEXTBOX_RED = new Color(242, 168, 133, 234);
|
||||
public static final Color LAND_TEXTBOX_GREEN = new Color(198, 220, 198, 234);
|
||||
public static final Color LAND_TEXTBOX_GOLD = new Color(236, 229, 207, 234);
|
||||
|
||||
public static final Color TEXTBOX_WHITE = new Color(252, 249, 244, 244);
|
||||
public static final Color TEXTBOX_BLUE = new Color(229, 238, 247, 244);
|
||||
public static final Color TEXTBOX_BLACK = new Color(241, 241, 240, 244);
|
||||
public static final Color TEXTBOX_RED = new Color(243, 224, 217, 244);
|
||||
public static final Color TEXTBOX_GREEN = new Color(217, 232, 223, 244);
|
||||
public static final Color TEXTBOX_GOLD = new Color(240, 234, 209, 244);
|
||||
public static final Color TEXTBOX_COLORLESS = new Color(219, 229, 233, 244);
|
||||
public static final Color TEXTBOX_LAND = new Color(218, 214, 212, 244);
|
||||
public static final Color TEXTBOX_WHITE = new Color(252, 249, 244, 234);
|
||||
public static final Color TEXTBOX_BLUE = new Color(229, 238, 247, 234);
|
||||
public static final Color TEXTBOX_BLACK = new Color(241, 241, 240, 234);
|
||||
public static final Color TEXTBOX_RED = new Color(243, 224, 217, 234);
|
||||
public static final Color TEXTBOX_GREEN = new Color(217, 232, 223, 234);
|
||||
public static final Color TEXTBOX_GOLD = new Color(240, 234, 209, 234);
|
||||
public static final Color TEXTBOX_COLORLESS = new Color(199, 209, 213, 234);
|
||||
public static final Color TEXTBOX_LAND = new Color(218, 214, 212, 234);
|
||||
|
||||
public static final Color ERROR_COLOR = new Color(255, 0, 255);
|
||||
|
||||
|
|
|
@ -124,7 +124,6 @@ public final class ImageCache {
|
|||
if (exists) {
|
||||
LOGGER.debug("loading thumbnail for " + key + ", path=" + thumbnailPath);
|
||||
BufferedImage thumbnailImage = loadImage(thumbnailFile);
|
||||
|
||||
if (thumbnailImage == null) { // thumbnail exists but broken for some reason
|
||||
LOGGER.warn("failed loading thumbnail for " + key + ", path=" + thumbnailPath
|
||||
+ ", thumbnail file is probably broken, attempting to recreate it...");
|
||||
|
@ -361,6 +360,23 @@ public final class ImageCache {
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean isFaceImagePresent(CardView card) {
|
||||
String path;
|
||||
path = CardImageUtils.generateFaceImagePath(card.getName(), card.getExpansionSetCode());
|
||||
|
||||
if (path == null) {
|
||||
return false;
|
||||
}
|
||||
TFile file = getTFile(path);
|
||||
if (file == null) {
|
||||
return false;
|
||||
}
|
||||
if (file.exists()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static BufferedImage getThumbnail(CardView card) {
|
||||
return getImage(getKey(card, card.getName(), "#thumb"));
|
||||
}
|
||||
|
@ -464,7 +480,6 @@ public final class ImageCache {
|
|||
// return alternateName + "#" + card.getExpansionSetCode() + "#" +card.getType()+ "#" + card.getCardNumber() + "#"
|
||||
// + (card.getTokenSetCode() == null ? "":card.getTokenSetCode());
|
||||
// }
|
||||
|
||||
/**
|
||||
* Load image from file
|
||||
*
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.deck;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import mage.abilities.common.CanBeYourCommanderAbility;
|
||||
import mage.abilities.keyword.PartnerAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.ExpansionSet;
|
||||
import mage.cards.Sets;
|
||||
import mage.cards.decks.Constructed;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.constants.SetType;
|
||||
import mage.filter.FilterMana;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author spjspj
|
||||
*/
|
||||
public class FreeformCommander extends Constructed {
|
||||
|
||||
protected List<String> bannedCommander = new ArrayList<>();
|
||||
private static final Map<String, Integer> pdAllowed = new HashMap<>();
|
||||
private static boolean setupAllowed = false;
|
||||
|
||||
public FreeformCommander() {
|
||||
this("Freeform Commander");
|
||||
for (ExpansionSet set : Sets.getInstance().values()) {
|
||||
setCodes.add(set.getCode());
|
||||
}
|
||||
}
|
||||
|
||||
public FreeformCommander(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(Deck deck) {
|
||||
boolean valid = true;
|
||||
FilterMana colorIdentity = new FilterMana();
|
||||
|
||||
if (deck.getCards().size() + deck.getSideboard().size() != 100) {
|
||||
invalid.put("Deck", "Must contain 100 cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
List<String> basicLandNames = new ArrayList<>(Arrays.asList("Forest", "Island", "Mountain", "Swamp", "Plains", "Wastes"));
|
||||
Map<String, Integer> counts = new HashMap<>();
|
||||
countCards(counts, deck.getCards());
|
||||
countCards(counts, deck.getSideboard());
|
||||
|
||||
for (Map.Entry<String, Integer> entry : counts.entrySet()) {
|
||||
if (entry.getValue() > 1) {
|
||||
if (!basicLandNames.contains(entry.getKey())) {
|
||||
invalid.put(entry.getKey(), "Too many: " + entry.getValue());
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generateFreeformHash();
|
||||
|
||||
if (deck.getSideboard().size() < 1 || deck.getSideboard().size() > 2) {
|
||||
invalid.put("Commander", "Sideboard must contain only the commander(s)");
|
||||
valid = false;
|
||||
} else {
|
||||
for (Card commander : deck.getSideboard()) {
|
||||
if (!(commander.isCreature() ||
|
||||
commander.isLegendary())) {
|
||||
invalid.put("Commander", "For Freeform Commander, the commander must be a creature or be legendary. Yours was: " + commander.getName());
|
||||
valid = false;
|
||||
}
|
||||
if (deck.getSideboard().size() == 2 && !commander.getAbilities().contains(PartnerAbility.getInstance())) {
|
||||
invalid.put("Commander", "Commander without Partner (" + commander.getName() + ')');
|
||||
valid = false;
|
||||
}
|
||||
FilterMana commanderColor = commander.getColorIdentity();
|
||||
if (commanderColor.isWhite()) {
|
||||
colorIdentity.setWhite(true);
|
||||
}
|
||||
if (commanderColor.isBlue()) {
|
||||
colorIdentity.setBlue(true);
|
||||
}
|
||||
if (commanderColor.isBlack()) {
|
||||
colorIdentity.setBlack(true);
|
||||
}
|
||||
if (commanderColor.isRed()) {
|
||||
colorIdentity.setRed(true);
|
||||
}
|
||||
if (commanderColor.isGreen()) {
|
||||
colorIdentity.setGreen(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Card card : deck.getCards()) {
|
||||
if (!cardHasValidColor(colorIdentity, card)) {
|
||||
invalid.put(card.getName(), "Invalid color (" + colorIdentity.toString() + ')');
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (Card card : deck.getSideboard()) {
|
||||
if (!isSetAllowed(card.getExpansionSetCode())) {
|
||||
if (!legalSets(card)) {
|
||||
invalid.put(card.getName(), "Not allowed Set: " + card.getExpansionSetCode());
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
public boolean cardHasValidColor(FilterMana commander, Card card) {
|
||||
FilterMana cardColor = card.getColorIdentity();
|
||||
return !(cardColor.isBlack() && !commander.isBlack()
|
||||
|| cardColor.isBlue() && !commander.isBlue()
|
||||
|| cardColor.isGreen() && !commander.isGreen()
|
||||
|| cardColor.isRed() && !commander.isRed()
|
||||
|| cardColor.isWhite() && !commander.isWhite());
|
||||
}
|
||||
|
||||
public void generateFreeformHash() {
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.26</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-game-freeformcommanderfreeforall</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Mage Game Freeform Commander Free For All</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>mage</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>src</sourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<configuration>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
|
||||
<finalName>mage-game-freeforall</finalName>
|
||||
</build>
|
||||
|
||||
<properties/>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.game;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.constants.MultiplayerAttackOption;
|
||||
import mage.constants.RangeOfInfluence;
|
||||
import mage.game.match.MatchType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author spjspj
|
||||
*/
|
||||
public class FreeformCommanderFreeForAll extends GameCommanderImpl {
|
||||
|
||||
private int numPlayers;
|
||||
|
||||
public FreeformCommanderFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) {
|
||||
super(attackOption, range, freeMulligans, startLife);
|
||||
}
|
||||
|
||||
public FreeformCommanderFreeForAll(final FreeformCommanderFreeForAll game) {
|
||||
super(game);
|
||||
this.numPlayers = game.numPlayers;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(UUID choosingPlayerId) {
|
||||
startingPlayerSkipsDraw = false;
|
||||
super.init(choosingPlayerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MatchType getGameType() {
|
||||
return new FreeformCommanderFreeForAllType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumPlayers() {
|
||||
return numPlayers;
|
||||
}
|
||||
|
||||
public void setNumPlayers(int numPlayers) {
|
||||
this.numPlayers = numPlayers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FreeformCommanderFreeForAll copy() {
|
||||
return new FreeformCommanderFreeForAll(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.game;
|
||||
|
||||
import mage.game.match.MatchImpl;
|
||||
import mage.game.match.MatchOptions;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author spjspj
|
||||
*/
|
||||
public class FreeformCommanderFreeForAllMatch extends MatchImpl {
|
||||
|
||||
public FreeformCommanderFreeForAllMatch(MatchOptions options) {
|
||||
super(options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startGame() throws GameException {
|
||||
int startLife = 40;
|
||||
boolean alsoHand = true;
|
||||
FreeformCommanderFreeForAll game = new FreeformCommanderFreeForAll(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), startLife);
|
||||
game.setStartMessage(this.createGameStartMessage());
|
||||
game.setAlsoHand(alsoHand);
|
||||
game.setAlsoLibrary(true);
|
||||
initGame(game);
|
||||
games.add(game);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.game;
|
||||
|
||||
import mage.game.match.MatchType;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author spjspj
|
||||
*/
|
||||
public class FreeformCommanderFreeForAllType extends MatchType {
|
||||
|
||||
public FreeformCommanderFreeForAllType() {
|
||||
this.name = "Freeform Commander Free For All";
|
||||
this.maxPlayers = 10;
|
||||
this.minPlayers = 3;
|
||||
this.numTeams = 0;
|
||||
this.useAttackOption = true;
|
||||
this.useRange = true;
|
||||
this.sideboardingAllowed = false;
|
||||
}
|
||||
|
||||
protected FreeformCommanderFreeForAllType(final FreeformCommanderFreeForAllType matchType) {
|
||||
super(matchType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FreeformCommanderFreeForAllType copy() {
|
||||
return new FreeformCommanderFreeForAllType(this);
|
||||
}
|
||||
}
|
|
@ -2250,7 +2250,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
* @return
|
||||
*/
|
||||
private UUID getRandomOpponent(UUID abilityControllerId, Game game) {
|
||||
UUID randomOpponentId = game.getOpponents(abilityControllerId).iterator().next();
|
||||
UUID randomOpponentId = null;
|
||||
Set<UUID> opponents = game.getOpponents(abilityControllerId);
|
||||
if (opponents.size() > 1) {
|
||||
int rand = RandomUtil.nextInt(opponents.size());
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
<module>Mage.Game.TinyLeadersDuel</module>
|
||||
<module>Mage.Game.CanadianHighlanderDuel</module>
|
||||
<module>Mage.Game.PennyDreadfulCommanderFreeForAll</module>
|
||||
<module>Mage.Game.FreeformCommanderFreeForAll</module>
|
||||
<module>Mage.Game.TwoPlayerDuel</module>
|
||||
<module>Mage.Player.AI</module>
|
||||
<module>Mage.Player.AIMinimax</module>
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
<gameType name="Tiny Leaders Two Player Duel" jar="mage-game-tinyleadersduel.jar" className="mage.game.TinyLeadersDuelMatch" typeName="mage.game.TinyLeadersDuelType"/>
|
||||
<gameType name="Canadian Highlander Two Player Duel" jar="mage-game-canadianhighlanderduel.jar" className="mage.game.CanadianHighlanderDuelMatch" typeName="mage.game.CanadianHighlanderDuelType"/>
|
||||
<gameType name="Penny Dreadful Commander Free For All" jar="mage-game-pennydreadfulcommanderfreeforall.jar" className="mage.game.PennyDreadfulCommanderFreeForAllMatch" typeName="mage.game.PennyDreadfulCommanderFreeForAllType"/>
|
||||
<gameType name="Freeform Commander Free For All" jar="mage-game-freeformcommanderfreeforall.jar" className="mage.game.FreeformCommanderFreeForAllMatch" typeName="mage.game.FreeformCommanderFreeForAllType"/>
|
||||
<gameType name="Momir Basic Two Player Duel" jar="mage-game-momirduel.jar" className="mage.game.MomirDuelMatch" typeName="mage.game.MomirDuelType"/>
|
||||
<gameType name="Momir Basic Free For All" jar="mage-game-momir.jar" className="mage.game.MomirFreeForAllMatch" typeName="mage.game.MomirFreeForAllType"/>
|
||||
</gameTypes>
|
||||
|
@ -151,6 +152,7 @@
|
|||
<deckType name="Variant Magic - Tiny Leaders" jar="mage-deck-constructed.jar" className="mage.deck.TinyLeaders"/>
|
||||
<deckType name="Variant Magic - Momir Basic" jar="mage-deck-constructed.jar" className="mage.deck.Momir"/>
|
||||
<deckType name="Variant Magic - Penny Dreadful Commander" jar="mage-deck-constructed.jar" className="mage.deck.PennyDreadfulCommander"/>
|
||||
<deckType name="Variant Magic - Freeform Commander" jar="mage-deck-constructed.jar" className="mage.deck.FreeformCommander"/>
|
||||
<deckType name="Block Constructed - Amonkhet" jar="mage-deck-constructed.jar" className="mage.deck.AmonkhetBlock"/>
|
||||
<deckType name="Block Constructed - Battle for Zendikar" jar="mage-deck-constructed.jar" className="mage.deck.BattleForZendikarBlock"/>
|
||||
<deckType name="Block Constructed - Innistrad" jar="mage-deck-constructed.jar" className="mage.deck.InnistradBlock"/>
|
||||
|
|
|
@ -154,6 +154,13 @@
|
|||
<version>${project.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>mage-game-freeformcommanderfreeforall</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>mage-game-momirduel</artifactId>
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
<gameType name="Tiny Leaders Two Player Duel" jar="mage-game-tinyleadersduel-${project.version}.jar" className="mage.game.TinyLeadersDuelMatch" typeName="mage.game.TinyLeadersDuelType"/>
|
||||
<gameType name="Canadian Highlander Two Player Duel" jar="mage-game-canadianhighlanderduel-${project.version}.jar" className="mage.game.CanadianHighlanderDuelMatch" typeName="mage.game.CanadianHighlanderDuelType"/>
|
||||
<gameType name="Penny Dreadful Commander Free For All" jar="mage-game-pennydreadfulcommanderfreeforall-${project.version}.jar" className="mage.game.PennyDreadfulCommanderFreeForAllMatch" typeName="mage.game.PennyDreadfulCommanderFreeForAllType"/>
|
||||
<gameType name="Freeform Commander Free For All" jar="mage-game-freeformcommanderfreeforall-${project.version}.jar" className="mage.game.FreeformCommanderFreeForAllMatch" typeName="mage.game.FreeformCommanderFreeForAllType"/>
|
||||
<gameType name="Momir Basic Two Player Duel" jar="mage-game-momirduel-${project.version}.jar" className="mage.game.MomirDuelMatch" typeName="mage.game.MomirDuelType"/>
|
||||
</gameTypes>
|
||||
<tournamentTypes>
|
||||
|
@ -147,6 +148,7 @@
|
|||
<deckType name="Variant Magic - Tiny Leaders" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.TinyLeaders"/>
|
||||
<deckType name="Variant Magic - Momir Basic" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.Momir"/>
|
||||
<deckType name="Variant Magic - Penny Dreadful Commander" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.PennyDreadfulCommander"/>
|
||||
<deckType name="Variant Magic - Freeform Commander" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.FreeformCommander"/>
|
||||
<deckType name="Block Constructed - Amonkhet" jar="mage-deck-constructed.jar" className="mage.deck.AmonkhetBlock"/>
|
||||
<deckType name="Block Constructed - Battle for Zendikar" jar="mage-deck-constructed.jar" className="mage.deck.BattleForZendikarBlock"/>
|
||||
<deckType name="Block Constructed - Innistrad" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.InnistradBlock"/>
|
||||
|
|
|
@ -40,6 +40,7 @@ import mage.cards.CardSetInfo;
|
|||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.TargetAdjustment;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.StaticFilters;
|
||||
|
@ -65,6 +66,7 @@ public class AlexiZephyrMage extends CardImpl {
|
|||
ability.addCost(new TapSourceCost());
|
||||
ability.addCost(new DiscardTargetCost(new TargetCardInHand(2, new FilterCard("two cards"))));
|
||||
ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURES));
|
||||
ability.setTargetAdjustment(TargetAdjustment.X_TARGETS);
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@ class CurtainOfLightEffect extends OneShotEffect {
|
|||
CombatGroup combatGroup = game.getCombat().findGroup(permanent.getId());
|
||||
if (combatGroup != null) {
|
||||
combatGroup.setBlocked(true);
|
||||
game.informPlayers(permanent.getLogName() + " has become blocked");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,6 +110,7 @@ class DazzlingBeautyEffect extends OneShotEffect {
|
|||
CombatGroup combatGroup = game.getCombat().findGroup(permanent.getId());
|
||||
if (combatGroup != null) {
|
||||
combatGroup.setBlocked(true);
|
||||
game.informPlayers(permanent.getLogName() + " has become blocked");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,34 +34,41 @@ import mage.abilities.common.SimpleActivatedAbility;
|
|||
import mage.abilities.costs.common.DiscardCardCost;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.continuous.BecomesBasicLandTargetEffect;
|
||||
import mage.constants.SubType;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.TargetAdjustment;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.Target;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author L_J
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class DeepwoodElder extends CardImpl {
|
||||
|
||||
public DeepwoodElder(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}{G}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{G}");
|
||||
|
||||
this.subtype.add(SubType.DRYAD);
|
||||
this.subtype.add(SubType.SPELLSHAPER);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(2);
|
||||
|
||||
// {X}{G}{G}, {T}, Discard a card: X target lands become Forests until end of turn.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesBasicLandTargetEffect(Duration.EndOfTurn, SubType.FOREST).setText("X target lands become Forests until end of turn"), new ManaCostsImpl("{X}{G}{G}"));
|
||||
// {X}{G}{G}, {tap}, Discard a card: X target lands become Forests until end of turn.
|
||||
Ability ability = new SimpleActivatedAbility(new DeepwoodElderEffect(), new ManaCostsImpl("{X}{G}{G}"));
|
||||
ability.addCost(new TapSourceCost());
|
||||
ability.addCost(new DiscardCardCost());
|
||||
ability.addCost(new DiscardCardCost());
|
||||
ability.addTarget(new TargetPermanent(StaticFilters.FILTER_LANDS));
|
||||
ability.setTargetAdjustment(TargetAdjustment.X_TARGETS);
|
||||
this.addAbility(ability);
|
||||
|
@ -76,3 +83,35 @@ public class DeepwoodElder extends CardImpl {
|
|||
return new DeepwoodElder(this);
|
||||
}
|
||||
}
|
||||
|
||||
class DeepwoodElderEffect extends OneShotEffect {
|
||||
|
||||
DeepwoodElderEffect() {
|
||||
super(Outcome.LoseAbility);
|
||||
this.staticText = "X target lands become Forests until end of turn";
|
||||
}
|
||||
|
||||
DeepwoodElderEffect(final DeepwoodElderEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeepwoodElderEffect copy() {
|
||||
return new DeepwoodElderEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
for (Target target : source.getTargets()) {
|
||||
for (UUID targetId : target.getTargets()) {
|
||||
Permanent permanent = game.getPermanent(targetId);
|
||||
if (permanent != null) {
|
||||
ContinuousEffect effect = new BecomesBasicLandTargetEffect(Duration.EndOfTurn, SubType.FOREST);
|
||||
effect.setTargetPointer(new FixedTarget(permanent, game));
|
||||
game.addEffect(effect, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import mage.cards.CardSetInfo;
|
|||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.target.TargetPlayer;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -54,6 +55,7 @@ public class OrcishSpy extends CardImpl {
|
|||
|
||||
// {T}: Look at the top three cards of target player's library.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LookLibraryTopCardTargetPlayerEffect(3), new TapSourceCost());
|
||||
ability.addTarget(new TargetPlayer());
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,26 +30,20 @@ package mage.cards.s;
|
|||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.common.RemoveVariableCountersSourceCost;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
|
||||
import mage.abilities.keyword.EvolveAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.TargetAdjustment;
|
||||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
/**
|
||||
|
@ -69,7 +63,7 @@ public class SimicManipulator extends CardImpl {
|
|||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with power less than or equal to the number of +1/+1 counters removed this way");
|
||||
|
||||
public SimicManipulator(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{U}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{U}");
|
||||
this.subtype.add(SubType.MUTANT);
|
||||
this.subtype.add(SubType.WIZARD);
|
||||
|
||||
|
@ -80,11 +74,10 @@ public class SimicManipulator extends CardImpl {
|
|||
this.addAbility(new EvolveAbility());
|
||||
|
||||
// {T}, Remove one or more +1/+1 counters from Simic Manipulator: Gain control of target creature with power less than or equal to the number of +1/+1 counters removed this way.
|
||||
// TODO: Improve targeting, that only valid targets (power <= removed counters) can be choosen
|
||||
// Disadvantage now is, that a creature can be targeted that couldn't be targeted by rules.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SimicManipulatorGainControlTargetEffect(Duration.Custom), new TapSourceCost());
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainControlTargetEffect(Duration.Custom, true), new TapSourceCost());
|
||||
ability.addTarget(new TargetCreaturePermanent(filter));
|
||||
ability.addCost(new RemoveVariableCountersSourceCost(CounterType.P1P1.createInstance(), 1, "Remove one or more +1/+1 counters from {this}"));
|
||||
ability.setTargetAdjustment(TargetAdjustment.SIMIC_MANIPULATOR);
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
|
@ -97,53 +90,3 @@ public class SimicManipulator extends CardImpl {
|
|||
return new SimicManipulator(this);
|
||||
}
|
||||
}
|
||||
|
||||
class SimicManipulatorGainControlTargetEffect extends ContinuousEffectImpl {
|
||||
|
||||
private boolean valid;
|
||||
|
||||
public SimicManipulatorGainControlTargetEffect(Duration duration) {
|
||||
super(duration, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl);
|
||||
}
|
||||
|
||||
public SimicManipulatorGainControlTargetEffect(final SimicManipulatorGainControlTargetEffect effect) {
|
||||
super(effect);
|
||||
this.valid = effect.valid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Ability source, Game game) {
|
||||
Permanent permanent = game.getPermanent(source.getFirstTarget());
|
||||
if (permanent != null) {
|
||||
int maxPower = 0;
|
||||
for (Cost cost : source.getCosts()) {
|
||||
if (cost instanceof RemoveVariableCountersSourceCost) {
|
||||
maxPower = ((RemoveVariableCountersSourceCost) cost).getAmount();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (permanent.getPower().getValue() <= maxPower) {
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimicManipulatorGainControlTargetEffect copy() {
|
||||
return new SimicManipulatorGainControlTargetEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(source.getFirstTarget());
|
||||
if (permanent != null && valid) {
|
||||
return permanent.changeControllerId(source.getControllerId(), game);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(Mode mode) {
|
||||
return "Gain control of target " + mode.getTargets().get(0).getTargetName() + ' ' + duration.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,50 +29,49 @@ package mage.cards.s;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.AsEntersBattlefieldAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.common.ChooseOpponentEffect;
|
||||
import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect;
|
||||
import mage.constants.SubType;
|
||||
import mage.abilities.keyword.TrampleAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterLandPermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.SupertypePredicate;
|
||||
import mage.filter.predicate.permanent.ControllerIdPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeffwadsworth, fireshoes & L_J
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class SkyshroudWarBeast extends CardImpl {
|
||||
|
||||
public SkyshroudWarBeast(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}");
|
||||
|
||||
this.subtype.add(SubType.BEAST);
|
||||
this.power = new MageInt(0);
|
||||
this.toughness = new MageInt(0);
|
||||
|
||||
// Trample
|
||||
this.addAbility(TrampleAbility.getInstance());
|
||||
|
||||
|
||||
// As Skyshroud War Beast enters the battlefield, choose an opponent.
|
||||
this.addAbility(new AsEntersBattlefieldAbility(new ChooseOpponentEffect(Outcome.Detriment)));
|
||||
|
||||
// Skyshroud War Beast's power is equal to the number of tapped lands the chosen player controls.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new SkyshroudWarBeastCount(), Duration.WhileOnBattlefield, SubLayer.CharacteristicDefining_7a)));
|
||||
this.addAbility(new AsEntersBattlefieldAbility(new ChooseOpponentEffect(Outcome.BoostCreature)));
|
||||
|
||||
// Skyshroud War Beast's power and toughness are each equal to the number of nonbasic lands the chosen player controls.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SkyshroudWarBeastEffect()));
|
||||
}
|
||||
|
||||
public SkyshroudWarBeast(final SkyshroudWarBeast card) {
|
||||
|
@ -85,35 +84,37 @@ public class SkyshroudWarBeast extends CardImpl {
|
|||
}
|
||||
}
|
||||
|
||||
class SkyshroudWarBeastCount implements DynamicValue {
|
||||
class SkyshroudWarBeastEffect extends ContinuousEffectImpl {
|
||||
|
||||
public SkyshroudWarBeastEffect() {
|
||||
super(Duration.EndOfGame, Layer.PTChangingEffects_7, SubLayer.CharacteristicDefining_7a, Outcome.BoostCreature);
|
||||
staticText = "{this}'s power and toughness are each equal to the number of nonbasic lands the chosen player controls";
|
||||
}
|
||||
|
||||
public SkyshroudWarBeastEffect(final SkyshroudWarBeastEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||
if (sourceAbility != null) {
|
||||
UUID playerId = (UUID) game.getState().getValue(sourceAbility.getSourceId() + ChooseOpponentEffect.VALUE_KEY);
|
||||
Player chosenPlayer = game.getPlayer(playerId);
|
||||
if (chosenPlayer != null) {
|
||||
FilterLandPermanent filter = new FilterLandPermanent("nonbasic lands the chosen player controls");
|
||||
filter.add(Predicates.not(new SupertypePredicate(SuperType.BASIC)));
|
||||
public SkyshroudWarBeastEffect copy() {
|
||||
return new SkyshroudWarBeastEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
MageObject target = game.getObject(source.getSourceId());
|
||||
if (target != null) {
|
||||
UUID playerId = (UUID) game.getState().getValue(source.getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY);
|
||||
FilterLandPermanent filter = new FilterLandPermanent();
|
||||
filter.add(new ControllerIdPredicate(playerId));
|
||||
return game.getBattlefield().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game);
|
||||
int number = new PermanentsOnBattlefieldCount(filter).calculate(game, source, this);
|
||||
target.getPower().setValue(number);
|
||||
target.getToughness().setValue(number);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicValue copy() {
|
||||
return new SkyshroudWarBeastCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "1";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "nonbasic lands the chosen player controls";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,19 +28,23 @@
|
|||
package mage.cards.v;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.CipherEffect;
|
||||
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlSourceEffect;
|
||||
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect;
|
||||
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.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -49,7 +53,7 @@ import mage.target.common.TargetCreaturePermanent;
|
|||
public class Voidwalk extends CardImpl {
|
||||
|
||||
public Voidwalk(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{U}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}");
|
||||
|
||||
// Exile target creature. Return it to the battlefield under its owner's control at the beginning of the next end step.
|
||||
this.getSpellAbility().addEffect(new VoidwalkEffect());
|
||||
|
@ -71,32 +75,29 @@ public class Voidwalk extends CardImpl {
|
|||
|
||||
class VoidwalkEffect extends OneShotEffect {
|
||||
|
||||
private static final String effectText = "Exile target creature. Return it to the battlefield under its owner's control at the beginning of the next end step";
|
||||
|
||||
VoidwalkEffect() {
|
||||
super(Outcome.Benefit);
|
||||
staticText = effectText;
|
||||
public VoidwalkEffect() {
|
||||
super(Outcome.Detriment);
|
||||
staticText = "Exile target creature. Return it to the battlefield under its owner's control at the beginning of the next end step";
|
||||
}
|
||||
|
||||
VoidwalkEffect(VoidwalkEffect effect) {
|
||||
public VoidwalkEffect(final VoidwalkEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(source.getFirstTarget());
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
if (getTargetPointer().getFirst(game, source) != null) {
|
||||
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||
if (permanent != null) {
|
||||
int zcc = game.getState().getZoneChangeCounter(permanent.getId());
|
||||
if (permanent.moveToExile(null, "", source.getSourceId(), game)) {
|
||||
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(
|
||||
new ReturnToBattlefieldUnderOwnerControlSourceEffect(false, zcc + 1)), source);
|
||||
}
|
||||
}
|
||||
MageObject sourceObject = game.getObject(source.getSourceId());
|
||||
if (controller != null && permanent != null && sourceObject != null) {
|
||||
if (controller.moveCardToExileWithInfo(permanent, source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true)) {
|
||||
//create delayed triggered ability
|
||||
Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect();
|
||||
effect.setText("Return that card to the battlefield under its owner's control at the beginning of the next end step");
|
||||
effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game));
|
||||
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -190,8 +190,10 @@ class BestowEntersBattlefieldEffect extends ReplacementEffectImpl {
|
|||
if (bestowPermanent != null) {
|
||||
if (bestowPermanent.hasSubtype(SubType.AURA, game)) {
|
||||
MageObject basicObject = bestowPermanent.getBasicMageObject(game);
|
||||
basicObject.getSubtype(null).add(SubType.AURA);
|
||||
basicObject.getCardType().remove(CardType.CREATURE);
|
||||
if (basicObject != null && !basicObject.getSubtype(null).contains(SubType.AURA)) {
|
||||
basicObject.getSubtype(null).add(SubType.AURA);
|
||||
basicObject.getCardType().remove(CardType.CREATURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -37,6 +37,8 @@ import mage.MageObjectImpl;
|
|||
import mage.Mana;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.*;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.common.RemoveVariableCountersTargetCost;
|
||||
import mage.abilities.effects.common.NameACardEffect;
|
||||
import mage.abilities.mana.ActivatedManaAbilityImpl;
|
||||
import mage.cards.repository.PluginClassloaderRegistery;
|
||||
|
@ -417,6 +419,19 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
ability.getTargets().add(new TargetCreaturePermanent(filter2));
|
||||
}
|
||||
break;
|
||||
case SIMIC_MANIPULATOR: //Simic Manipulator only
|
||||
xValue = 0;
|
||||
for (Cost cost : ability.getCosts()) {
|
||||
if (cost instanceof RemoveVariableCountersTargetCost) {
|
||||
xValue = ((RemoveVariableCountersTargetCost) cost).getAmount();
|
||||
break;
|
||||
}
|
||||
}
|
||||
ability.getTargets().clear();
|
||||
FilterCreaturePermanent newFilter = new FilterCreaturePermanent("creature with power less than or equal to " + xValue);
|
||||
newFilter.add(new PowerPredicate(ComparisonType.FEWER_THAN, xValue + 1));
|
||||
ability.addTarget(new TargetCreaturePermanent(newFilter));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,5 +12,6 @@ public enum TargetAdjustment {
|
|||
X_POWER_LEQ, CHOSEN_NAME,
|
||||
CHOSEN_COLOR,
|
||||
VERSE_COUNTER_TARGETS,
|
||||
TREASURE_COUNTER_POWER
|
||||
TREASURE_COUNTER_POWER,
|
||||
SIMIC_MANIPULATOR
|
||||
}
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
*/
|
||||
package mage.game.stack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.Mana;
|
||||
|
@ -60,11 +64,6 @@ import mage.players.Player;
|
|||
import mage.util.GameLog;
|
||||
import mage.util.SubTypeList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
|
@ -254,7 +253,9 @@ public class Spell extends StackObjImpl implements Card {
|
|||
// Must be removed first time, after that will be removed by continous effect
|
||||
// Otherwise effects like evolve trigger from creature comes into play event
|
||||
card.getCardType().remove(CardType.CREATURE);
|
||||
card.getSubtype(game).add(SubType.AURA);
|
||||
if (!card.getSubtype(game).contains(SubType.AURA)) {
|
||||
card.getSubtype(game).add(SubType.AURA);
|
||||
}
|
||||
}
|
||||
if (controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null)) {
|
||||
if (bestow) {
|
||||
|
@ -263,7 +264,9 @@ public class Spell extends StackObjImpl implements Card {
|
|||
Permanent permanent = game.getPermanent(card.getId());
|
||||
if (permanent != null && permanent instanceof PermanentCard) {
|
||||
permanent.setSpellAbility(ability); // otherwise spell ability without bestow will be set
|
||||
card.addCardType(CardType.CREATURE);
|
||||
if (!card.getCardType().contains(CardType.CREATURE)) {
|
||||
card.addCardType(CardType.CREATURE);
|
||||
}
|
||||
card.getSubtype(game).remove(SubType.AURA);
|
||||
}
|
||||
}
|
||||
|
@ -483,7 +486,9 @@ public class Spell extends StackObjImpl implements Card {
|
|||
public SubTypeList getSubtype(Game game) {
|
||||
if (this.getSpellAbility() instanceof BestowAbility) {
|
||||
SubTypeList subtypes = card.getSubtype(game);
|
||||
subtypes.add(SubType.AURA);
|
||||
if (!subtypes.contains(SubType.AURA)) { // do it only once
|
||||
subtypes.add(SubType.AURA);
|
||||
}
|
||||
return subtypes;
|
||||
}
|
||||
return card.getSubtype(game);
|
||||
|
@ -493,7 +498,9 @@ public class Spell extends StackObjImpl implements Card {
|
|||
public boolean hasSubtype(SubType subtype, Game game) {
|
||||
if (this.getSpellAbility() instanceof BestowAbility) { // workaround for Bestow (don't like it)
|
||||
SubTypeList subtypes = card.getSubtype(game);
|
||||
subtypes.add(SubType.AURA);
|
||||
if (!subtypes.contains(SubType.AURA)) { // do it only once
|
||||
subtypes.add(SubType.AURA);
|
||||
}
|
||||
if (subtypes.contains(subtype)) {
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue