Merge pull request #89 from magefree/master

Merge https://github.com/magefree/mage
This commit is contained in:
L_J 2019-01-24 22:47:46 +01:00 committed by GitHub
commit 329bc42bf6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
98 changed files with 2200 additions and 958 deletions

View file

@ -0,0 +1,41 @@
package mage.client.table;
/**
* @author JayDi85
*/
public class ColumnInfo {
private Integer index;
private Integer width;
private String headerName;
private String headerHint;
private Class colClass;
public ColumnInfo(Integer index, Integer width, Class colClass, String headerName, String headerHint) {
this.index = index;
this.width = width;
this.colClass = colClass;
this.headerName = headerName;
this.headerHint = headerHint;
}
public Integer getIndex() {
return index;
}
public Integer getWidth() {
return width;
}
public String getHeaderName() {
return headerName;
}
public String getHeaderHint() {
return headerHint;
}
public Class getColClass() {
return colClass;
}
}

View file

@ -0,0 +1,69 @@
package mage.client.table;
import mage.client.util.GUISizeHelper;
import org.apache.log4j.Logger;
import javax.swing.*;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
import java.awt.event.MouseEvent;
/**
* @author JayDi85
*/
public class MageTable extends JTable {
private static final Logger logger = Logger.getLogger(MageTable.class);
private TableInfo tableInfo;
public MageTable() {
this(null);
}
public MageTable(TableInfo tableInfo) {
this.tableInfo = tableInfo;
}
@Override
public String getToolTipText(MouseEvent e) {
// default tooltip for cells
java.awt.Point p = e.getPoint();
int viewRow = rowAtPoint(p);
int viewCol = columnAtPoint(p);
int modelRow = TablesUtil.getModelRowFromView(this, viewRow);
int modelCol = this.convertColumnIndexToModel(viewCol);
String tip = null;
if (modelRow != -1 && modelCol != -1) {
tip = this.getModel().getValueAt(modelRow, modelCol).toString();
}
return GUISizeHelper.textToHtmlWithSize(tip, GUISizeHelper.tableFont);
}
@Override
protected JTableHeader createDefaultTableHeader() {
// default tooltip for headers
return new JTableHeader(columnModel) {
public String getToolTipText(MouseEvent e) {
// html tooltip
java.awt.Point p = e.getPoint();
int colIndex = columnModel.getColumnIndexAtX(p.x);
TableColumn col = columnModel.getColumn(colIndex);
int realIndex = col.getModelIndex();
String tip;
if (tableInfo != null) {
// custom hint from table info
tip = tableInfo.getColumnByIndex(realIndex).getHeaderHint();
if (tip == null) {
tip = tableInfo.getColumnByIndex(realIndex).getHeaderName();
}
} else {
// default hint from header
tip = col.getHeaderValue().toString();
}
return GUISizeHelper.textToHtmlWithSize(tip, GUISizeHelper.tableFont);
}
};
}
}

View file

@ -1,13 +1,5 @@
/*
* ChatPanel.java
*
* Created on 15-Dec-2009, 11:04:31 PM
*/
package mage.client.table;
import mage.client.MageFrame;
import mage.client.chat.ChatPanelBasic;
import mage.client.util.GUISizeHelper;
import mage.client.util.MageTableRowSorter;
@ -16,18 +8,15 @@ import mage.client.util.gui.countryBox.CountryCellRenderer;
import mage.remote.MageRemoteException;
import mage.view.RoomUsersView;
import mage.view.UsersView;
import net.java.balloontip.utils.ToolTipUtils;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static mage.client.chat.ChatPanelBasic.CHAT_ALPHA;
@ -35,20 +24,45 @@ import static mage.client.dialog.PreferencesDialog.KEY_USERS_COLUMNS_ORDER;
import static mage.client.dialog.PreferencesDialog.KEY_USERS_COLUMNS_WIDTH;
/**
*
* @author BetaSteward_at_googlemail.com, nantuko
* @author BetaSteward_at_googlemail.com, nantuko, JayDi85
*/
public class PlayersChatPanel extends javax.swing.JPanel {
private final List<String> players = new ArrayList<>();
private final UserTableModel userTableModel;
private static final int[] DEFAULT_COLUMNS_WIDTH = {20, 100, 40, 40, 40, 100, 40, 100, 80, 80};
private static final TableInfo tableInfo = new TableInfo()
.addColumn(0, 20, Icon.class, "Flag", null)
.addColumn(1, 100, String.class, "Players",
"<b>User name</b>"
+ "<br>(the number behind the header text is the number of users online)")
.addColumn(2, 40, Integer.class, "Constructed Rating", null)
.addColumn(3, 40, Integer.class, "Limited Rating", null)
.addColumn(4, 40, String.class, "Matches",
"<b>Number of matches the user played so far</b>"
+ "<br>Q = number of matches quit"
+ "<br>I = number of matches lost because of idle timeout"
+ "<br>T = number of matches lost because of match timeout")
.addColumn(5, 100, Integer.class, "MQP",
"<b>Percent-Ratio of matches played related to matches quit</b>"
+ "<br>this calculation does not include tournament matches")
.addColumn(6, 40, String.class, "Tourneys",
"<b>Number of tournaments the user played so far</b>"
+ "<br>D = number of tournaments left during draft phase"
+ "<br>C = number of tournaments left during constructing phase"
+ "<br>R = number of tournaments left during rounds")
.addColumn(7, 100, Integer.class, "TQP",
"<b>Percent-Ratio of tournament matches played related to tournament matches quit</b>"
+ "<br>this calculation does not include non tournament matches")
.addColumn(8, 80, String.class, "Games",
"<b>Current activities of the player</b>"
+ "<BR>the header itself shows the number of currently active games"
+ "<BR>T: = number of games threads "
+ "<BR><i>(that can vary from active games because of sideboarding or crashed games)</i>"
+ "<BR>limt: the maximum of games the server is configured to"
+ "<BR><i>(if the number of started games exceed that limit, the games have to wait"
+ "<BR>until active games end)</i>")
.addColumn(9, 80, String.class, "Ping", null);
/*
* Creates new form ChatPanel
*
*/
public PlayersChatPanel() {
userTableModel = new UserTableModel(); // needs to be set before initComponents();
@ -60,8 +74,7 @@ public class PlayersChatPanel extends javax.swing.JPanel {
jTablePlayers.setRowSorter(new MageTableRowSorter(userTableModel));
setGUISize();
TableUtil.setColumnWidthAndOrder(jTablePlayers, DEFAULT_COLUMNS_WIDTH, KEY_USERS_COLUMNS_WIDTH, KEY_USERS_COLUMNS_ORDER);
userTableModel.initHeaderTooltips();
TableUtil.setColumnWidthAndOrder(jTablePlayers, tableInfo.getColumnsWidth(), KEY_USERS_COLUMNS_WIDTH, KEY_USERS_COLUMNS_ORDER);
jTablePlayers.setDefaultRenderer(Icon.class, new CountryCellRenderer());
@ -122,7 +135,6 @@ public class PlayersChatPanel extends javax.swing.JPanel {
class UserTableModel extends AbstractTableModel {
private final String[] columnNames = new String[]{"Loc", "Players", "Constructed Rating", "Limited Rating", "Matches", "MQP", "Tourneys", "TQP", "Games", "Connection"};
private UsersView[] players = new UsersView[0];
public void loadData(Collection<RoomUsersView> roomUserInfoList) throws MageRemoteException {
@ -131,9 +143,9 @@ public class PlayersChatPanel extends javax.swing.JPanel {
JTableHeader th = jTablePlayers.getTableHeader();
TableColumnModel tcm = th.getColumnModel();
tcm.getColumn(jTablePlayers.convertColumnIndexToView(1)).setHeaderValue("Players (" + this.players.length + ')');
tcm.getColumn(jTablePlayers.convertColumnIndexToView(8)).setHeaderValue(
"Games " + roomUserInfo.getNumberActiveGames()
tcm.getColumn(jTablePlayers.convertColumnIndexToView(tableInfo.getColumnByName("Players").getIndex())).setHeaderValue("Players (" + this.players.length + ')');
tcm.getColumn(jTablePlayers.convertColumnIndexToView(tableInfo.getColumnByName("Games").getIndex())).setHeaderValue("Games "
+ roomUserInfo.getNumberActiveGames()
+ (roomUserInfo.getNumberActiveGames() != roomUserInfo.getNumberGameThreads() ? " (T:" + roomUserInfo.getNumberGameThreads() : " (")
+ " limit: " + roomUserInfo.getNumberMaxGames() + ')');
th.repaint();
@ -147,117 +159,44 @@ public class PlayersChatPanel extends javax.swing.JPanel {
@Override
public int getColumnCount() {
return columnNames.length;
return tableInfo.getColumns().size();
}
@Override
public Object getValueAt(int arg0, int arg1) {
switch (arg1) {
public Object getValueAt(int rowIndex, int colIndex) {
switch (colIndex) {
case 0:
return players[arg0].getFlagName();
return players[rowIndex].getFlagName();
case 1:
return players[arg0].getUserName();
return players[rowIndex].getUserName();
case 2:
return players[arg0].getConstructedRating();
return players[rowIndex].getConstructedRating();
case 3:
return players[arg0].getLimitedRating();
return players[rowIndex].getLimitedRating();
case 4:
return players[arg0].getMatchHistory();
return players[rowIndex].getMatchHistory();
case 5:
return players[arg0].getMatchQuitRatio();
return players[rowIndex].getMatchQuitRatio();
case 6:
return players[arg0].getTourneyHistory();
return players[rowIndex].getTourneyHistory();
case 7:
return players[arg0].getTourneyQuitRatio();
return players[rowIndex].getTourneyQuitRatio();
case 8:
return players[arg0].getInfoGames();
return players[rowIndex].getInfoGames();
case 9:
return players[arg0].getInfoPing();
return players[rowIndex].getInfoPing();
}
return "";
}
public void initHeaderTooltips() {
ColumnHeaderToolTips tips = new ColumnHeaderToolTips();
for (int c = 0; c < jTablePlayers.getColumnCount(); c++) {
String tooltipText = "";
switch (c) {
case 0:
tooltipText = "<HTML><b>The flag the user has assigned to his profile</b>"
+ "<br>You can assign the flag in the connect to server dialog window";
break;
case 1:
tooltipText = "<HTML><b>Name of the user</b>"
+ "<br>(the number behind the header text is the number of currently connected users to the server)";
break;
case 2:
tooltipText = "<HTML><b>Constructed player rating</b>";
break;
case 3:
tooltipText = "<HTML><b>Limited player rating</b>";
break;
case 4:
tooltipText = "<HTML><b>Number of matches the user played so far</b>"
+ "<br>Q = number of matches quit"
+ "<br>I = number of matches lost because of idle timeout"
+ "<br>T = number of matches lost because of match timeout";
break;
case 5:
tooltipText = "<HTML><b>Percent-Ratio of matches played related to matches quit</b>"
+ "<br>this calculation does not include tournament matches";
break;
case 6:
tooltipText = "<HTML><b>Number of tournaments the user played so far</b>"
+ "<br>D = number of tournaments left during draft phase"
+ "<br>C = number of tournaments left during constructing phase"
+ "<br>R = number of tournaments left during rounds";
break;
case 7:
tooltipText = "<HTML><b>Percent-Ratio of tournament matches played related to tournament matches quit</b>"
+ "<br>this calculation does not include non tournament matches";
break;
case 8:
tooltipText = "<HTML><b>Current activities of the player</b>"
+ "<BR>the header itself shows the number of currently active games"
+ "<BR>T: = number of games threads "
+ "<BR><i>(that can vary from active games because of sideboarding or crashed games)</i>"
+ "<BR>limt: the maximum of games the server is configured to"
+ "<BR><i>(if the number of started games exceed that limit, the games have to wait"
+ "<BR>until active games end)</i>";
break;
case 9:
tooltipText = "<HTML><b>Latency of the user's connection to the server</b>";
break;
}
tips.setToolTip(c, tooltipText);
}
JTableHeader header = jTablePlayers.getTableHeader();
header.addMouseMotionListener(tips);
}
@Override
public String getColumnName(int columnIndex) {
String colName = "";
if (columnIndex <= getColumnCount()) {
colName = columnNames[columnIndex];
}
return colName;
return tableInfo.getColumnByIndex(columnIndex).getHeaderName();
}
@Override
public Class getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0:
return Icon.class;
case 2:
case 3:
case 5:
case 7:
return Integer.class;
default:
return String.class;
}
return tableInfo.getColumnByIndex(columnIndex).getColClass();
}
@Override
@ -279,7 +218,7 @@ public class PlayersChatPanel extends javax.swing.JPanel {
jSpinner1 = new javax.swing.JSpinner();
jSplitPane1 = new javax.swing.JSplitPane();
jScrollPanePlayers = new javax.swing.JScrollPane();
jTablePlayers = new javax.swing.JTable();
jTablePlayers = new MageTable(tableInfo);
jTabbedPaneText = new javax.swing.JTabbedPane();
jScrollPaneTalk = new mage.client.chat.ChatPanelSeparated();
jScrollPaneSystem = new javax.swing.JScrollPane();
@ -332,14 +271,14 @@ public class PlayersChatPanel extends javax.swing.JPanel {
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 350, Short.MAX_VALUE)
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 350, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(jSplitPane1)
.addGap(0, 0, 0))
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(jSplitPane1)
.addGap(0, 0, 0))
);
}// </editor-fold>//GEN-END:initComponents
@ -350,6 +289,7 @@ public class PlayersChatPanel extends javax.swing.JPanel {
this.players.clear();
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private mage.client.components.ColorPane colorPaneSystem;
private javax.swing.JScrollPane jScrollPanePlayers;
@ -358,45 +298,6 @@ public class PlayersChatPanel extends javax.swing.JPanel {
private javax.swing.JSpinner jSpinner1;
private javax.swing.JSplitPane jSplitPane1;
private javax.swing.JTabbedPane jTabbedPaneText;
private javax.swing.JTable jTablePlayers;
private MageTable jTablePlayers;
// End of variables declaration//GEN-END:variables
static class ColumnHeaderToolTips extends MouseMotionAdapter {
int curCol;
final Map<Integer, String> tips = new HashMap<>();
public void setToolTip(Integer mCol, String tooltip) {
if (tooltip == null) {
tips.remove(mCol);
} else {
tips.put(mCol, tooltip);
}
}
@Override
public void mouseMoved(MouseEvent evt) {
JTableHeader header = (JTableHeader) evt.getSource();
JTable table = header.getTable();
TableColumnModel colModel = table.getColumnModel();
int vColIndex = colModel.getColumnIndexAtX(evt.getX());
TableColumn col = null;
if (vColIndex >= 0) {
col = colModel.getColumn(table.convertColumnIndexToModel(vColIndex));
}
if (table.convertColumnIndexToModel(vColIndex) != curCol) {
if (col != null) {
MageFrame.getInstance().getBalloonTip().setAttachedComponent(header);
JLabel content = new JLabel(tips.get(table.convertColumnIndexToModel(vColIndex)));
content.setFont(GUISizeHelper.balloonTooltipFont);
MageFrame.getInstance().getBalloonTip().setContents(content);
ToolTipUtils.balloonToToolTip(MageFrame.getInstance().getBalloonTip(), 600, 10000);
} else {
MageFrame.getInstance().getBalloonTip().setTextContents("");
}
curCol = table.convertColumnIndexToModel(vColIndex);
}
}
}
}

View file

@ -0,0 +1,47 @@
package mage.client.table;
import java.util.ArrayList;
import java.util.List;
/**
* @author JayDi85
*/
public class TableInfo {
private List<ColumnInfo> columns = new ArrayList<>();
public TableInfo() {
}
public TableInfo addColumn(Integer index, Integer width, Class colClass, String headerName, String headerHint) {
this.columns.add(new ColumnInfo(index, width, colClass, headerName, headerHint));
return this;
}
public int[] getColumnsWidth() {
return this.columns.stream().mapToInt(ColumnInfo::getIndex).toArray();
}
public List<ColumnInfo> getColumns() {
return this.columns;
}
public ColumnInfo getColumnByIndex(int index) {
for (ColumnInfo col : this.columns) {
if (col.getIndex().equals(index)) {
return col;
}
}
return null;
}
public ColumnInfo getColumnByName(String name) {
for (ColumnInfo col : this.columns) {
if (col.getHeaderName().equals(name)) {
return col;
}
}
return null;
}
}

View file

@ -28,6 +28,10 @@ import org.ocpsoft.prettytime.units.JustNow;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
@ -52,7 +56,7 @@ import static mage.client.dialog.PreferencesDialog.*;
public class TablesPanel extends javax.swing.JPanel {
private static final Logger LOGGER = Logger.getLogger(TablesPanel.class);
private static final int[] DEFAULT_COLUMNS_WIDTH = {35, 150, 120, 180, 80, 120, 80, 60, 40, 40, 60};
private static final int[] DEFAULT_COLUMNS_WIDTH = {35, 150, 100, 50, 120, 180, 80, 120, 80, 60, 40, 40, 60};
private final TablesTableModel tableModel;
private final MatchesTableModel matchesModel;
@ -71,6 +75,7 @@ public class TablesPanel extends javax.swing.JPanel {
private final TablesButtonColumn actionButton1;
private final TablesButtonColumn actionButton2;
private final Map<JTable, String> tablesLastSelection = new HashMap<>();
final JToggleButton[] filterButtons;
@ -158,6 +163,16 @@ public class TablesPanel extends javax.swing.JPanel {
}
};
// center text render
TableCellRenderer centerCellRenderer = new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
label.setHorizontalAlignment(JLabel.CENTER);
return label;
}
};
/**
* Creates new form TablesPanel
*/
@ -184,6 +199,8 @@ public class TablesPanel extends javax.swing.JPanel {
tableTables.getColumnModel().getColumn(TablesTableModel.COLUMN_CREATED).setCellRenderer(timeAgoCellRenderer);
// skill level
tableTables.getColumnModel().getColumn(TablesTableModel.COLUMN_SKILL).setCellRenderer(skillCellRenderer);
// seats
tableTables.getColumnModel().getColumn(TablesTableModel.COLUMN_SEATS).setCellRenderer(centerCellRenderer);
/* date sorter (not need, default is good - see getColumnClass)
activeTablesSorter.setComparator(TablesTableModel.COLUMN_CREATED, new Comparator<Date>() {
@ -353,18 +370,59 @@ public class TablesPanel extends javax.swing.JPanel {
// !!!! adds action buttons to the table panel (don't delete this)
actionButton1 = new TablesButtonColumn(tableTables, openTableAction, tableTables.convertColumnIndexToView(TablesTableModel.ACTION_COLUMN));
actionButton2 = new TablesButtonColumn(tableCompleted, closedTableAction, tableCompleted.convertColumnIndexToView(MatchesTableModel.COLUMN_ACTION));
// !!!!
// selection
tablesLastSelection.put(tableTables, "");
tablesLastSelection.put(tableCompleted, "");
addTableSelectListener(tableTables);
addTableSelectListener(tableCompleted);
// double click
addTableDoubleClickListener(tableTables, openTableAction);
addTableDoubleClickListener(tableCompleted, closedTableAction);
}
private void addTableSelectListener(JTable table) {
// https://stackoverflow.com/a/26142800/1276632
// save last selection
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
int modelRow = TablesUtil.getSelectedModelRow(table);
if (modelRow != -1) {
// needs only selected
String rowId = TablesUtil.getSearchIdFromTable(table, modelRow);
tablesLastSelection.put(table, rowId);
}
}
});
// restore selection
table.getModel().addTableModelListener(new TableModelListener() {
@Override
public void tableChanged(TableModelEvent e) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
String lastRowID = tablesLastSelection.get(table);
int needModelRow = TablesUtil.findTableRowFromSearchId(table.getModel(), lastRowID);
int needViewRow = TablesUtil.getViewRowFromModel(table, needModelRow);
if (needViewRow != -1) {
table.clearSelection();
table.addRowSelectionInterval(needViewRow, needViewRow);
}
}
});
}
});
}
private void addTableDoubleClickListener(JTable table, Action action) {
table.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int row = table.getSelectedRow();
if (e.getClickCount() == 2 && row != -1) {
action.actionPerformed(new ActionEvent(table, ActionEvent.ACTION_PERFORMED, TablesUtil.getSearchIdFromTable(table, row)));
int modelRow = TablesUtil.getSelectedModelRow(table);
if (e.getClickCount() == 2 && modelRow != -1) {
action.actionPerformed(new ActionEvent(table, ActionEvent.ACTION_PERFORMED, TablesUtil.getSearchIdFromTable(table, modelRow)));
}
}
});
@ -810,9 +868,9 @@ public class TablesPanel extends javax.swing.JPanel {
jPanelTables = new javax.swing.JPanel();
jSplitPaneTables = new javax.swing.JSplitPane();
jScrollPaneTablesActive = new javax.swing.JScrollPane();
tableTables = new javax.swing.JTable();
tableTables = new MageTable();
jScrollPaneTablesFinished = new javax.swing.JScrollPane();
tableCompleted = new javax.swing.JTable();
tableCompleted = new MageTable();
chatPanelMain = new mage.client.table.PlayersChatPanel();
jPanelBottom = new javax.swing.JPanel();
jButtonFooterNext = new javax.swing.JButton();
@ -1351,8 +1409,8 @@ public class TablesPanel extends javax.swing.JPanel {
private javax.swing.JToolBar.Separator jSeparator5;
private javax.swing.JSplitPane jSplitPane1;
private javax.swing.JSplitPane jSplitPaneTables;
private javax.swing.JTable tableCompleted;
private javax.swing.JTable tableTables;
private MageTable tableCompleted;
private MageTable tableTables;
// End of variables declaration//GEN-END:variables
}

View file

@ -12,29 +12,42 @@ import java.util.Date;
public class TablesTableModel extends AbstractTableModel {
final ImageIcon tourneyIcon = new ImageIcon(getClass().getResource("/tables/tourney_icon.png"));
final ImageIcon matchIcon = new ImageIcon(getClass().getResource("/tables/match_icon.png"));
// icons with tostring for tables hints
final ImageIcon tourneyIcon = new ImageIcon(getClass().getResource("/tables/tourney_icon.png")) {
@Override
public String toString() {
return "Tourney";
}
};
final ImageIcon matchIcon = new ImageIcon(getClass().getResource("/tables/match_icon.png")) {
@Override
public String toString() {
return "Match";
}
};
public static final int COLUMN_ICON = 0;
public static final int COLUMN_DECK_TYPE = 1; // column the deck type is located (starting with 0) Start string is used to check for Limited
public static final int COLUMN_OWNER = 2;
public static final int COLUMN_GAME_TYPE = 3;
public static final int COLUMN_INFO = 4;
public static final int COLUMN_STATUS = 5;
public static final int COLUMN_PASSWORD = 6;
public static final int COLUMN_CREATED = 7;
public static final int COLUMN_SKILL = 8;
public static final int COLUMN_RATING = 9;
public static final int COLUMN_QUIT_RATIO = 10;
public static final int COLUMN_MINIMUM_RATING = 11;
public static final int ACTION_COLUMN = 12; // column the action is located (starting with 0)
public static final int COLUMN_NAME = 2;
public static final int COLUMN_SEATS = 3;
public static final int COLUMN_OWNER = 4;
public static final int COLUMN_GAME_TYPE = 5;
public static final int COLUMN_INFO = 6;
public static final int COLUMN_STATUS = 7;
public static final int COLUMN_PASSWORD = 8;
public static final int COLUMN_CREATED = 9;
public static final int COLUMN_SKILL = 10;
public static final int COLUMN_RATING = 11;
public static final int COLUMN_QUIT_RATIO = 12;
public static final int COLUMN_MINIMUM_RATING = 13;
public static final int ACTION_COLUMN = 14; // column the action is located (starting with 0)
public static final String RATED_VALUE_YES = "YES";
public static final String RATED_VALUE_NO = "";
public static final String PASSWORD_VALUE_YES = "YES";
private final String[] columnNames = new String[]{"M/T", "Deck Type", "Owner / Players", "Game Type", "Info", "Status", "Password", "Created / Started", "Skill Level", "Rated", "Quit %", "Min Rating", "Action"};
private final String[] columnNames = new String[]{"M/T", "Deck Type", "Name", "Seats", "Owner / Players", "Game Type", "Info", "Status", "Password", "Created / Started", "Skill Level", "Rated", "Quit %", "Min Rating", "Action"};
private TableView[] tables = new TableView[0];
@ -104,55 +117,59 @@ public class TablesTableModel extends AbstractTableModel {
}
@Override
public Object getValueAt(int arg0, int arg1) {
switch (arg1) {
public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0:
return tables[arg0].isTournament() ? tourneyIcon : matchIcon;
return tables[rowIndex].isTournament() ? tourneyIcon : matchIcon;
case 1:
return tables[arg0].getDeckType();
return tables[rowIndex].getDeckType();
case 2:
return tables[arg0].getControllerName();
return tables[rowIndex].getTableName();
case 3:
return tables[arg0].getGameType();
return tables[rowIndex].getSeatsInfo();
case 4:
return tables[arg0].getAdditionalInfo();
return tables[rowIndex].getControllerName();
case 5:
return tables[arg0].getTableStateText();
return tables[rowIndex].getGameType();
case 6:
return tables[arg0].isPassworded() ? PASSWORD_VALUE_YES : "";
return tables[rowIndex].getAdditionalInfo();
case 7:
return tables[arg0].getCreateTime(); // use cell render, not format here
return tables[rowIndex].getTableStateText();
case 8:
return this.getSkillLevelAsCode(tables[arg0].getSkillLevel(), false);
return tables[rowIndex].isPassworded() ? PASSWORD_VALUE_YES : "";
case 9:
return tables[arg0].isRated() ? RATED_VALUE_YES : RATED_VALUE_NO;
return tables[rowIndex].getCreateTime(); // use cell render, not format here
case 10:
return tables[arg0].getQuitRatio();
return this.getSkillLevelAsCode(tables[rowIndex].getSkillLevel(), false);
case 11:
return tables[arg0].getMinimumRating();
return tables[rowIndex].isRated() ? RATED_VALUE_YES : RATED_VALUE_NO;
case 12:
switch (tables[arg0].getTableState()) {
return tables[rowIndex].getQuitRatio();
case 13:
return tables[rowIndex].getMinimumRating();
case 14:
switch (tables[rowIndex].getTableState()) {
case WAITING:
String owner = tables[arg0].getControllerName();
String owner = tables[rowIndex].getControllerName();
if (SessionHandler.getSession() != null && owner.equals(SessionHandler.getUserName())) {
return "";
}
return "Join";
case CONSTRUCTING:
case DRAFTING:
if (tables[arg0].isTournament()) {
if (tables[rowIndex].isTournament()) {
return "Show";
}
case DUELING:
if (tables[arg0].isTournament()) {
if (tables[rowIndex].isTournament()) {
return "Show";
} else {
owner = tables[arg0].getControllerName();
owner = tables[rowIndex].getControllerName();
if (SessionHandler.getSession() != null && owner.equals(SessionHandler.getUserName())) {
return "";
}
if (tables[arg0].getSpectatorsAllowed()) {
if (tables[rowIndex].getSpectatorsAllowed()) {
return "Watch";
}
return "";
@ -160,15 +177,15 @@ public class TablesTableModel extends AbstractTableModel {
default:
return "";
}
case 13:
return tables[arg0].isTournament();
case 14:
if (!tables[arg0].getGames().isEmpty()) {
return tables[arg0].getGames().get(0);
case 15:
return tables[rowIndex].isTournament();
case 16:
if (!tables[rowIndex].getGames().isEmpty()) {
return tables[rowIndex].getGames().get(0);
}
return null;
case 15:
return tables[arg0].getTableId();
case 17:
return tables[rowIndex].getTableId();
}
return "";
}

View file

@ -29,16 +29,35 @@ public class TablesUtil {
public static int findTableRowFromSearchId(Object tableModel, String searchId) {
// tableUUID;gameUUID
int row = -1;
if (tableModel instanceof TablesTableModel) {
row = ((TablesTableModel) tableModel).findRowByTableAndGameInfo(searchId);
} else if (tableModel instanceof MatchesTableModel) {
row = ((MatchesTableModel) tableModel).findRowByTableAndGameInfo(searchId);
} else if (tableModel instanceof TournamentMatchesTableModel) {
row = ((TournamentMatchesTableModel) tableModel).findRowByTableAndGameInfo(searchId);
} else {
logger.error("Not supported tables model " + tableModel.getClass().toString());
if (searchId != null) {
if (tableModel instanceof TablesTableModel) {
row = ((TablesTableModel) tableModel).findRowByTableAndGameInfo(searchId);
} else if (tableModel instanceof MatchesTableModel) {
row = ((MatchesTableModel) tableModel).findRowByTableAndGameInfo(searchId);
} else if (tableModel instanceof TournamentMatchesTableModel) {
row = ((TournamentMatchesTableModel) tableModel).findRowByTableAndGameInfo(searchId);
} else {
logger.error("Not supported tables model " + tableModel.getClass().toString());
}
}
return row;
}
public static int getSelectedModelRow(JTable table) {
return getModelRowFromView(table, table.getSelectedRow());
}
public static int getModelRowFromView(JTable table, int viewRow) {
if (viewRow != -1 && viewRow < table.getModel().getRowCount()) {
return table.convertRowIndexToModel(viewRow);
}
return -1;
}
public static int getViewRowFromModel(JTable table, int modelRow) {
if (modelRow != -1 && modelRow < table.getModel().getRowCount()) {
return table.convertRowIndexToView(modelRow);
}
return -1;
}
}

View file

@ -8,6 +8,7 @@ package mage.client.util;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.util.Locale;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
@ -178,4 +179,11 @@ public final class GUISizeHelper {
}
}
}
public static String textToHtmlWithSize(String text, Font font) {
if (text != null && !text.toLowerCase(Locale.ENGLISH).startsWith("<html>")) {
return "<html><p style=\"font-size: " + font.getSize() + ";\">" + text + "</p>";
}
return text;
}
}

View file

@ -70,7 +70,7 @@ public class ScryfallSymbolsSource implements Iterable<DownloadJob> {
}
// gen symbols list
List<String> allMageSymbols = Arrays.asList(SYMBOLS_LIST);
List<String> allMageSymbols = new ArrayList<>(Arrays.asList(SYMBOLS_LIST));
for (Integer i = SYMBOLS_NUMBER_START; i <= SYMBOLS_NUMBER_END; i++) {
allMageSymbols.add(String.valueOf(SYMBOLS_NUMBER_START + i));
}

View file

@ -11,7 +11,6 @@ import mage.client.dialog.PreferencesDialog;
import mage.client.util.CardLanguage;
import mage.client.util.sets.ConstructedFormats;
import mage.remote.Connection;
import mage.util.StreamUtils;
import net.java.truevfs.access.TFile;
import net.java.truevfs.access.TFileOutputStream;
import net.java.truevfs.access.TVFS;
@ -26,8 +25,8 @@ import java.awt.event.ItemEvent;
import java.io.*;
import java.net.*;
import java.nio.file.AccessDeniedException;
import java.util.*;
import java.util.List;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@ -49,8 +48,11 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
private static final String ALL_STANDARD_IMAGES = "- STANDARD images";
private static final String ALL_TOKENS = "- TOKEN images";
private static final int MAX_ERRORS_COUNT_BEFORE_CANCEL = 50;
private DownloadImagesDialog uiDialog;
private boolean needCancel;
private int errorCount;
private int cardIndex;
private List<CardInfo> cardsAll;
@ -110,19 +112,28 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
// show dialog
instance.setNeedCancel(false);
instance.resetErrorCount();
instance.uiDialog.showDialog();
instance.uiDialog.dispose();
instance.setNeedCancel(true);
}
public boolean getNeedCancel() {
return this.needCancel;
private boolean getNeedCancel() {
return this.needCancel || (this.errorCount > MAX_ERRORS_COUNT_BEFORE_CANCEL);
}
public void setNeedCancel(boolean needCancel) {
private void setNeedCancel(boolean needCancel) {
this.needCancel = needCancel;
}
private void incErrorCount() {
this.errorCount = this.errorCount + 1;
}
private void resetErrorCount() {
this.errorCount = 0;
}
public DownloadPicturesService(JFrame frame) {
// init service and dialog
cardsAll = Collections.synchronizedList(new ArrayList<>());
@ -788,29 +799,43 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
// download
selectedSource.doPause(url.getPath());
httpConn = url.openConnection(p);
httpConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2");
httpConn.connect();
int responseCode = ((HttpURLConnection) httpConn).getResponseCode();
if (httpConn != null) {
// check result
if (responseCode != 200) {
// show errors only on full fail (all urls were not work)
errorsList.add("Image download for " + card.getName()
+ (!card.getDownloadName().equals(card.getName()) ? " downloadname: " + card.getDownloadName() : "")
+ " (" + card.getSet() + ") failed - responseCode: " + responseCode + " url: " + url.toString());
if (logger.isDebugEnabled()) {
// Shows the returned html from the request to the web server
logger.debug("Returned HTML ERROR:\n" + convertStreamToString(((HttpURLConnection) httpConn).getErrorStream()));
httpConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2");
try {
httpConn.connect();
} catch (SocketException e) {
incErrorCount();
errorsList.add("Wrong image URL or java app is not allowed to use network. Check your firewall or proxy settings. Error: " + e.getMessage() + ". Image URL: " + url.toString());
break;
} catch (UnknownHostException e) {
incErrorCount();
errorsList.add("Unknown site. Check your DNS settings. Error: " + e.getMessage() + ". Image URL: " + url.toString());
break;
}
int responseCode = ((HttpURLConnection) httpConn).getResponseCode();
// go to next try
continue;
} else {
// all fine
isDownloadOK = true;
break;
// check result
if (responseCode != 200) {
// show errors only on full fail (all urls were not work)
errorsList.add("Image download for " + card.getName()
+ (!card.getDownloadName().equals(card.getName()) ? " downloadname: " + card.getDownloadName() : "")
+ " (" + card.getSet() + ") failed - responseCode: " + responseCode + " url: " + url.toString());
if (logger.isDebugEnabled()) {
// Shows the returned html from the request to the web server
logger.debug("Returned HTML ERROR:\n" + convertStreamToString(((HttpURLConnection) httpConn).getErrorStream()));
}
// go to next try
continue;
} else {
// all fine
isDownloadOK = true;
break;
}
}
}
@ -868,9 +893,11 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
}
} catch (AccessDeniedException e) {
incErrorCount();
logger.error("Can't access to files: " + card.getName() + "(" + card.getSet() + "). Try rebooting your system to remove the file lock.");
} catch (Exception e) {
logger.error(e.getMessage(), e);
incErrorCount();
logger.error("Unknown error: " + e.getMessage(), e);
} finally {
}

View file

@ -1,11 +1,5 @@
package mage.view;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import mage.constants.SkillLevel;
import mage.constants.TableState;
import mage.game.Game;
@ -15,6 +9,12 @@ import mage.game.draft.Draft;
import mage.game.match.MatchPlayer;
import mage.game.tournament.TournamentPlayer;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
/**
* @author BetaSteward_at_googlemail.com
*/
@ -32,6 +32,7 @@ public class TableView implements Serializable {
private TableState tableState;
private final SkillLevel skillLevel;
private final String tableStateText;
private final String seatsInfo;
private boolean isTournament;
private List<SeatView> seats = new ArrayList<>();
private List<UUID> games = new ArrayList<>();
@ -46,10 +47,6 @@ public class TableView implements Serializable {
this.tableId = table.getId();
this.gameType = table.getGameType();
this.tableName = table.getName();
String tableNameInfo = null;
if (tableName != null && !tableName.isEmpty()) {
tableNameInfo = " [" + table.getName() + ']';
}
this.controllerName = table.getControllerName();
this.tableState = table.getState();
if (table.getState() == TableState.WAITING
@ -69,8 +66,9 @@ public class TableView implements Serializable {
}
if (!table.isTournament()) {
// MATCH
seatsInfo = "" + table.getMatch().getPlayers().size() + '/' + table.getSeats().length;
if (table.getState() == TableState.WAITING || table.getState() == TableState.READY_TO_START) {
tableStateText = table.getState().toString() + " (" + table.getMatch().getPlayers().size() + '/' + table.getSeats().length + ')';
tableStateText = table.getState().toString() + " (" + seatsInfo + ')';
} else {
tableStateText = table.getState().toString();
}
@ -94,7 +92,7 @@ public class TableView implements Serializable {
sbScore.append(" Draws: ").append(table.getMatch().getDraws());
}
this.controllerName += sb.toString();
this.deckType = table.getDeckType() + (tableNameInfo != null ? tableNameInfo : "");
this.deckType = table.getDeckType();
StringBuilder addInfo = new StringBuilder();
if (table.getMatch().getGames().isEmpty()) {
addInfo.append("Wins:").append(table.getMatch().getWinsNeeded());
@ -129,10 +127,11 @@ public class TableView implements Serializable {
}
}
this.controllerName += sb1.toString();
this.seatsInfo = "" + table.getTournament().getPlayers().size() + "/" + table.getNumberOfSeats();
StringBuilder infoText = new StringBuilder();
StringBuilder stateText = new StringBuilder(table.getState().toString());
infoText.append("Wins:").append(table.getTournament().getOptions().getMatchOptions().getWinsNeeded());
infoText.append(" Seats: ").append(table.getTournament().getPlayers().size()).append('/').append(table.getNumberOfSeats());
infoText.append(" Seats: ").append(this.seatsInfo);
switch (table.getState()) {
case WAITING:
stateText.append(" (").append(table.getTournament().getPlayers().size()).append('/').append(table.getNumberOfSeats()).append(')');
@ -158,7 +157,7 @@ public class TableView implements Serializable {
}
this.additionalInfo = infoText.toString();
this.tableStateText = stateText.toString();
this.deckType = table.getDeckType() + ' ' + table.getTournament().getBoosterInfo() + (tableNameInfo != null ? tableNameInfo : "");
this.deckType = table.getDeckType() + ' ' + table.getTournament().getBoosterInfo();
this.skillLevel = table.getTournament().getOptions().getMatchOptions().getSkillLevel();
this.quitRatio = Integer.toString(table.getTournament().getOptions().getQuitRatio());
this.minimumRating = Integer.toString(table.getTournament().getOptions().getMinimumRating());
@ -180,11 +179,11 @@ public class TableView implements Serializable {
public String getControllerName() {
return controllerName;
}
public boolean getSpectatorsAllowed() {
return spectatorsAllowed;
}
public String getGameType() {
return gameType;
@ -210,6 +209,10 @@ public class TableView implements Serializable {
return games;
}
public String getSeatsInfo() {
return seatsInfo;
}
public boolean isTournament() {
return this.isTournament;
}
@ -226,9 +229,13 @@ public class TableView implements Serializable {
return skillLevel;
}
public String getQuitRatio() { return quitRatio; }
public String getQuitRatio() {
return quitRatio;
}
public String getMinimumRating() { return minimumRating; }
public String getMinimumRating() {
return minimumRating;
}
public boolean isLimited() {
return limited;

View file

@ -1,16 +1,15 @@
package mage.deck;
import java.util.Date;
import java.util.GregorianCalendar;
import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.cards.decks.Constructed;
import mage.constants.SetType;
import java.util.Date;
import java.util.GregorianCalendar;
/**
*
* @author LevelX2
*/
public class Modern extends Constructed {
@ -42,6 +41,7 @@ public class Modern extends Constructed {
banned.add("Great Furnace");
banned.add("Green Sun's Zenith");
banned.add("Hypergenesis");
banned.add("Krark-Clan Ironworks");
banned.add("Mental Misstep");
banned.add("Ponder");
banned.add("Preordain");

View file

@ -1,8 +1,5 @@
package mage.player.human;
import java.io.Serializable;
import java.util.*;
import mage.MageObject;
import mage.abilities.*;
import mage.abilities.costs.VariableCost;
@ -18,8 +15,6 @@ import mage.cards.decks.Deck;
import mage.choices.Choice;
import mage.choices.ChoiceImpl;
import mage.constants.*;
import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_RESET_ALL;
import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_RESET_ALL;
import mage.filter.StaticFilters;
import mage.filter.common.FilterAttackingCreature;
import mage.filter.common.FilterBlockingCreature;
@ -42,16 +37,21 @@ import mage.target.Target;
import mage.target.TargetAmount;
import mage.target.TargetCard;
import mage.target.TargetPermanent;
import mage.target.common.TargetAttackingCreature;
import mage.target.common.TargetAnyTarget;
import mage.target.common.TargetAttackingCreature;
import mage.target.common.TargetDefender;
import mage.util.GameLog;
import mage.util.ManaUtil;
import mage.util.MessageToClient;
import org.apache.log4j.Logger;
import java.io.Serializable;
import java.util.*;
import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_RESET_ALL;
import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_RESET_ALL;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class HumanPlayer extends PlayerImpl {
@ -341,7 +341,7 @@ public class HumanPlayer extends PlayerImpl {
replacementEffectChoice.getChoices().clear();
replacementEffectChoice.setKeyChoices(rEffects);
// Check if there are different ones
int differentChoices = 0;
String lastChoice = "";
@ -511,6 +511,7 @@ public class HumanPlayer extends PlayerImpl {
prepareForResponse(game);
if (!isExecutingMacro()) {
// hmm
game.fireSelectTargetEvent(getId(), new MessageToClient(target.getMessage(), getRelatedObjectName(source, game)), possibleTargets, required, getOptions(target, null));
}
waitForResponse(game);
@ -782,9 +783,9 @@ public class HumanPlayer extends PlayerImpl {
if (!skippedAtLeastOnce
|| (playerId.equals(game.getActivePlayerId())
&& !controllingPlayer
.getUserData()
.getUserSkipPrioritySteps()
.isStopOnAllEndPhases())) {
.getUserData()
.getUserSkipPrioritySteps()
.isStopOnAllEndPhases())) {
skippedAtLeastOnce = true;
if (passWithManaPoolCheck(game)) {
return false;
@ -876,9 +877,7 @@ public class HumanPlayer extends PlayerImpl {
}
}
return result;
} else if (response.getManaType() != null) {
return false;
}
} else return response.getManaType() == null;
return true;
}
return false;
@ -1126,8 +1125,8 @@ public class HumanPlayer extends PlayerImpl {
if (passedAllTurns
|| passedUntilEndStepBeforeMyTurn
|| (!getControllingPlayersUserData(game)
.getUserSkipPrioritySteps()
.isStopOnDeclareAttackersDuringSkipAction()
.getUserSkipPrioritySteps()
.isStopOnDeclareAttackersDuringSkipAction()
&& (passedTurn
|| passedTurnSkipStack
|| passedUntilEndOfTurn
@ -1146,7 +1145,7 @@ public class HumanPlayer extends PlayerImpl {
}
options.put(Constants.Option.POSSIBLE_ATTACKERS, (Serializable) possibleAttackers);
if (!possibleAttackers.isEmpty()) {
options.put(Constants.Option.SPECIAL_BUTTON, (Serializable) "All attack");
options.put(Constants.Option.SPECIAL_BUTTON, "All attack");
}
prepareForResponse(game);
@ -1304,7 +1303,7 @@ public class HumanPlayer extends PlayerImpl {
/**
* Selects a defender for an attacker and adds the attacker to combat
*
* @param defenders - list of possible defender
* @param defenders - list of possible defender
* @param attackerId - UUID of attacker
* @param game
* @return
@ -1364,8 +1363,8 @@ public class HumanPlayer extends PlayerImpl {
filter.add(new ControllerIdPredicate(defendingPlayerId));
if (game.getBattlefield().count(filter, null, playerId, game) == 0
&& !getControllingPlayersUserData(game)
.getUserSkipPrioritySteps()
.isStopOnDeclareBlockerIfNoneAvailable()) {
.getUserSkipPrioritySteps()
.isStopOnDeclareBlockerIfNoneAvailable()) {
return;
}
while (!abort) {

View file

@ -418,7 +418,7 @@ public final class Main {
File[] files = directory.listFiles(
(dir, name) -> name.endsWith(".game")
);
if(files != null) {
if (files != null) {
for (File file : files) {
file.delete();
}

View file

@ -30,7 +30,7 @@ public enum SessionManager {
if (session.getUserId() != null && !UserManager.instance.getUser(session.getUserId()).isPresent()) {
logger.error("User for session " + sessionId + " with userId " + session.getUserId() + " is missing. Session removed.");
// can happen if user from same host signs in multiple time with multiple clients, after he disconnects with one client
disconnect(sessionId, DisconnectReason.ConnectingOtherInstance);
disconnect(sessionId, DisconnectReason.ConnectingOtherInstance, session); // direct disconnect
return Optional.empty();
}
return Optional.of(session);
@ -96,32 +96,42 @@ public enum SessionManager {
}
public void disconnect(String sessionId, DisconnectReason reason) {
getSession(sessionId).ifPresent(session -> {
if (!isValidSession(sessionId)) {
// session was removed meanwhile by another thread so we can return
return;
}
logger.debug("DISCONNECT " + reason.toString() + " - sessionId: " + sessionId);
sessions.remove(sessionId);
switch (reason) {
case AdminDisconnect:
session.kill(reason);
break;
case ConnectingOtherInstance:
case Disconnected: // regular session end or wrong client version
UserManager.instance.disconnect(session.getUserId(), reason);
break;
case SessionExpired: // session ends after no reconnect happens in the defined time span
break;
case LostConnection: // user lost connection - session expires countdown starts
session.userLostConnection();
UserManager.instance.disconnect(session.getUserId(), reason);
break;
default:
logger.trace("endSession: unexpected reason " + reason.toString() + " - sessionId: " + sessionId);
}
});
disconnect(sessionId, reason, null);
}
public void disconnect(String sessionId, DisconnectReason reason, Session directSession) {
if (directSession == null) {
// find real session to disconnects
getSession(sessionId).ifPresent(session -> {
if (!isValidSession(sessionId)) {
// session was removed meanwhile by another thread so we can return
return;
}
logger.debug("DISCONNECT " + reason.toString() + " - sessionId: " + sessionId);
sessions.remove(sessionId);
switch (reason) {
case AdminDisconnect:
session.kill(reason);
break;
case ConnectingOtherInstance:
case Disconnected: // regular session end or wrong client version
UserManager.instance.disconnect(session.getUserId(), reason);
break;
case SessionExpired: // session ends after no reconnect happens in the defined time span
break;
case LostConnection: // user lost connection - session expires countdown starts
session.userLostConnection();
UserManager.instance.disconnect(session.getUserId(), reason);
break;
default:
logger.trace("endSession: unexpected reason " + reason.toString() + " - sessionId: " + sessionId);
}
});
} else {
// direct session to disconnects
sessions.remove(sessionId);
directSession.kill(reason);
}
}

View file

@ -1,9 +1,8 @@
package mage.cards.a;
import java.util.UUID;
import mage.ObjectColor;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.InvertCondition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
@ -13,20 +12,21 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.filter.predicate.permanent.ControllerPredicate;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class AngelicVoices extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("nonartifact, nonwhite creatures");
private static final FilterPermanent filter = new FilterCreaturePermanent("nonartifact, nonwhite creatures");
static {
filter.add(Predicates.not(
@ -38,15 +38,15 @@ public final class AngelicVoices extends CardImpl {
filter.add(new ControllerPredicate(TargetController.YOU));
}
private static final Condition condition = new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter));
public AngelicVoices(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}");
// Creatures you control get +1/+1 as long as you control no nonartifact, nonwhite creatures.
this.addAbility(new SimpleStaticAbility(
Zone.BATTLEFIELD,
new ConditionalContinuousEffect(
new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield),
new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)),
new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield), condition,
"Creatures you control get +1/+1 as long as you control no nonartifact, nonwhite creatures."
)
));

View file

@ -24,11 +24,11 @@ public final class AppliedBiomancy extends CardImpl {
// Target creature gets +1/+1 until end of turn.
this.getSpellAbility().addEffect(new BoostTargetEffect(1, 1));
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("gets +1/+1 until end of turn"));
// Return target creature to its owner's hand.
Mode mode = new Mode(new ReturnToHandTargetEffect());
mode.addTarget(new TargetCreaturePermanent());
mode.addTarget(new TargetCreaturePermanent().withChooseHint("return to its owner's hand"));
this.getSpellAbility().addMode(mode);
}

View file

@ -1,6 +1,5 @@
package mage.cards.a;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.effects.common.TapTargetEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
@ -11,8 +10,9 @@ import mage.constants.Duration;
import mage.filter.common.FilterCreaturePermanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class ArtfulTakedown extends CardImpl {
@ -33,14 +33,14 @@ public final class ArtfulTakedown extends CardImpl {
this.getSpellAbility().addEffect(
new TapTargetEffect().setText("target creature")
);
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter1));
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter1).withChooseHint("tap"));
// Target creature gets -2/-4 until end of turn.
Mode mode = new Mode(
new BoostTargetEffect(-2, -4, Duration.EndOfTurn)
.setText("target creature gets -2/-4 until end of turn")
);
mode.addTarget(new TargetCreaturePermanent(filter2));
mode.addTarget(new TargetCreaturePermanent(filter2).withChooseHint("gets -2/-4 until end of turn"));
this.getSpellAbility().addMode(mode);
}

View file

@ -76,7 +76,7 @@ class BedazzleEffect extends OneShotEffect {
permanent.destroy(source.getSourceId(), game, false);
}
Effect effect = new DamageTargetEffect(new StaticValue(2), true, "", true);
effect.setTargetPointer(new FixedTarget(source.getTargets().get(0).getFirstTarget(), game));
effect.setTargetPointer(new FixedTarget(source.getTargets().get(1).getFirstTarget(), game));
effect.apply(game, source);
return true;
}

View file

@ -110,7 +110,7 @@ class BiomancersFamiliarCostReductionEffect extends CostModificationEffectImpl {
|| (abilityToModify.getAbilityType() == AbilityType.MANA && abilityToModify instanceof ActivatedAbility)) {
//Activated abilities of creatures you control
Permanent permanent = game.getPermanent(abilityToModify.getSourceId());
if (permanent != null && permanent.isControlledBy(source.getControllerId())) {
if (permanent != null && permanent.isCreature() && permanent.isControlledBy(source.getControllerId())) {
return true;
}
}

View file

@ -1,7 +1,5 @@
package mage.cards.b;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.Effect;
@ -20,8 +18,9 @@ import mage.filter.predicate.other.PlayerPredicate;
import mage.target.TargetPlayer;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author emerald000
*/
public final class BlessedAlliance extends CardImpl {
@ -35,7 +34,7 @@ public final class BlessedAlliance extends CardImpl {
}
public BlessedAlliance(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}");
// Escalate {2}
this.addAbility(new EscalateAbility(new GenericManaCost(2)));
@ -48,20 +47,20 @@ public final class BlessedAlliance extends CardImpl {
Effect effect = new GainLifeTargetEffect(4);
effect.setText("Target player gains 4 life");
this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterGainLife));
this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterGainLife).withChooseHint("player gains 4 life"));
// Untap up to two target creatures.
Mode mode = new Mode();
effect = new UntapTargetEffect();
effect.setText("Untap up to two target creatures");
mode.addEffect(effect);
mode.addTarget(new TargetCreaturePermanent(0, 2, filterCreature, false));
mode.addTarget(new TargetCreaturePermanent(0, 2, filterCreature, false).withChooseHint("untap"));
this.getSpellAbility().addMode(mode);
// Target opponent sacrifices an attacking creature.
mode = new Mode();
mode.addEffect(new SacrificeEffect(new FilterAttackingCreature(), 1, "Target opponent"));
mode.addTarget(new TargetPlayer(1, 1, false, filterSacrifice));
mode.addTarget(new TargetPlayer(1, 1, false, filterSacrifice).withChooseHint("sacrifices an attacking creature"));
this.getSpellAbility().addMode(mode);
}

View file

@ -1,7 +1,5 @@
package mage.cards.b;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.Effect;
@ -16,8 +14,9 @@ import mage.constants.Duration;
import mage.filter.common.FilterCreaturePermanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class BorrowedHostility extends CardImpl {
@ -26,7 +25,7 @@ public final class BorrowedHostility extends CardImpl {
private static final FilterCreaturePermanent filterFirstStrike = new FilterCreaturePermanent("creature to gain first strike");
public BorrowedHostility(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{R}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}");
// Escalate {3}
this.addAbility(new EscalateAbility(new ManaCostsImpl<>("{3}")));
@ -38,15 +37,15 @@ public final class BorrowedHostility extends CardImpl {
// Target creature gets +3/+0 until end of turn.;
Effect effect = new BoostTargetEffect(3, 0, Duration.EndOfTurn);
effect.setText("Target creature gets +3/+0 until end of turn");
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterBoost));
this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterBoost).withChooseHint("gets +3/+0 until end of turn"));
// Target creature gains first strike until end of turn.
Mode mode = new Mode();
effect = new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn);
effect.setText("Target creature gains first strike until end of turn");
mode.addEffect(effect);
mode.addTarget(new TargetCreaturePermanent(filterFirstStrike));
mode.addTarget(new TargetCreaturePermanent(filterFirstStrike).withChooseHint("gains first strike until end of turn"));
this.getSpellAbility().addMode(mode);
}

View file

@ -1,7 +1,5 @@
package mage.cards.b;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.Effect;
@ -14,8 +12,9 @@ import mage.constants.Duration;
import mage.filter.common.FilterCreaturePermanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author fireshoes
*/
public final class BorrowedMalevolence extends CardImpl {
@ -24,7 +23,7 @@ public final class BorrowedMalevolence extends CardImpl {
private static final FilterCreaturePermanent filterCreatureMinus = new FilterCreaturePermanent("creature to get -1/-1");
public BorrowedMalevolence(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{B}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}");
// Escalate {2}
this.addAbility(new EscalateAbility(new GenericManaCost(2)));
@ -37,14 +36,14 @@ public final class BorrowedMalevolence extends CardImpl {
Effect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn);
effect.setText("Target creature gets +1/+1 until end of turn");
this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterCreaturePlus));
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterCreaturePlus).withChooseHint("gets +1/+1 until end of turn"));
// Target creature gets -1/-1 until end of turn.
Mode mode = new Mode();
effect = new BoostTargetEffect(-1, -1, Duration.EndOfTurn);
effect.setText("Target creature gets -1/-1 until end of turn");
mode.addEffect(effect);
mode.addTarget(new TargetCreaturePermanent(filterCreatureMinus));
mode.addTarget(new TargetCreaturePermanent(filterCreatureMinus).withChooseHint("gets -1/-1 until end of turn"));
this.getSpellAbility().addMode(mode);
}

View file

@ -1,7 +1,5 @@
package mage.cards.b;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.OneShotEffect;
@ -18,8 +16,9 @@ import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author North
*/
public final class BranchingBolt extends CardImpl {
@ -33,19 +32,18 @@ public final class BranchingBolt extends CardImpl {
}
public BranchingBolt(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{R}{G}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}{G}");
// Choose one or both -
this.getSpellAbility().getModes().setMinModes(1);
this.getSpellAbility().getModes().setMaxModes(2);
// Branching Bolt deals 3 damage to target creature with flying;
this.getSpellAbility().addEffect(new DamageTargetEffect(3));
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterFlying));
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterFlying).withChooseHint("deals 3 damage, without flying"));
// or Branching Bolt deals 3 damage to target creature without flying.
Mode mode = new Mode();
mode.addEffect(new DamageTargetEffect(3));
mode.addTarget(new TargetCreaturePermanent(filterNotFlying));
mode.addTarget(new TargetCreaturePermanent(filterNotFlying).withChooseHint("deals 3 damage, without flying"));
this.getSpellAbility().addMode(mode);
}

View file

@ -1,7 +1,5 @@
package mage.cards.b;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DamageTargetEffect;
@ -18,13 +16,15 @@ import mage.target.common.TargetCreatureOrPlaneswalker;
import mage.target.common.TargetSpellOrPermanent;
import mage.watchers.common.DamagedByWatcher;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class BrutalExpulsion extends CardImpl {
private static final FilterSpellOrPermanent filter = new FilterSpellOrPermanent("spell or creature");
static {
filter.setPermanentFilter(new FilterCreaturePermanent());
}
@ -39,15 +39,15 @@ public final class BrutalExpulsion extends CardImpl {
this.getSpellAbility().getModes().setMinModes(1);
this.getSpellAbility().getModes().setMaxModes(2);
// - Return target spell or creature to its owner's hand;
this.getSpellAbility().addTarget(new TargetSpellOrPermanent(1, 1, filter, false));
this.getSpellAbility().addEffect(new ReturnToHandTargetEffect());
this.getSpellAbility().addTarget(new TargetSpellOrPermanent(1, 1, filter, false).withChooseHint("return to its owner's hand"));
// or Brutal Expulsion deals 2 damage to target creature or planeswalker. If that permanent would be put into a graveyard this turn, exile it instead.
Mode mode = new Mode();
mode.addTarget(new TargetCreatureOrPlaneswalker());
mode.addEffect(new DamageTargetEffect(2));
Effect effect = new DealtDamageToCreatureBySourceDies(this, Duration.EndOfTurn);
effect.setText("If that permanent would be put into a graveyard this turn, exile it instead");
mode.addEffect(effect);
mode.addTarget(new TargetCreatureOrPlaneswalker().withChooseHint("deals 2 damage and exile instead"));
this.getSpellAbility().addMode(mode);
this.getSpellAbility().addWatcher(new DamagedByWatcher(true));
}

View file

@ -1,7 +1,5 @@
package mage.cards.c;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
@ -13,12 +11,11 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Zone;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class CephalidPathmage extends CardImpl {
@ -35,8 +32,8 @@ public final class CephalidPathmage extends CardImpl {
this.addAbility(new CantBeBlockedSourceAbility());
// {tap}, Sacrifice Cephalid Pathmage: Target creature is unblockable this turn.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CantBeBlockedTargetEffect(Duration.EndOfTurn), new SacrificeSourceCost());
ability.addCost(new TapSourceCost());
Ability ability = new SimpleActivatedAbility(new CantBeBlockedTargetEffect(), new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}

View file

@ -1,7 +1,5 @@
package mage.cards.c;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
import mage.abilities.effects.common.DamageTargetEffect;
@ -15,18 +13,19 @@ import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.target.common.TargetCreaturePermanent;
import mage.target.common.TargetPlayerOrPlaneswalker;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
public final class ClanDefiance extends CardImpl {
static final private FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying");
static final private FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creature without flying");
static final private FilterCreaturePermanent filterFlying = new FilterCreaturePermanent("creature with flying");
static final private FilterCreaturePermanent filterWithoutFlying = new FilterCreaturePermanent("creature without flying");
static {
filter.add(new AbilityPredicate(FlyingAbility.class));
filter2.add(Predicates.not(new AbilityPredicate(FlyingAbility.class)));
filterFlying.add(new AbilityPredicate(FlyingAbility.class));
filterWithoutFlying.add(Predicates.not(new AbilityPredicate(FlyingAbility.class)));
}
public ClanDefiance(UUID ownerId, CardSetInfo setInfo) {
@ -37,16 +36,16 @@ public final class ClanDefiance extends CardImpl {
this.getSpellAbility().getModes().setMaxModes(3);
// Clan Defiance deals X damage to target creature with flying;
this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance));
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter));
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterFlying).withChooseHint("deals X damage, with flying"));
// Clan Defiance deals X damage to target creature without flying;
Mode mode1 = new Mode();
mode1.addEffect(new DamageTargetEffect(ManacostVariableValue.instance));
mode1.addTarget(new TargetCreaturePermanent(filter2));
mode1.addTarget(new TargetCreaturePermanent(filterWithoutFlying).withChooseHint("deals X damage, without flying"));
this.getSpellAbility().addMode(mode1);
// and/or Clan Defiance deals X damage to target player.
Mode mode2 = new Mode();
mode2.addEffect(new DamageTargetEffect(ManacostVariableValue.instance));
mode2.addTarget(new TargetPlayerOrPlaneswalker());
mode2.addTarget(new TargetPlayerOrPlaneswalker().withChooseHint("deals X damage"));
this.getSpellAbility().addMode(mode2);
}

View file

@ -1,8 +1,6 @@
package mage.cards.c;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.AttachEffect;
@ -11,18 +9,13 @@ import mage.abilities.effects.common.ruleModifying.TargetsHaveToTargetPermanentI
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AttachmentType;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.constants.*;
import mage.target.TargetPermanent;
import mage.target.common.TargetControlledCreaturePermanent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class CoalitionFlag extends CardImpl {
@ -40,10 +33,12 @@ public final class CoalitionFlag extends CardImpl {
this.addAbility(ability);
// Enchanted creature is a Flagbearer.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SetCardSubtypeAttachedEffect(Duration.WhileOnBattlefield, AttachmentType.AURA, SubType.FLAGBEARER)));
this.addAbility(new SimpleStaticAbility(new SetCardSubtypeAttachedEffect(
Duration.WhileOnBattlefield, AttachmentType.AURA, SubType.FLAGBEARER
)));
// While choosing targets as part of casting a spell or activating an ability, your opponents must choose at least one Flagbearer on the battlefield if able.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TargetsHaveToTargetPermanentIfAbleEffect(new FilterPermanent(SubType.FLAGBEARER, "one Flagbearer"))));
this.addAbility(new SimpleStaticAbility(new TargetsHaveToTargetPermanentIfAbleEffect()));
}
public CoalitionFlag(final CoalitionFlag card) {

View file

@ -1,7 +1,6 @@
package mage.cards.c;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.ruleModifying.TargetsHaveToTargetPermanentIfAbleEffect;
@ -9,8 +8,8 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import java.util.UUID;
/**
* Cardname: Coalition Honor Guard
@ -28,7 +27,7 @@ public final class CoalitionHonorGuard extends CardImpl {
this.toughness = new MageInt(4);
// While choosing targets as part of casting a spell or activating an ability, your opponents must choose at least one Flagbearer on the battlefield if able.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TargetsHaveToTargetPermanentIfAbleEffect(new FilterPermanent(SubType.FLAGBEARER, "one Flagbearer"))));
this.addAbility(new SimpleStaticAbility(new TargetsHaveToTargetPermanentIfAbleEffect()));
}
public CoalitionHonorGuard(final CoalitionHonorGuard card) {

View file

@ -1,7 +1,5 @@
package mage.cards.c;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.costs.Cost;
import mage.abilities.costs.common.DiscardCardCost;
@ -25,8 +23,9 @@ import mage.filter.predicate.other.PlayerPredicate;
import mage.target.TargetPlayer;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author fireshoes
*/
public final class CollectiveBrutality extends CardImpl {
@ -44,7 +43,7 @@ public final class CollectiveBrutality extends CardImpl {
}
public CollectiveBrutality(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{B}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}");
// Escalate - Discard a card.
Cost cost = new DiscardCardCost();
@ -59,14 +58,14 @@ public final class CollectiveBrutality extends CardImpl {
Effect effect = new DiscardCardYouChooseTargetEffect(filter, TargetController.ANY);
effect.setText("Target opponent reveals their hand. You choose an instant or sorcery card from it. That player discards that card");
this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterDiscard));
this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterDiscard).withChooseHint("reveals hand, you choose to discard"));
// Target creature gets -2/-2 until end of turn.;
Mode mode = new Mode();
effect = new BoostTargetEffect(-2, -2, Duration.EndOfTurn);
effect.setText("Target creature gets -2/-2 until end of turn");
mode.addEffect(effect);
mode.addTarget(new TargetCreaturePermanent(filterCreatureMinus));
mode.addTarget(new TargetCreaturePermanent(filterCreatureMinus).withChooseHint("gets -2/-2 until end of turn"));
this.getSpellAbility().addMode(mode);
// Target opponent loses 2 life and you gain 2 life.
@ -74,10 +73,9 @@ public final class CollectiveBrutality extends CardImpl {
effect = new LoseLifeTargetEffect(2);
effect.setText("Target opponent loses 2 life");
mode.addEffect(effect);
mode.addTarget(new TargetPlayer(1, 1, false, filterLoseLife));
mode.addTarget(new TargetPlayer(1, 1, false, filterLoseLife).withChooseHint("loses 2 life"));
effect = new GainLifeEffect(2);
effect.setText("and you gain 2 life");
mode.addEffect(effect);
mode.addEffect(effect.concatBy("and"));
this.getSpellAbility().addMode(mode);
}

View file

@ -1,7 +1,5 @@
package mage.cards.c;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.costs.mana.GenericManaCost;
@ -22,8 +20,9 @@ import mage.target.TargetPlayer;
import mage.target.common.TargetCreaturePermanent;
import mage.target.common.TargetOpponentOrPlaneswalker;
import java.util.UUID;
/**
*
* @author fireshoes
*/
public final class CollectiveDefiance extends CardImpl {
@ -43,14 +42,14 @@ public final class CollectiveDefiance extends CardImpl {
// Target player discards all cards in their hand, then draws that many cards.;
this.getSpellAbility().addEffect(new CollectiveDefianceEffect());
this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterDiscard));
this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterDiscard).withChooseHint("discards all cards and draws"));
// Collective Defiance deals 4 damage to target creature.;
Mode mode = new Mode();
Effect effect = new DamageTargetEffect(4);
effect.setText("{this} deals 4 damage to target creature");
mode.addEffect(effect);
mode.addTarget(new TargetCreaturePermanent(filterCreature));
mode.addTarget(new TargetCreaturePermanent(filterCreature).withChooseHint("deals 4 damage to"));
this.getSpellAbility().addMode(mode);
// Collective Defiance deals 3 damage to target opponent or planeswalker.
@ -58,7 +57,7 @@ public final class CollectiveDefiance extends CardImpl {
effect = new DamageTargetEffect(3);
effect.setText("{this} deals 3 damage to target opponent or planeswalker");
mode.addEffect(effect);
mode.addTarget(new TargetOpponentOrPlaneswalker());
mode.addTarget(new TargetOpponentOrPlaneswalker().withChooseHint("deals 3 damage to"));
this.getSpellAbility().addMode(mode);
}

View file

@ -1,7 +1,5 @@
package mage.cards.c;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.costs.Cost;
@ -32,8 +30,9 @@ import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetCreaturePermanent;
import mage.target.common.TargetEnchantmentPermanent;
import java.util.UUID;
/**
*
* @author fireshoes
*/
public final class CollectiveEffort extends CardImpl {
@ -62,14 +61,14 @@ public final class CollectiveEffort extends CardImpl {
// Destroy target creature with power 4 or greater.;
this.getSpellAbility().addEffect(new DestroyTargetEffect());
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterDestroyCreature));
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterDestroyCreature).withChooseHint("destroy"));
// Destroy target enchantment.;
Mode mode = new Mode();
Effect effect = new DestroyTargetEffect();
effect.setText("Destroy target enchantment");
mode.addEffect(effect);
mode.addTarget(new TargetEnchantmentPermanent(filterDestroyEnchantment));
mode.addTarget(new TargetEnchantmentPermanent(filterDestroyEnchantment).withChooseHint("destroy"));
this.getSpellAbility().addMode(mode);
// Put a +1/+1 counter on each creature target player controls.
@ -77,7 +76,7 @@ public final class CollectiveEffort extends CardImpl {
effect = new CollectiveEffortEffect();
effect.setText("Put a +1/+1 counter on each creature target player controls");
mode.addEffect(effect);
mode.addTarget(new TargetPlayer(1, 1, false, filterPlayer));
mode.addTarget(new TargetPlayer(1, 1, false, filterPlayer).withChooseHint("put +1/+1 counter on each creature"));
this.getSpellAbility().addMode(mode);
}

View file

@ -1,49 +1,52 @@
package mage.cards.c;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.VariableCost;
import mage.abilities.costs.mana.VariableManaCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.InfoEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterMana;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetAnyTarget;
import java.util.UUID;
/**
* @author nantuko
*/
public final class ConsumeSpirit extends CardImpl {
static final FilterMana filterBlack = new FilterMana();
private static final FilterMana filterBlack = new FilterMana();
static {
filterBlack.setBlack(true);
}
public ConsumeSpirit(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{1}{B}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{1}{B}");
// Spend only black mana on X.
this.addAbility(new SimpleStaticAbility(
Zone.ALL, new InfoEffect("Spend only black mana on X")).setRuleAtTheTop(true)
);
// Consume Spirit deals X damage to any target and you gain X life.
this.getSpellAbility().addTarget(new TargetAnyTarget());
this.getSpellAbility().addEffect(new ConsumeSpiritEffect());
this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance));
this.getSpellAbility().addEffect(new GainLifeEffect(ManacostVariableValue.instance).concatBy("and"));
VariableCost variableCost = this.getSpellAbility().getManaCostsToPay().getVariableCosts().get(0);
if (variableCost instanceof VariableManaCost) {
((VariableManaCost) variableCost).setFilter(filterBlack);
}
}
public ConsumeSpirit(final ConsumeSpirit card) {
private ConsumeSpirit(final ConsumeSpirit card) {
super(card);
}
@ -52,46 +55,3 @@ public final class ConsumeSpirit extends CardImpl {
return new ConsumeSpirit(this);
}
}
class ConsumeSpiritEffect extends OneShotEffect {
public ConsumeSpiritEffect() {
super(Outcome.Damage);
staticText = "Consume Spirit deals X damage to any target and you gain X life. Spend only black mana on X";
}
public ConsumeSpiritEffect(final ConsumeSpiritEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
int amount = source.getManaCostsToPay().getX();
if (amount > 0) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null) {
permanent.damage(amount, source.getSourceId(), game, false, true);
} else {
Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
if (player != null) {
player.damage(amount, source.getSourceId(), game, false, true);
} else {
return false;
}
}
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
controller.gainLife(amount, game, source);
} else {
return false;
}
}
return true;
}
@Override
public ConsumeSpiritEffect copy() {
return new ConsumeSpiritEffect(this);
}
}

View file

@ -1,7 +1,6 @@
package mage.cards.c;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
@ -9,15 +8,16 @@ import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class CrazedFirecat extends CardImpl {
@ -34,7 +34,7 @@ public final class CrazedFirecat extends CardImpl {
this.addAbility(new EntersBattlefieldTriggeredAbility(new CrazedFirecatEffect(), false));
}
public CrazedFirecat(final CrazedFirecat card) {
private CrazedFirecat(final CrazedFirecat card) {
super(card);
}
@ -46,12 +46,12 @@ public final class CrazedFirecat extends CardImpl {
class CrazedFirecatEffect extends OneShotEffect {
public CrazedFirecatEffect() {
CrazedFirecatEffect() {
super(Outcome.Benefit);
this.staticText = "flip a coin until you lose a flip. Put a +1/+1 counter on {this} for each flip you win.";
this.staticText = "flip a coin until you lose a flip. Put a +1/+1 counter on {this} for each flip you won.";
}
public CrazedFirecatEffect(final CrazedFirecatEffect effect) {
private CrazedFirecatEffect(final CrazedFirecatEffect effect) {
super(effect);
}

View file

@ -1,7 +1,5 @@
package mage.cards.c;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.cards.CardImpl;
@ -10,28 +8,28 @@ import mage.constants.CardType;
import mage.target.common.TargetArtifactPermanent;
import mage.target.common.TargetEnchantmentPermanent;
import java.util.UUID;
/**
*
* @author Ryan-Saklad
*/
public final class CrushContraband extends CardImpl {
public CrushContraband(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{W}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{W}");
// Choose one or both - Destroy target artifact; or Destroy target land.
this.getSpellAbility().getModes().setMinModes(1);
this.getSpellAbility().getModes().setMaxModes(2);
this.getSpellAbility().addTarget(new TargetArtifactPermanent());
this.getSpellAbility().addEffect(new ExileTargetEffect());
this.getSpellAbility().addTarget(new TargetArtifactPermanent().withChooseHint("destroy"));
Mode mode1 = new Mode();
mode1.addTarget(new TargetEnchantmentPermanent());
mode1.addEffect(new ExileTargetEffect());
mode1.addTarget(new TargetEnchantmentPermanent().withChooseHint("destroy"));
this.getSpellAbility().addMode(mode1);
}
public CrushContraband(final CrushContraband card) {

View file

@ -12,6 +12,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
@ -28,7 +29,7 @@ public final class CryptOfTheEternals extends CardImpl {
this.addAbility(new ColorlessManaAbility());
// {1}, {T}: Add {U}, {B}, or {R}.
List<Mana> list = Arrays.asList(Mana.BlueMana(1), Mana.BlackMana(1), Mana.RedMana(1));
List<Mana> list = new ArrayList<>(Arrays.asList(Mana.BlueMana(1), Mana.BlackMana(1), Mana.RedMana(1)));
for (Mana m : list) {

View file

@ -1,7 +1,6 @@
package mage.cards.d;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.StateTriggeredAbility;
import mage.abilities.common.EntersBattlefieldAbility;
@ -22,8 +21,9 @@ import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.MaritLageToken;
import java.util.UUID;
/**
*
* @author Plopman
*/
public final class DarkDepths extends CardImpl {
@ -106,7 +106,8 @@ class DarkDepthsAbility extends StateTriggeredAbility {
@Override
public String getRule() {
return "When {this} has no ice counters on it, sacrifice it. If you do, create a legendary 20/20 black Avatar creature token with flying and indestructible named Marit Lage.";
return "When {this} has no ice counters on it, sacrifice it. If you do, " +
"create Marit Lage, a legendary 20/20 black Avatar creature token with flying and indestructible.";
}
}

View file

@ -1,7 +1,5 @@
package mage.cards.d;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect;
@ -13,19 +11,21 @@ import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.target.common.TargetCardInYourGraveyard;
import mage.target.common.TargetEnchantmentPermanent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class DawnToDusk extends CardImpl {
private static final FilterCard filterCard = new FilterCard("enchantment card from your graveyard");
static {
filterCard.add(new CardTypePredicate(CardType.ENCHANTMENT));
}
public DawnToDusk(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{W}{W}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}{W}");
// Choose one or both -
@ -33,11 +33,11 @@ public final class DawnToDusk extends CardImpl {
this.getSpellAbility().getModes().setMaxModes(2);
// Return target enchantment card from your graveyard to your hand;
this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect());
this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filterCard));
this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filterCard).withChooseHint("return from graveyard to hand"));
// and/or destroy target enchantment.
Mode mode = new Mode();
mode.addEffect(new DestroyTargetEffect());
mode.addTarget(new TargetEnchantmentPermanent());
mode.addTarget(new TargetEnchantmentPermanent().withChooseHint("destroy"));
this.getSpellAbility().addMode(mode);
}

View file

@ -1,29 +1,32 @@
package mage.cards.d;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.VariableCost;
import mage.abilities.costs.mana.VariableManaCost;
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.Outcome;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.FilterMana;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetAnyTarget;
import java.util.UUID;
/**
*
* @author KholdFuzion
*
*/
public final class DrainLife extends CardImpl {
static final FilterMana filterBlack = new FilterMana();
private static final FilterMana filterBlack = new FilterMana();
static {
filterBlack.setBlack(true);
@ -33,6 +36,10 @@ public final class DrainLife extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{1}{B}");
// Spend only black mana on X.
this.addAbility(new SimpleStaticAbility(
Zone.ALL, new InfoEffect("Spend only black mana on X")).setRuleAtTheTop(true)
);
// Drain Life deals X damage to any target. You gain life equal to the damage dealt, but not more life than the player's life total before Drain Life dealt damage or the creature's toughness.
this.getSpellAbility().addTarget(new TargetAnyTarget());
this.getSpellAbility().addEffect(new DrainLifeEffect());
@ -42,7 +49,7 @@ public final class DrainLife extends CardImpl {
}
}
public DrainLife(final DrainLife card) {
private DrainLife(final DrainLife card) {
super(card);
}
@ -54,12 +61,14 @@ public final class DrainLife extends CardImpl {
class DrainLifeEffect extends OneShotEffect {
public DrainLifeEffect() {
DrainLifeEffect() {
super(Outcome.Damage);
staticText = "Spend only black mana on X.<br>{this} deals X damage to any target. You gain life equal to the damage dealt, but not more life than the player's life total before Drain Life dealt damage or the creature's toughness";
staticText = "{this} deals X damage to any target. You gain life equal to the damage dealt, " +
"but not more life than the players life total before the damage was dealt, " +
"the planeswalkers loyalty before the damage was dealt, or the creatures toughness.";
}
public DrainLifeEffect(final DrainLifeEffect effect) {
private DrainLifeEffect(final DrainLifeEffect effect) {
super(effect);
}
@ -67,31 +76,32 @@ class DrainLifeEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
int amount = source.getManaCostsToPay().getX();
int lifetogain = amount;
if (amount > 0) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null) {
if (permanent.getToughness().getValue() < amount) {
lifetogain = permanent.getToughness().getValue();
}
permanent.damage(amount, source.getSourceId(), game, false, true);
} else {
Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
if (player != null) {
if (player.getLife() < amount) {
lifetogain = player.getLife();
}
player.damage(amount, source.getSourceId(), game, false, true);
} else {
return false;
}
}
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
controller.gainLife(lifetogain, game, source);
if (amount == 0) {
return true;
}
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null) {
if (permanent.isCreature()) {
lifetogain = Math.min(permanent.getToughness().getValue(), lifetogain);
} else if (permanent.isPlaneswalker()) {
lifetogain = Math.min(permanent.getCounters(game).getCount(CounterType.LOYALTY), lifetogain);
} else {
return false;
}
permanent.damage(amount, source.getSourceId(), game);
} else {
Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
if (player == null) {
return false;
}
lifetogain = Math.min(player.getLife(), lifetogain);
player.damage(amount, source.getSourceId(), game);
}
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
controller.gainLife(lifetogain, game, source);
return true;
}

View file

@ -1,7 +1,5 @@
package mage.cards.f;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.cards.CardImpl;
@ -10,25 +8,26 @@ import mage.constants.CardType;
import mage.target.common.TargetArtifactPermanent;
import mage.target.common.TargetNonBasicLandPermanent;
import java.util.UUID;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public final class FissureVent extends CardImpl {
public FissureVent(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{R}{R}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}{R}");
// Choose one or both - Destroy target artifact; and/or destroy target nonbasic land.
this.getSpellAbility().getModes().setMinModes(1);
this.getSpellAbility().getModes().setMaxModes(2);
this.getSpellAbility().addTarget(new TargetArtifactPermanent());
this.getSpellAbility().addEffect(new DestroyTargetEffect());
this.getSpellAbility().addTarget(new TargetArtifactPermanent().withChooseHint("destroy"));
Mode mode1 = new Mode();
mode1.addTarget(new TargetNonBasicLandPermanent());
mode1.addEffect(new DestroyTargetEffect());
mode1.addTarget(new TargetNonBasicLandPermanent().withChooseHint("destroy"));
this.getSpellAbility().addMode(mode1);
}

View file

@ -1,7 +1,5 @@
package mage.cards.f;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.cards.CardImpl;
@ -11,8 +9,9 @@ import mage.filter.StaticFilters;
import mage.filter.common.FilterArtifactCard;
import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID;
/**
*
* @author fireshoes
*/
public final class FortuitousFind extends CardImpl {
@ -26,12 +25,12 @@ public final class FortuitousFind extends CardImpl {
// Return target artifact card from your graveyard to your hand.;
this.getSpellAbility().addEffect(new ReturnToHandTargetEffect());
this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard")));
this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard")).withChooseHint("return to hand"));
// or Return target creature card from your graveyard to your hand.
Mode mode = new Mode();
mode.addEffect(new ReturnToHandTargetEffect());
mode.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD));
mode.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD).withChooseHint("return to hand"));
this.getSpellAbility().addMode(mode);
}

View file

@ -1,18 +1,18 @@
package mage.cards.g;
import java.util.UUID;
import mage.abilities.common.EntersBattlefieldTappedAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect;
import mage.abilities.mana.AnyColorManaAbility;
import mage.constants.SubType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class GatewayPlaza extends CardImpl {
@ -27,9 +27,7 @@ public final class GatewayPlaza extends CardImpl {
// When Gateway Plaza enters the battlefield, sacrifice it unless you pay {1}.
this.addAbility(new EntersBattlefieldTriggeredAbility(
new SacrificeSourceUnlessPaysEffect(
new GenericManaCost(1)
), false
new SacrificeSourceUnlessPaysEffect(new GenericManaCost(1)).setText("sacrifice it unless you pay {1}")
));
// {T}: Add one mana of any color.

View file

@ -0,0 +1,154 @@
package mage.cards.g;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageObject;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.counter.RemoveCounterSourceEffect;
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.counters.CounterType;
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.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
import mage.watchers.common.BlockedAttackerWatcher;
/**
*
* @author L_J
*/
public final class GlyphOfDelusion extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Wall creature");
static {
filter.add(new SubtypePredicate(SubType.WALL));
}
public GlyphOfDelusion(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}");
// Put X glyph counters on target creature that target Wall blocked this turn, where X is the power of that blocked creature. The creature gains This creature doesnt untap during your untap step if it has a glyph counter on it and At the beginning of your upkeep, remove a glyph counter from this creature.
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter));
this.getSpellAbility().addTarget(new GlyphOfDelusionSecondTarget());
this.getSpellAbility().addEffect(new GlyphOfDelusionEffect());
this.getSpellAbility().addWatcher(new BlockedAttackerWatcher());
}
public GlyphOfDelusion(final GlyphOfDelusion card) {
super(card);
}
@Override
public GlyphOfDelusion copy() {
return new GlyphOfDelusion(this);
}
}
class GlyphOfDelusionSecondTarget extends TargetPermanent {
private Permanent firstTarget = null;
public GlyphOfDelusionSecondTarget() {
super();
setTargetName("target creature that target Wall blocked this turn");
}
public GlyphOfDelusionSecondTarget(final GlyphOfDelusionSecondTarget target) {
super(target);
this.firstTarget = target.firstTarget;
}
@Override
public Set<UUID> possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) {
Set<UUID> possibleTargets = new HashSet<>();
if (firstTarget != null) {
BlockedAttackerWatcher watcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName());
if (watcher != null) {
MageObject targetSource = game.getObject(sourceId);
if (targetSource != null) {
for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, sourceId, game)) {
if (!targets.containsKey(creature.getId()) && creature.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), new MageObjectReference(firstTarget, game), game)) {
possibleTargets.add(creature.getId());
}
}
}
}
}
}
return possibleTargets;
}
@Override
public boolean chooseTarget(Outcome outcome, UUID playerId, Ability source, Game game) {
firstTarget = game.getPermanent(source.getFirstTarget());
return super.chooseTarget(Outcome.Tap, playerId, source, game);
}
@Override
public GlyphOfDelusionSecondTarget copy() {
return new GlyphOfDelusionSecondTarget(this);
}
}
class GlyphOfDelusionEffect extends OneShotEffect {
public GlyphOfDelusionEffect() {
super(Outcome.Detriment);
this.staticText = "Put X glyph counters on target creature that target Wall blocked this turn, where X is the power of that blocked creature. The creature gains \"This creature doesnt untap during your untap step if it has a glyph counter on it\" and \"At the beginning of your upkeep, remove a glyph counter from this creature.\"";
}
public GlyphOfDelusionEffect(final GlyphOfDelusionEffect effect) {
super(effect);
}
@Override
public GlyphOfDelusionEffect copy() {
return new GlyphOfDelusionEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
if (source.getTargets().get(1) != null) {
Permanent targetPermanent = game.getPermanent(source.getTargets().get(1).getFirstTarget());
if (targetPermanent != null) {
targetPermanent.addCounters(CounterType.GLYPH.createInstance(targetPermanent.getPower().getValue()), source, game);
SimpleStaticAbility ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepSourceEffect(),
new SourceHasCounterCondition(CounterType.GLYPH)).setText("This creature doesnt untap during your untap step if it has a glyph counter on it"));
GainAbilityTargetEffect effect = new GainAbilityTargetEffect(ability, Duration.Custom);
effect.setTargetPointer(new FixedTarget(targetPermanent.getId()));
game.addEffect(effect, source);
BeginningOfUpkeepTriggeredAbility ability2 = new BeginningOfUpkeepTriggeredAbility(new RemoveCounterSourceEffect(CounterType.GLYPH.createInstance()),
TargetController.YOU, false);
GainAbilityTargetEffect effect2 = new GainAbilityTargetEffect(ability2, Duration.Custom);
effect2.setTargetPointer(new FixedTarget(targetPermanent.getId()));
game.addEffect(effect2, source);
}
}
return false;
}
}

View file

@ -1,7 +1,5 @@
package mage.cards.g;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.cards.CardImpl;
@ -11,8 +9,9 @@ import mage.filter.StaticFilters;
import mage.filter.common.FilterLandCard;
import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID;
/**
*
* @author North
*/
public final class GrimDiscovery extends CardImpl {
@ -27,11 +26,11 @@ public final class GrimDiscovery extends CardImpl {
this.getSpellAbility().getModes().setMaxModes(2);
// Return target creature card from your graveyard to your hand;
this.getSpellAbility().addEffect(new ReturnToHandTargetEffect());
this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD));
this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD).withChooseHint("return to hand"));
// and/or return target land card from your graveyard to your hand.
Mode mode1 = new Mode();
mode1.addEffect(new ReturnToHandTargetEffect());
mode1.addTarget(new TargetCardInYourGraveyard(filterLandCard));
mode1.addTarget(new TargetCardInYourGraveyard(filterLandCard).withChooseHint("return to hand"));
this.getSpellAbility().addMode(mode1);
}

View file

@ -0,0 +1,135 @@
package mage.cards.i;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.Effect;
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.WatcherScope;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.stack.Spell;
import mage.target.targetpointer.FixedTarget;
import mage.watchers.Watcher;
/**
*
* @author L_J
*/
public final class IchneumonDruid extends CardImpl {
public IchneumonDruid(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{G}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.DRUID);
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// Whenever an opponent casts an instant spell other than the first instant spell that player casts each turn, Ichneumon Druid deals 4 damage to that player.
this.addAbility(new IchneumonDruidAbility(), new IchneumonDruidWatcher());
}
public IchneumonDruid(final IchneumonDruid card) {
super(card);
}
@Override
public IchneumonDruid copy() {
return new IchneumonDruid(this);
}
}
class IchneumonDruidAbility extends TriggeredAbilityImpl {
public IchneumonDruidAbility() {
super(Zone.BATTLEFIELD, new DamageTargetEffect(new StaticValue(4), false, "that player", true));
}
public IchneumonDruidAbility(final IchneumonDruidAbility ability) {
super(ability);
}
@Override
public IchneumonDruidAbility copy() {
return new IchneumonDruidAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == EventType.SPELL_CAST;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (!event.getPlayerId().equals(controllerId)) {
Spell spell = game.getStack().getSpell(event.getTargetId());
if (spell != null && spell.isInstant()) {
IchneumonDruidWatcher watcher = (IchneumonDruidWatcher) game.getState().getWatchers().get(IchneumonDruidWatcher.class.getSimpleName());
if (watcher != null && watcher.moreThanTwoInstantsCast(event.getPlayerId(), game)) {
for (Effect effect : getEffects()) {
effect.setTargetPointer(new FixedTarget(event.getPlayerId()));
}
return true;
}
}
}
return false;
}
@Override
public String getRule() {
return "Whenever an opponent casts an instant spell other than the first instant spell that player casts each turn, {this} deals 4 damage to that player.";
}
}
class IchneumonDruidWatcher extends Watcher {
private final Map<UUID, Integer> playerInstantCount = new HashMap<>();
public IchneumonDruidWatcher() {
super(IchneumonDruidWatcher.class.getSimpleName(), WatcherScope.GAME);
}
public IchneumonDruidWatcher(final IchneumonDruidWatcher watcher) {
super(watcher);
for (Map.Entry<UUID, Integer> entry : watcher.playerInstantCount.entrySet()) {
playerInstantCount.put(entry.getKey(), entry.getValue());
}
}
@Override
public IchneumonDruidWatcher copy() {
return new IchneumonDruidWatcher(this);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == EventType.SPELL_CAST) {
UUID playerId = event.getPlayerId();
Spell spell = game.getStack().getSpell(event.getTargetId());
if (spell != null && spell.isInstant()) {
playerInstantCount.putIfAbsent(event.getPlayerId(), 0);
playerInstantCount.compute(playerId, (k, v) -> v + 1);
}
}
}
public boolean moreThanTwoInstantsCast(UUID playerId, Game game) {
return playerInstantCount.get(playerId) > 1;
}
@Override
public void reset() {
playerInstantCount.clear();
}
}

View file

@ -1,4 +1,3 @@
package mage.cards.i;
import java.util.UUID;
@ -39,7 +38,7 @@ public final class ImprisonedInTheMoon extends CardImpl {
}
public ImprisonedInTheMoon(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}");
this.subtype.add(SubType.AURA);
// Enchant creature, land, or planeswalker
@ -87,10 +86,18 @@ class BecomesColorlessLandEffect extends ContinuousEffectImpl {
@Override
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
Permanent enchantment = game.getPermanent(source.getSourceId());
if (enchantment != null && enchantment.getAttachedTo() != null) {
if (enchantment != null
&& enchantment.getAttachedTo() != null) {
Permanent permanent = game.getPermanent(enchantment.getAttachedTo());
if (permanent != null) {
switch (layer) {
case TypeChangingEffects_4:
// 305.7 Note that this doesn't remove any abilities that were granted to the land by other effects
// So the ability removing has to be done before Layer 6
permanent.removeAllAbilities(source.getSourceId(), game);
permanent.getCardType().clear();
permanent.addCardType(CardType.LAND);
break;
case ColorChangingEffects_5:
permanent.getColor(game).setWhite(false);
permanent.getColor(game).setGreen(false);
@ -102,14 +109,6 @@ class BecomesColorlessLandEffect extends ContinuousEffectImpl {
permanent.removeAllAbilities(source.getSourceId(), game);
permanent.addAbility(new ColorlessManaAbility(), source.getSourceId(), game);
break;
case TypeChangingEffects_4:
boolean isLand = permanent.isLand();
permanent.getCardType().clear();
permanent.addCardType(CardType.LAND);
if (!isLand) {
permanent.getSubtype(game).clear();
}
break;
}
return true;
}
@ -119,6 +118,8 @@ class BecomesColorlessLandEffect extends ContinuousEffectImpl {
@Override
public boolean hasLayer(Layer layer) {
return layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.ColorChangingEffects_5 || layer == Layer.TypeChangingEffects_4;
return layer == Layer.AbilityAddingRemovingEffects_6
|| layer == Layer.ColorChangingEffects_5
|| layer == Layer.TypeChangingEffects_4;
}
}

View file

@ -34,7 +34,7 @@ public final class IncubationIncongruity extends SplitCard {
new StaticValue(1), StaticFilters.FILTER_CARD_CREATURE_A,
Zone.LIBRARY, false, true, false,
Zone.HAND, false, false, false
));
).setBackInRandomOrder(true));
// Incongruity
// Exile target creature. That creature's controller creates a 3/3 green Frog Lizard creature token.

View file

@ -50,7 +50,8 @@ public final class KessDissidentMage extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// During each of your turns, you may cast an instant or sorcery card from your graveyard. If a card cast this way would be put into your graveyard this turn, exile it instead.
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new KessDissidentMageCastFromGraveyardEffect());
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD,
new KessDissidentMageCastFromGraveyardEffect());
ability.addEffect(new KessDissidentMageReplacementEffect());
this.addAbility(ability, new KessDissidentMageWatcher());
}
@ -88,13 +89,18 @@ class KessDissidentMageCastFromGraveyardEffect extends AsThoughEffectImpl {
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
if (!(source instanceof FlashbackAbility) && affectedControllerId.equals(source.getControllerId()) && game.isActivePlayer(source.getControllerId())) {
if (!(source instanceof FlashbackAbility)
&& affectedControllerId.equals(source.getControllerId())
&& game.isActivePlayer(source.getControllerId())) {
Card card = game.getCard(objectId);
if (card != null && (card.isInstant() || card.isSorcery())
if (card != null
&& (card.isInstant()
|| card.isSorcery())
&& game.getState().getZone(objectId).equals(Zone.GRAVEYARD)) {
// check if not already a card was cast this turn with this ability
KessDissidentMageWatcher watcher = game.getState().getWatcher(KessDissidentMageWatcher.class);
return watcher != null && !watcher.isAbilityUsed(new MageObjectReference(source.getSourceId(), game));
return watcher != null
&& !watcher.isAbilityUsed(new MageObjectReference(source.getSourceId(), game));
}
}
return false;
@ -121,9 +127,9 @@ class KessDissidentMageReplacementEffect extends ReplacementEffectImpl {
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
Card card = game.getCard(event.getTargetId());
if (controller != null && card != null) {
controller.moveCards(card, Zone.EXILED, source, game);
return true;
if (controller != null
&& card != null) {
return controller.moveCards(card, Zone.EXILED, source, game);
}
return false;
}
@ -138,9 +144,9 @@ class KessDissidentMageReplacementEffect extends ReplacementEffectImpl {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.getToZone() == Zone.GRAVEYARD) {
KessDissidentMageWatcher watcher = game.getState().getWatcher(KessDissidentMageWatcher.class);
if (watcher != null && source.getSourceId().equals(watcher.spellCastWasAllowedBy(new MageObjectReference(event.getTargetId(), game)))) {
return true;
}
return (watcher != null
&& source.getSourceId().equals(watcher.spellCastWasAllowedBy(
new MageObjectReference(event.getTargetId(), game))));
}
return false;
}
@ -164,11 +170,16 @@ class KessDissidentMageWatcher extends Watcher {
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.SPELL_CAST && event.getZone() == Zone.GRAVEYARD) {
if (event.getType() == GameEvent.EventType.SPELL_CAST
&& event.getZone() == Zone.GRAVEYARD) {
Spell spell = (Spell) game.getObject(event.getTargetId());
if (null != event.getAdditionalReference() && spell.isInstant() || spell.isSorcery()) {
if (event.getAdditionalReference() != null
&& event.getAdditionalReference().getSourceId() != null
&& spell.isInstant()
|| spell.isSorcery()) {
allowingObjects.add(event.getAdditionalReference());
castSpells.put(new MageObjectReference(spell.getSourceId(), game), event.getAdditionalReference().getSourceId());
castSpells.put(new MageObjectReference(spell.getSourceId(), game),
event.getAdditionalReference().getSourceId());
}
}
}

View file

@ -0,0 +1,120 @@
package mage.cards.k;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnFromExileForSourceEffect;
import mage.abilities.effects.common.discard.DiscardHandControllerEffect;
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.ExileZone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.util.CardUtil;
/**
*
* @author emerald000 & L_J
*/
public final class KnowledgeVault extends CardImpl {
public KnowledgeVault(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
// {2}, {T}: Exile the top card of your library face down.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new KnowledgeVaultExileEffect(), new GenericManaCost(2)));
// {0}: Sacrifice Knowledge Vault. If you do, discard your hand, then put all cards exiled with Knowledge Vault into their owners hand.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new KnowledgeVaultReturnEffect(), new GenericManaCost(0)));
// When Knowledge Vault leaves the battlefield, put all cards exiled with Knowledge Vault into their owners graveyard.
this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.GRAVEYARD), false));
}
public KnowledgeVault(final KnowledgeVault card) {
super(card);
}
@Override
public KnowledgeVault copy() {
return new KnowledgeVault(this);
}
}
class KnowledgeVaultExileEffect extends OneShotEffect {
KnowledgeVaultExileEffect() {
super(Outcome.Exile);
this.staticText = "exile the top card of your library face down";
}
KnowledgeVaultExileEffect(final KnowledgeVaultExileEffect effect) {
super(effect);
}
@Override
public KnowledgeVaultExileEffect copy() {
return new KnowledgeVaultExileEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game);
if (controller != null && sourceObject != null) {
Card card = controller.getLibrary().getFromTop(game);
if (card != null) {
UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
card.setFaceDown(true, game);
controller.moveCardsToExile(card, source, game, false, exileZoneId, sourceObject.getIdName());
card.setFaceDown(true, game);
return true;
}
}
return false;
}
}
class KnowledgeVaultReturnEffect extends OneShotEffect {
KnowledgeVaultReturnEffect() {
super(Outcome.DrawCard);
this.staticText = "Sacrifice {this}. If you do, discard your hand, then put all cards exiled with {this} into their owners' hands";
}
KnowledgeVaultReturnEffect(final KnowledgeVaultReturnEffect effect) {
super(effect);
}
@Override
public KnowledgeVaultReturnEffect copy() {
return new KnowledgeVaultReturnEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
Player controller = game.getPlayer(source.getControllerId());
if (sourcePermanent != null && controller != null) {
if (sourcePermanent.sacrifice(source.getSourceId(), game)) {
new DiscardHandControllerEffect().apply(game, source);
ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()));
if (exileZone != null) {
controller.moveCards(exileZone, Zone.HAND, source, game);
}
}
return true;
}
return false;
}
}

View file

@ -0,0 +1,51 @@
package mage.cards.l;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.condition.common.IsStepCondition;
import mage.abilities.costs.common.RemoveCountersSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.decorator.ConditionalActivatedAbility;
import mage.abilities.effects.common.RegenerateSourceEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author L_J
*/
public final class LifeMatrix extends CardImpl {
public LifeMatrix(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
// {4}, {T}: Put a matrix counter on target creature and that creature gains Remove a matrix counter from this creature: Regenerate this creature. Activate this ability only during your upkeep.
Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.MATRIX.createInstance()), new GenericManaCost(4),
new IsStepCondition(PhaseStep.UPKEEP), null);
Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new RemoveCountersSourceCost(CounterType.MATRIX.createInstance()));
ability.addEffect(new GainAbilityTargetEffect(ability2, Duration.Custom));
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
public LifeMatrix(final LifeMatrix card) {
super(card);
}
@Override
public LifeMatrix copy() {
return new LifeMatrix(this);
}
}

View file

@ -1,7 +1,6 @@
package mage.cards.l;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
@ -16,22 +15,18 @@ import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.SubtypePredicate;
import java.util.UUID;
/**
*
* @author jonubuu
*/
public final class LordOfAtlantis extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Merfolk creatures");
static {
filter.add(new SubtypePredicate(SubType.MERFOLK));
}
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.MERFOLK, "Merfolk");
public LordOfAtlantis(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{U}{U}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{U}");
this.subtype.add(SubType.MERFOLK);
this.power = new MageInt(2);
@ -39,7 +34,7 @@ public final class LordOfAtlantis extends CardImpl {
// Other Merfolk creatures get +1/+1 and have islandwalk.
Effect effect = new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter, true);
effect.setText("Other Merfolk creatures get +1/+1");
effect.setText("Other Merfolk get +1/+1");
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect);
effect = new GainAbilityAllEffect(new IslandwalkAbility(), Duration.WhileOnBattlefield, filter, true);
effect.setText("and have islandwalk");

View file

@ -12,7 +12,10 @@ import mage.abilities.keyword.HasteAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
@ -82,11 +85,9 @@ class MacabreMockeryEffect extends OneShotEffect {
effect = new BoostTargetEffect(2, 0, Duration.EndOfTurn);
effect.setTargetPointer(new FixedTarget(permanent, game));
game.addEffect(effect, source);
Effect sacrificeEffect = new SacrificeTargetEffect("exile " + permanent.getLogName());
Effect sacrificeEffect = new SacrificeTargetEffect("sacrifice " + permanent.getLogName(), controller.getId());
sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game));
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(
sacrificeEffect, TargetController.YOU
), source);
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect), source);
return true;
}
}

View file

@ -1,7 +1,6 @@
package mage.cards.m;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTappedAbility;
import mage.abilities.common.SimpleActivatedAbility;
@ -18,6 +17,8 @@ import mage.constants.CardType;
import mage.constants.Zone;
import mage.filter.common.FilterCreatureCard;
import java.util.UUID;
/**
* @author Rystan
*/
@ -34,7 +35,7 @@ public final class MemorialToUnity extends CardImpl {
// {2}{G}, {T}, Sacrifice Memorial to Unity: Look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand. Then put the rest on the bottom of your library in a random order.
Effect effect = new LookLibraryAndPickControllerEffect(
new StaticValue(5), false, new StaticValue(1), new FilterCreatureCard("a creature card"), false, true
);
).setBackInRandomOrder(true);
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{2}{G}"));
ability.addCost(new TapSourceCost());

View file

@ -1,4 +1,3 @@
package mage.cards.p;
import java.util.Arrays;
@ -86,7 +85,7 @@ class ParallelThoughtsSearchEffect extends OneShotEffect {
}
}
// 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);
@ -96,16 +95,15 @@ class ParallelThoughtsSearchEffect extends OneShotEffect {
}
cardsInExilePile.clear();
cardsInExilePile.addAll(Arrays.asList(shuffled));
// move to exile zone and turn face down
String exileName = permanent.getIdName() + " (" + game.getState().getZoneChangeCounter(source.getSourceId()) + ")";
for (Card card : cardsInExilePile.getCards(game)) {
controller.moveCardsToExile(card, source, game, false, CardUtil.getCardExileZoneId(game, source), permanent.getLogName());
controller.moveCardsToExile(card, source, game, false, CardUtil.getCardExileZoneId(game, source), exileName);
card.setFaceDown(true, game);
}
// shuffle controller library
controller.shuffleLibrary(source, game);
}
return true;
@ -118,7 +116,7 @@ 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";
staticText = "If you would draw a card, you may instead put the top card of the pile you exiled with {this} into your hand";
}
ParallelThoughtsReplacementEffect(final ParallelThoughtsReplacementEffect effect) {
@ -135,12 +133,15 @@ class ParallelThoughtsReplacementEffect extends ReplacementEffectImpl {
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);
if (controller.chooseUse(outcome, "Draw a card from the pile you exiled instead drawing from your library?", source, game)) {
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;
}
}
return true;
return false;
}
@Override

View file

@ -1,7 +1,5 @@
package mage.cards.r;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.cards.CardImpl;
@ -11,31 +9,31 @@ import mage.target.common.TargetArtifactPermanent;
import mage.target.common.TargetEnchantmentPermanent;
import mage.target.common.TargetLandPermanent;
/**
*
* @author noxx
import java.util.UUID;
/**
* @author noxx
*/
public final class RainOfThorns extends CardImpl {
public RainOfThorns(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{G}{G}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}{G}");
// Choose one or more - Destroy target artifact; destroy target enchantment; and/or destroy target land.
this.getSpellAbility().addEffect(new DestroyTargetEffect());
this.getSpellAbility().addTarget(new TargetArtifactPermanent());
this.getSpellAbility().addTarget(new TargetArtifactPermanent().withChooseHint("destroy"));
this.getSpellAbility().getModes().setMaxModes(1);
this.getSpellAbility().getModes().setMaxModes(3);
Mode mode1 = new Mode();
mode1.addEffect(new DestroyTargetEffect());
mode1.addTarget(new TargetEnchantmentPermanent());
mode1.addTarget(new TargetEnchantmentPermanent().withChooseHint("destroy"));
this.getSpellAbility().addMode(mode1);
Mode mode2 = new Mode();
mode2.addEffect(new DestroyTargetEffect());
mode2.addTarget(new TargetLandPermanent());
mode2.addTarget(new TargetLandPermanent().withChooseHint("destroy"));
this.getSpellAbility().addMode(mode2);
}

View file

@ -80,9 +80,12 @@ class RegalBehemothTriggeredManaAbility extends TriggeredManaAbility {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (isControlledBy(game.getMonarchId())) {
if (game.getMonarchId() != null
&& isControlledBy(game.getMonarchId())) {
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId());
if (permanent != null && filter.match(permanent, getSourceId(), getControllerId(), game)) {
if (permanent != null
&& getControllerId() != null
&& filter.match(permanent, getSourceId(), getControllerId(), game)) {
ManaEvent mEvent = (ManaEvent) event;
for (Effect effect : getEffects()) {
effect.setValue("mana", mEvent.getMana());

View file

@ -1,7 +1,5 @@
package mage.cards.r;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.cards.CardImpl;
@ -11,8 +9,9 @@ import mage.filter.StaticFilters;
import mage.filter.common.FilterArtifactCard;
import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID;
/**
*
* @author North
*/
public final class RememberTheFallen extends CardImpl {
@ -28,12 +27,12 @@ public final class RememberTheFallen extends CardImpl {
// Return target creature card from your graveyard to your hand.
this.getSpellAbility().addEffect(new ReturnToHandTargetEffect());
this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD));
this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD).withChooseHint("return to hand"));
// Return target artifact card from your graveyard to your hand.
Mode mode = new Mode();
mode.addEffect(new ReturnToHandTargetEffect());
mode.addTarget(new TargetCardInYourGraveyard(filterArtifact));
mode.addTarget(new TargetCardInYourGraveyard(filterArtifact).withChooseHint("return to hand"));
this.getSpellAbility().addMode(mode);
}

View file

@ -1,33 +1,27 @@
package mage.cards.r;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.predicate.permanent.ControllerPredicate;
import mage.filter.predicate.permanent.TokenPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class Remembrance extends CardImpl {
@ -39,7 +33,7 @@ public final class Remembrance extends CardImpl {
this.addAbility(new RemembranceTriggeredAbility());
}
public Remembrance(final Remembrance card) {
private Remembrance(final Remembrance card) {
super(card);
}
@ -51,19 +45,17 @@ public final class Remembrance extends CardImpl {
class RemembranceTriggeredAbility extends TriggeredAbilityImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature you control");
private static final FilterPermanent filter = new FilterControlledCreaturePermanent();
static {
filter.add(new ControllerPredicate(TargetController.YOU));
filter.add(Predicates.not(TokenPredicate.instance));
}
public RemembranceTriggeredAbility() {
super(Zone.BATTLEFIELD, new RemembranceEffect());
this.optional = true;
RemembranceTriggeredAbility() {
super(Zone.BATTLEFIELD, null, true);
}
public RemembranceTriggeredAbility(final RemembranceTriggeredAbility ability) {
private RemembranceTriggeredAbility(final RemembranceTriggeredAbility ability) {
super(ability);
}
@ -79,55 +71,26 @@ class RemembranceTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD
&& ((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD) {
Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD);
MageObject mageObject = game.getObject(sourceId);
if (permanent != null
&& filter.match(permanent, game)) {
game.getState().setValue(mageObject + "nameOfPermanent", permanent.getName());
return true;
}
if (!((ZoneChangeEvent) event).isDiesEvent()) {
return false;
}
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId());
if (permanent != null && filter.match(permanent, game)) {
FilterCard filterCard = new FilterCard("card named " + permanent.getName());
filterCard.add(new NamePredicate(permanent.getName()));
this.getEffects().clear();
this.addEffect(new SearchLibraryPutInHandEffect(
new TargetCardInLibrary(filterCard), true, true
));
return true;
}
return false;
}
@Override
public String getRule() {
return "Whenever a nontoken creature you control dies, you may search your library for a card with the same name as that creature, reveal it, and put it into your hand. If you do, shuffle your library.";
}
}
class RemembranceEffect extends OneShotEffect {
private String cardName;
RemembranceEffect() {
super(Outcome.Benefit);
}
RemembranceEffect(final RemembranceEffect effect) {
super(effect);
}
@Override
public RemembranceEffect copy() {
return new RemembranceEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject mageObject = game.getObject(source.getSourceId());
if(mageObject != null) {
cardName = (String) game.getState().getValue(mageObject + "nameOfPermanent");
if (controller != null
&& cardName != null) {
FilterCard filterCard = new FilterCard("card named " + cardName);
filterCard.add(new NamePredicate(cardName));
return new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filterCard), true, true).apply(game, source);
}
}
return false;
return "Whenever a nontoken creature you control dies, " +
"you may search your library for a card with the same name as that creature, " +
"reveal it, and put it into your hand. If you do, shuffle your library.";
}
}

View file

@ -25,9 +25,9 @@ import mage.watchers.common.PlayerLostLifeWatcher;
*
* @author Styxo
*/
public final class Revenge extends CardImpl {
public final class RevengeStarWars extends CardImpl {
public Revenge(UUID ownerId, CardSetInfo setInfo) {
public RevengeStarWars(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}");
// Target creature you control gets +4/+0 until end of turn before it fights if you lost life this turn.
@ -45,13 +45,13 @@ public final class Revenge extends CardImpl {
}
public Revenge(final Revenge card) {
public RevengeStarWars(final RevengeStarWars card) {
super(card);
}
@Override
public Revenge copy() {
return new Revenge(this);
public RevengeStarWars copy() {
return new RevengeStarWars(this);
}
}

View file

@ -1,7 +1,5 @@
package mage.cards.r;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect;
import mage.cards.CardImpl;
@ -12,8 +10,9 @@ import mage.filter.StaticFilters;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class RevivingMelody extends CardImpl {
@ -33,11 +32,11 @@ public final class RevivingMelody extends CardImpl {
//Return target creature card from your graveyard to your hand;
this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect());
this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD));
this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD).withChooseHint("return to hand"));
// and/or return target enchantment card from your graveyard to your hand.
Mode mode = new Mode();
mode.addEffect(new ReturnFromGraveyardToHandTargetEffect());
mode.addTarget(new TargetCardInYourGraveyard(filterCard));
mode.addTarget(new TargetCardInYourGraveyard(filterCard).withChooseHint("return to hand"));
this.getSpellAbility().addMode(mode);
}

View file

@ -1,8 +1,5 @@
package mage.cards.r;
import java.util.UUID;
import mage.abilities.common.EntersBattlefieldTappedAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
@ -12,21 +9,24 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import java.util.UUID;
/**
*
* @author Loki, North
*/
public final class RuptureSpire extends CardImpl {
public RuptureSpire (UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.LAND},null);
public RuptureSpire(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.LAND}, null);
this.addAbility(new EntersBattlefieldTappedAbility());
this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ManaCostsImpl("{1}")), false));
this.addAbility(new EntersBattlefieldTriggeredAbility(
new SacrificeSourceUnlessPaysEffect(new ManaCostsImpl("{1}")).setText("sacrifice it unless you pay {1}")
));
this.addAbility(new AnyColorManaAbility());
}
public RuptureSpire (final RuptureSpire card) {
public RuptureSpire(final RuptureSpire card) {
super(card);
}

View file

@ -1,7 +1,5 @@
package mage.cards.s;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.effects.common.CreateTokenCopyTargetEffect;
import mage.cards.CardImpl;
@ -10,30 +8,31 @@ import mage.constants.CardType;
import mage.target.common.TargetArtifactPermanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class SaheelisArtistry extends CardImpl {
public SaheelisArtistry(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{U}{U}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{U}{U}");
// Choose one or both
this.getSpellAbility().getModes().setMinModes(1);
this.getSpellAbility().getModes().setMaxModes(2);
// Create a token that's a copy of target artifact.
this.getSpellAbility().addTarget(new TargetArtifactPermanent());
CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect();
effect.setText("Create a token that's a copy of target artifact");
this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetArtifactPermanent().withChooseHint("create copy of that"));
// Create a token that's a copy of target creature, except that it's an artifact in addition to its other types.
Mode mode1 = new Mode();
mode1.addTarget(new TargetCreaturePermanent());
effect = new CreateTokenCopyTargetEffect();
effect.setBecomesArtifact(true);
effect.setText("Create a token that's a copy of target creature, except that it's an artifact in addition to its other types");
mode1.addEffect(effect);
mode1.addTarget(new TargetCreaturePermanent().withChooseHint("create copy of that, artifact type"));
this.getSpellAbility().addMode(mode1);
}

View file

@ -1,8 +1,5 @@
package mage.cards.s;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.costs.mana.GenericManaCost;
@ -29,22 +26,24 @@ import mage.players.Player;
import mage.target.TargetPlayer;
import mage.target.common.TargetCreaturePermanent;
import java.util.List;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class SavageAlliance extends CardImpl {
private static final FilterPlayer filterPlayer = new FilterPlayer("player whose creatures gain trample");
private static final FilterCreaturePermanent filterCreature = new FilterCreaturePermanent("creature to deal 2 damage to");
private static final FilterPlayer filterOpponent = new FilterPlayer("opponent whose creatures get dealt damage");
private static final FilterPlayer filterPlayer = new FilterPlayer();
private static final FilterCreaturePermanent filterCreature = new FilterCreaturePermanent();
private static final FilterPlayer filterOpponent = new FilterPlayer();
static {
filterOpponent.add(new PlayerPredicate(TargetController.OPPONENT));
}
public SavageAlliance(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{R}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}");
// Escalate {1}
this.addAbility(new EscalateAbility(new GenericManaCost(1)));
@ -55,20 +54,20 @@ public final class SavageAlliance extends CardImpl {
// Creatures target player controls gain trample until end of turn.
this.getSpellAbility().addEffect(new SavageAllianceGainTrampleEffect());
this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterPlayer));
this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterPlayer).withChooseHint("whose creatures gain trample"));
// Savage Alliance deals 2 damage to target creature.;
Mode mode = new Mode();
Effect effect = new DamageTargetEffect(2);
effect.setText("{this} deals 2 damage to target creature");
mode.addEffect(effect);
mode.addTarget(new TargetCreaturePermanent(filterCreature));
mode.addTarget(new TargetCreaturePermanent(filterCreature).withChooseHint("deals 2 damage to"));
this.getSpellAbility().addMode(mode);
// Savage Alliance deals 1 damage to each creature target opponent controls.
mode = new Mode();
mode.addEffect(new SavageAllianceDamageEffect());
mode.addTarget(new TargetPlayer(1, 1, false, filterOpponent));
mode.addTarget(new TargetPlayer(1, 1, false, filterOpponent).withChooseHint("whose creatures get dealt 1 damage"));
this.getSpellAbility().addMode(mode);
}

View file

@ -22,7 +22,7 @@ public final class ShimmerOfPossibility extends CardImpl {
this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(
new StaticValue(4), false, new StaticValue(1), StaticFilters.FILTER_CARD, Zone.LIBRARY,
false, false, false, Zone.HAND, false, false, false
));
).setBackInRandomOrder(true));
}
private ShimmerOfPossibility(final ShimmerOfPossibility card) {

View file

@ -42,7 +42,7 @@ public final class SilhanaWayfinder extends CardImpl {
this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect(
new StaticValue(4), false, new StaticValue(1), filter, Zone.LIBRARY, false,
true, true, Zone.LIBRARY, false, true, false
).setText("look at the top four cards of your library. " +
).setBackInRandomOrder(true).setText("look at the top four cards of your library. " +
"You may reveal a creature or land card from among them " +
"and put it on top of your library. Put the rest " +
"on the bottom of your library in a random order."), false

View file

@ -1,27 +1,32 @@
package mage.cards.s;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.VariableCost;
import mage.abilities.costs.mana.VariableManaCost;
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.Outcome;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.FilterMana;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetAnyTarget;
import java.util.UUID;
/**
* @author Johnny E. Hastings
*/
public final class SoulBurn extends CardImpl {
static final FilterMana filterBlackOrRed = new FilterMana();
private static final FilterMana filterBlackOrRed = new FilterMana();
static {
filterBlackOrRed.setBlack(true);
@ -29,9 +34,13 @@ public final class SoulBurn extends CardImpl {
}
public SoulBurn(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{2}{B}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{2}{B}");
// Spend only black or red mana on X.
this.addAbility(new SimpleStaticAbility(
Zone.ALL, new InfoEffect("Spend only black or red mana on X")).setRuleAtTheTop(true)
);
// Soul Burn deals X damage to any target. You gain life equal to the damage dealt for each black mana spent on X; not more life than the player's life total before Soul Burn dealt damage, or the creature's toughness.
this.getSpellAbility().addTarget(new TargetAnyTarget());
this.getSpellAbility().addEffect(new SoulBurnEffect());
@ -41,7 +50,7 @@ public final class SoulBurn extends CardImpl {
}
}
public SoulBurn(final SoulBurn card) {
private SoulBurn(final SoulBurn card) {
super(card);
}
@ -53,33 +62,35 @@ public final class SoulBurn extends CardImpl {
class SoulBurnEffect extends OneShotEffect {
public SoulBurnEffect() {
SoulBurnEffect() {
super(Outcome.Damage);
staticText = "{this} deals X damage to any target for each black or red mana spent on X. You gain life equal to the damage dealt for each black mana spent; not more life than the player's life total before Soul Burn dealt damage, or the creature's toughness.";
staticText = "{this} deals X damage to any target. You gain life equal to the damage dealt, " +
"but not more than the amount of {B} spent on X, the players life total before the damage was dealt, " +
"the planeswalkers loyalty before the damage was dealt, or the creatures toughness.";
}
public SoulBurnEffect(final SoulBurnEffect effect) {
private SoulBurnEffect(final SoulBurnEffect effect) {
super(effect);
}
/***
* @param game
* @param source
* @return
* @return
*/
@Override
public boolean apply(Game game, Ability source) {
// Get the colors we care about. (This isn't racist, honestly.)
int amountBlack = source.getManaCostsToPay().getPayment().getBlack();
int amountRed = source.getManaCostsToPay().getPayment().getRed();
// Get the colors we don't really care about. (See note above.)
int amountWhite = source.getManaCostsToPay().getPayment().getWhite();
int amountGreen = source.getManaCostsToPay().getPayment().getGreen();
int amountBlue = source.getManaCostsToPay().getPayment().getBlue();
int amountColorless = source.getManaCostsToPay().getPayment().getColorless();
// Figure out what was spent on the spell in total, determine proper values for
// black and red, minus initial casting cost.
int totalColorlessForCastingCost = amountWhite + amountGreen + amountBlue + amountColorless;
@ -90,17 +101,17 @@ class SoulBurnEffect extends OneShotEffect {
// The game should never let this happen, but I'll check anyway since I don't know
// the guts of the game [yet].
amountOffsetByColorless = 2;
}
}
}
// Remove 1 black to account for casting cost.
amountBlack--;
// Determine if we need to offset the red or black values any further due to the
// amount of non-red and non-black paid.
if (amountOffsetByColorless < 2) {
int amountToOffsetBy = 2 - amountOffsetByColorless;
if (amountRed > 0) {
if (amountRed >= amountToOffsetBy) {
// Pay all additional unpaid casting cost with red.
@ -118,35 +129,36 @@ class SoulBurnEffect extends OneShotEffect {
amountBlack = amountBlack - amountToOffsetBy;
}
}
int totalXAmount = amountBlack + amountRed;
int lifetogain = amountBlack;
if (totalXAmount > 0) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null ) {
if (permanent.getToughness().getValue() < lifetogain) {
lifetogain = permanent.getToughness().getValue();
}
permanent.damage(totalXAmount, source.getSourceId(), game, false, true);
} else {
Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
if (player != null) {
if (player.getLife() < lifetogain) {
lifetogain = player.getLife();
}
player.damage(totalXAmount, source.getSourceId(), game, false, true);
} else {
return false;
}
}
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
controller.gainLife(lifetogain, game, source);
if (totalXAmount == 0) {
return false;
}
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null) {
if (permanent.isCreature()) {
lifetogain = Math.min(permanent.getToughness().getValue(), lifetogain);
} else if (permanent.isPlaneswalker()) {
lifetogain = Math.min(permanent.getCounters(game).getCount(CounterType.LOYALTY), lifetogain);
} else {
return false;
}
permanent.damage(totalXAmount, source.getSourceId(), game);
} else {
Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
if (player == null) {
return false;
}
lifetogain = Math.min(player.getLife(), lifetogain);
player.damage(totalXAmount, source.getSourceId(), game);
}
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
controller.gainLife(lifetogain, game, source);
return true;
}

View file

@ -1,7 +1,5 @@
package mage.cards.s;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.effects.common.CounterTargetEffect;
import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect;
@ -12,8 +10,9 @@ import mage.filter.StaticFilters;
import mage.target.TargetSpell;
import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
public final class SoulManipulation extends CardImpl {
@ -27,12 +26,12 @@ public final class SoulManipulation extends CardImpl {
// Counter target creature spell;
this.getSpellAbility().addEffect(new CounterTargetEffect());
this.getSpellAbility().addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_CREATURE));
this.getSpellAbility().addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_CREATURE).withChooseHint("counter it"));
// and/or return target creature card from your graveyard to your hand.
Mode mode = new Mode();
mode.addEffect(new ReturnFromGraveyardToHandTargetEffect());
mode.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD));
mode.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD).withChooseHint("return it to hand"));
this.getSpellAbility().addMode(mode);
}

View file

@ -1,7 +1,6 @@
package mage.cards.s;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.ruleModifying.TargetsHaveToTargetPermanentIfAbleEffect;
@ -9,11 +8,10 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class StandardBearer extends CardImpl {
@ -27,7 +25,7 @@ public final class StandardBearer extends CardImpl {
this.toughness = new MageInt(1);
// While choosing targets as part of casting a spell or activating an ability, your opponents must choose at least one Flagbearer on the battlefield if able.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TargetsHaveToTargetPermanentIfAbleEffect(new FilterPermanent(SubType.FLAGBEARER, "one Flagbearer"))));
this.addAbility(new SimpleStaticAbility(new TargetsHaveToTargetPermanentIfAbleEffect()));
}
public StandardBearer(final StandardBearer card) {

View file

@ -1,7 +1,5 @@
package mage.cards.s;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
@ -12,14 +10,15 @@ import mage.constants.Duration;
import mage.counters.CounterType;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class SubtleStrike extends CardImpl {
public SubtleStrike(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}");
// Choose one or both
this.getSpellAbility().getModes().setMinModes(1);
@ -28,15 +27,14 @@ public final class SubtleStrike extends CardImpl {
BoostTargetEffect minusOneMinusOne = new BoostTargetEffect(-1, -1, Duration.EndOfTurn);
minusOneMinusOne.setText("Target creature gets -1/-1 until end of turn");
this.getSpellAbility().addEffect(minusOneMinusOne);
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("gets -1/-1 until end of turn"));
// Put a +1/+1 counter on target creature.
Mode mode1 = new Mode();
AddCountersTargetEffect plusOnePlusOneCounter = new AddCountersTargetEffect(CounterType.P1P1.createInstance());
plusOnePlusOneCounter.setText("Put a +1/+1 counter on target creature");
mode1.addEffect(plusOnePlusOneCounter);
mode1.addTarget(new TargetCreaturePermanent());
mode1.addTarget(new TargetCreaturePermanent().withChooseHint("gets +1/+1 counter"));
this.getSpellAbility().addMode(mode1);
}
public SubtleStrike(final SubtleStrike card) {

View file

@ -1,6 +1,5 @@
package mage.cards.s;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.dynamicvalue.common.StaticValue;
@ -14,8 +13,9 @@ import mage.filter.FilterCard;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class SumalaWoodshaper extends CardImpl {
@ -40,8 +40,9 @@ public final class SumalaWoodshaper extends CardImpl {
// When Sumala Woodshaper enters the battlefield, look at the top four cards of your library. You may reveal a creature or enchantment card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.
this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect(
new StaticValue(4), false, new StaticValue(1), filter, Zone.LIBRARY, false, true, false, Zone.HAND, false, false, false
), false));
new StaticValue(4), false, new StaticValue(1), filter, Zone.LIBRARY, false,
true, false, Zone.HAND, false, false, false
).setBackInRandomOrder(true), false));
}
public SumalaWoodshaper(final SumalaWoodshaper card) {

View file

@ -21,14 +21,14 @@ public final class SwirlingTorrent extends CardImpl {
// Choose one or both
this.getSpellAbility().getModes().setMinModes(1);
this.getSpellAbility().getModes().setMaxModes(2);
// Put target creature on top of its owner's library.
this.getSpellAbility().addEffect(new PutOnLibraryTargetEffect(true));
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("put on library top"));
// Return target creature to its owner's hand.
Mode mode = new Mode(new ReturnToHandTargetEffect());
mode.addTarget(new TargetCreaturePermanent());
mode.addTarget(new TargetCreaturePermanent().withChooseHint("return to hand"));
this.getSpellAbility().addMode(mode);
}

View file

@ -1,39 +1,33 @@
package mage.cards.t;
import java.util.UUID;
import mage.abilities.effects.common.continuous.BoostAllEffect;
import mage.abilities.effects.common.continuous.GainAbilityAllEffect;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.abilities.keyword.ReachAbility;
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.permanent.ControllerPredicate;
import java.util.UUID;
/**
*
* @author Plopman
*/
public final class TowerDefense extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures you control");
static {
filter.add(new ControllerPredicate(TargetController.YOU));
}
public TowerDefense(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{G}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}");
// Creatures you control get +0/+5 and gain reach until end of turn.
this.getSpellAbility().addEffect(new BoostAllEffect(0, 5, Duration.EndOfTurn, filter , false));
this.getSpellAbility().addEffect(new GainAbilityAllEffect(ReachAbility.getInstance(), Duration.EndOfTurn, filter));
this.getSpellAbility().addEffect(new BoostControlledEffect(
0, 5, Duration.EndOfTurn
).setText("creatures you control get +0/+5"));
this.getSpellAbility().addEffect(new GainAbilityControlledEffect(
ReachAbility.getInstance(), Duration.EndOfTurn
).setText("and gain reach until end of turn"));
}
public TowerDefense(final TowerDefense card) {
private TowerDefense(final TowerDefense card) {
super(card);
}

View file

@ -1,7 +1,5 @@
package mage.cards.t;
import java.util.UUID;
import mage.abilities.common.EntersBattlefieldTappedAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.costs.mana.GenericManaCost;
@ -11,18 +9,24 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import java.util.UUID;
/**
* @author LevelX2
*/
public final class TransguildPromenade extends CardImpl {
public TransguildPromenade(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// Transguild Promenade enters the battlefield tapped.
this.addAbility(new EntersBattlefieldTappedAbility());
// When Transguild Promenade enters the battlefield, sacrifice it unless you pay {1}.
this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new GenericManaCost(1))));
this.addAbility(new EntersBattlefieldTriggeredAbility(
new SacrificeSourceUnlessPaysEffect(new GenericManaCost(1)).setText("sacrifice it unless you pay {1}")
));
// {T}: Add one mana of any color.
this.addAbility(new AnyColorManaAbility());
}

View file

@ -0,0 +1,609 @@
package mage.cards.u;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.LoyaltyAbility;
import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility;
import mage.abilities.dynamicvalue.common.ControllerLifeCount;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.dynamicvalue.common.PermanentsTargetOpponentControlsCount;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.DamageAllControlledTargetEffect;
import mage.abilities.effects.common.DamageAllEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.DestroyAllControlledTargetEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.ExileFromZoneTargetEffect;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.GetEmblemEffect;
import mage.abilities.effects.common.LookLibraryAndPickControllerEffect;
import mage.abilities.effects.common.LoseLifeSourceControllerEffect;
import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect;
import mage.abilities.effects.common.PutLibraryIntoGraveTargetEffect;
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
import mage.abilities.effects.common.RevealLibraryPutIntoHandEffect;
import mage.abilities.effects.common.SacrificeEffect;
import mage.abilities.effects.common.ShuffleHandGraveyardAllEffect;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.counter.DistributeCountersEffect;
import mage.abilities.effects.common.discard.DiscardControllerEffect;
import mage.abilities.effects.common.discard.DiscardTargetEffect;
import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
import mage.abilities.effects.common.turn.ControlTargetPlayerNextTurnEffect;
import mage.abilities.keyword.FirstStrikeAbility;
import mage.abilities.keyword.LifelinkAbility;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.choices.Choice;
import mage.choices.ChoiceImpl;
import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterArtifactCard;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterControlledLandPermanent;
import mage.filter.common.FilterCreatureCard;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.common.FilterLandPermanent;
import mage.filter.common.FilterPermanentCard;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.filter.predicate.permanent.ControllerPredicate;
import mage.game.Game;
import mage.game.command.emblems.AjaniSteadfastEmblem;
import mage.game.command.emblems.DomriRadeEmblem;
import mage.game.command.emblems.ElspethKnightErrantEmblem;
import mage.game.command.emblems.GideonAllyOfZendikarEmblem;
import mage.game.command.emblems.KioraMasterOfTheDepthsEmblem;
import mage.game.command.emblems.VenserTheSojournerEmblem;
import mage.game.permanent.token.*;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetPermanent;
import mage.target.TargetPlayer;
import mage.target.common.TargetAnyTarget;
import mage.target.common.TargetCardInGraveyard;
import mage.target.common.TargetCardInHand;
import mage.target.common.TargetCardInLibrary;
import mage.target.common.TargetCreaturePermanent;
import mage.target.common.TargetCreaturePermanentAmount;
import mage.target.common.TargetNonlandPermanent;
import mage.target.common.TargetOpponent;
import mage.target.common.TargetPlayerOrPlaneswalker;
import mage.util.RandomUtil;
/**
*
* @author L_J
*/
public final class UrzaAcademyHeadmaster extends CardImpl {
public UrzaAcademyHeadmaster(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{W}{U}{B}{R}{G}");
this.addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.URZA);
this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4));
// +1: Head to AskUrza.com and click +1.
this.addAbility(new LoyaltyAbility(new UrzaAcademyHeadmasterRandomEffect(1, setInfo), 1));
// -1: Head to AskUrza.com and click -1.
this.addAbility(new LoyaltyAbility(new UrzaAcademyHeadmasterRandomEffect(2, setInfo), -1));
// -6: Head to AskUrza.com and click -6.
this.addAbility(new LoyaltyAbility(new UrzaAcademyHeadmasterRandomEffect(3, setInfo), -6));
}
public UrzaAcademyHeadmaster(final UrzaAcademyHeadmaster card) {
super(card);
}
@Override
public UrzaAcademyHeadmaster copy() {
return new UrzaAcademyHeadmaster(this);
}
}
class UrzaAcademyHeadmasterRandomEffect extends OneShotEffect {
private int selection;
private CardSetInfo setInfo;
private static final FilterCreaturePermanent filter1 = new FilterCreaturePermanent("creatures you control");
private static final FilterPermanent filter2 = new FilterPermanent("noncreature permanent");
private static final FilterCard filter3 = new FilterCard("creature and/or land cards");
private static final FilterPermanent filter4 = new FilterPermanent("creatures and/or planeswalkers");
static {
filter1.add(new ControllerPredicate(TargetController.YOU));
filter2.add(Predicates.not(new CardTypePredicate(CardType.CREATURE)));
filter3.add(Predicates.or(
new CardTypePredicate(CardType.CREATURE),
new CardTypePredicate(CardType.LAND)));
filter4.add(Predicates.or(
new CardTypePredicate(CardType.CREATURE),
new CardTypePredicate(CardType.PLANESWALKER)));
}
public UrzaAcademyHeadmasterRandomEffect(int selection, CardSetInfo setInfo) {
super(Outcome.Neutral);
this.selection = selection;
this.setInfo = setInfo;
switch (selection) {
case 1:
staticText = "Head to AskUrza.com and click +1";
break;
case 2:
staticText = "Head to AskUrza.com and click -1";
break;
case 3:
staticText = "Head to AskUrza.com and click -6";
}
}
public UrzaAcademyHeadmasterRandomEffect(final UrzaAcademyHeadmasterRandomEffect effect) {
super(effect);
this.selection = effect.selection;
this.setInfo = effect.setInfo;
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
int result = RandomUtil.nextInt(20) + 1;
List<Effect> effects = new ArrayList<>();
Target target = null;
StringBuilder sb = new StringBuilder("[URZA] ");
while (true) {
switch (selection) {
// ABILITY +1
case 1:
switch (result) {
case 1: // AJANI STEADFAST 1
sb.append("Until end of turn, up to one target creature gets +1/+1 and gains first strike, vigilance, and lifelink.");
effects.add(new BoostTargetEffect(1, 1, Duration.EndOfTurn));
effects.add(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn));
effects.add(new GainAbilityTargetEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn));
effects.add(new GainAbilityTargetEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn));
target = new TargetCreaturePermanent(0, 1);
break;
case 2: // AJANI MENTOR OF HEROES 1
sb.append("Distribute three +1/+1 counters among one, two, or three target creatures you control.");
effects.add(new DistributeCountersEffect(CounterType.P1P1, 3, false, "one, two, or three target creatures you control"));
target = new TargetCreaturePermanentAmount(3, filter1);
break;
case 3: // NICOL BOLAS PLANESWALKER 1
sb.append("Destroy target noncreature permanent.");
effects.add(new DestroyTargetEffect());
target = new TargetPermanent(filter2);
break;
case 4: // CHANDRA FLAMECALLER 1
sb.append("Create two 3/1 red Elemental creature tokens with haste. Exile them at the beginning of the next end step.");
effects.add(new mage.cards.c.ChandraFlamecaller(controller.getId(), setInfo).getAbilities().get(2).getEffects().get(0));
break;
case 5: // ELSPETH SUNS CHAMPION 1
sb.append("Create three 1/1 white Soldier creature tokens.");
effects.add(new CreateTokenEffect(new SoldierToken(), 3));
break;
case 6: // GARRUK APEX PREDATOR 2
sb.append("Create a 3/3 black Beast creature token with deathtouch.");
effects.add(new CreateTokenEffect(new GarrukApexPredatorBeastToken()));
break;
case 7: // GARRUK CALLER OF BEASTS 1
sb.append("Reveal the top five cards of your library. Put all creature cards revealed this way into your hand and the rest on the bottom of your library in any order.");
effects.add(new RevealLibraryPutIntoHandEffect(5, new FilterCreatureCard("creature cards"), Zone.LIBRARY));
break;
case 8: // GIDEON JURA 1
sb.append("During target opponents next turn, creatures that player controls attack Urza if able.");
effects.add(new mage.cards.g.GideonJura(controller.getId(), setInfo).getAbilities().get(2).getEffects().get(0));
target = new TargetOpponent();
break;
case 9: // GIDEON CHAMPION OF JUSTICE 1
sb.append("Put a loyalty counter on Urza for each creature target opponent controls.");
effects.add(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(0), new PermanentsTargetOpponentControlsCount(new FilterCreaturePermanent()), true));
target = new TargetOpponent();
break;
case 10: // JACE ARCHITECT OF THOUGHT 1
sb.append("Until your next turn, whenever a creature an opponent controls attacks, it gets -1/-0 until end of turn.");
effects.add(new mage.cards.j.JaceArchitectOfThought(controller.getId(), setInfo).getAbilities().get(2).getEffects().get(0));
break;
case 11: // KARN LIBERATED 1
sb.append("Target player exiles a card from his or her hand.");
effects.add(new ExileFromZoneTargetEffect(Zone.HAND, null, "", new FilterCard()));
target = new TargetPlayer();
break;
case 12: // NISSA SAGE ANIMIST 1
sb.append("Reveal the top card of your library. If its a land card, put it onto the battlefield. Otherwise, put it into your hand.");
effects.add(new mage.cards.n.NissaSageAnimist(controller.getId(), setInfo).getAbilities().get(2).getEffects().get(0));
break;
case 13: // NISSA WORLDWAKER 1
sb.append("Target land you control becomes a 4/4 Elemental creature with trample. Its still a land.");
effects.add(new mage.cards.n.NissaWorldwaker(controller.getId(), setInfo).getAbilities().get(2).getEffects().get(0));
target = new TargetPermanent(new FilterControlledLandPermanent());
break;
case 14: // SARKHAN UNBROKEN 1
sb.append("Draw a card, then add one mana of any color to your mana pool.");
effects.add(new mage.cards.s.SarkhanUnbroken(controller.getId(), setInfo).getAbilities().get(2).getEffects().get(0));
break;
case 15: // SARKHAN THE DRAGONSPEAKER 1
sb.append("Until end of turn, Urza becomes a legendary 4/4 red Dragon creature with flying, indestructible, and haste. (He doesnt lose loyalty while hes not a planeswalker.)");
effects.add(new mage.cards.s.SarkhanTheDragonspeaker(controller.getId(), setInfo).getAbilities().get(2).getEffects().get(0));
break;
case 16: // SORIN SOLEMN VISITOR 1
sb.append("Until your next turn, creatures you control get +1/+0 and gain lifelink.");
effects.add(new BoostControlledEffect(1, 0, Duration.UntilYourNextTurn, StaticFilters.FILTER_PERMANENT_CREATURES));
effects.add(new GainAbilityControlledEffect(LifelinkAbility.getInstance(), Duration.UntilYourNextTurn, StaticFilters.FILTER_PERMANENT_CREATURES));
break;
case 17: // TEZZERET AGENT OF BOLAS 1
sb.append("Look at the top five cards of your library. You may reveal an artifact card from among them and put it into your hand. Put the rest on the bottom of your library in any order.");
effects.add(new LookLibraryAndPickControllerEffect(5, 1, new FilterArtifactCard(), true));
break;
case 18: // UGIN 1
sb.append("Urza deals 3 damage to any target.");
effects.add(new DamageTargetEffect(3));
target = new TargetAnyTarget();
break;
case 19: // VRASKA 1
sb.append("Until your next turn, whenever a creature deals combat damage to Urza, destroy that creature.");
effects.add(new mage.cards.v.VraskaTheUnseen(controller.getId(), setInfo).getAbilities().get(2).getEffects().get(0));
break;
case 20: // (altered) XENAGOS 1
sb.append("Add X mana in any combination of colors to your mana pool, where X is the number of creatures you control.");
effects.add(new UrzaAcademyHeadmasterManaEffect());
}
break;
// ABILITY -1
case 2:
switch (result) {
case 1: // (altered) CHANDRA FLAMECALLER 3
sb.append("Urza deals 3 damage to each creature.");
effects.add(new DamageAllEffect(3, StaticFilters.FILTER_PERMANENT_CREATURE));
break;
case 2: // NICOL BOLAS PLANESWALKER 2
sb.append("Gain control of target creature.");
effects.add(new GainControlTargetEffect(Duration.Custom));
target = new TargetCreaturePermanent();
break;
case 3: // (double) SORIN MARKOV 1
sb.append("Urza deals 4 damage to target creature or player and you gain 4 life.");
effects.add(new DamageTargetEffect(4));
effects.add(new GainLifeEffect(4));
target = new TargetAnyTarget();
break;
case 4: // GARRUK APEX PREDATOR 3
sb.append("Destroy target creature. You gain life equal to its toughness.");
effects.add(new DestroyTargetEffect());
effects.add(new mage.cards.g.GarrukApexPredator(controller.getId(), setInfo).getAbilities().get(4).getEffects().get(1));
target = new TargetCreaturePermanent();
break;
case 5: // GIDEON ALLY OF ZENDIKAR 3
sb.append("You get an emblem with “Creatures you control get +1/+1.”");
effects.add(new GetEmblemEffect(new GideonAllyOfZendikarEmblem()));
break;
case 6: // (altered) GARRUK CALLER OF BEASTS 2
sb.append("You may put a creature card from your hand onto the battlefield.");
effects.add(new PutCardFromHandOntoBattlefieldEffect(new FilterCreatureCard()));
break;
case 7: // (altered) JACE THE MIND SCULPTOR 2
sb.append("Draw three cards, then put a card from your hand on top of your library.");
effects.add(new UrzaAcademyHeadmasterBrainstormEffect());
break;
case 8: // JACE MEMORY ADEPT 2
sb.append("Target player puts the top ten cards of his or her library into his or her graveyard.");
effects.add(new PutLibraryIntoGraveTargetEffect(10));
target = new TargetPlayer();
break;
case 9: // JACE ARCHITECT OF THOUGHT 2
sb.append("Reveal the top five cards of your library. An opponent separates those cards into two piles. Put one pile into your hand and the other on the bottom of your library in any order.");
effects.add(new mage.cards.j.JaceArchitectOfThought(controller.getId(), setInfo).getAbilities().get(3).getEffects().get(0));
break;
case 10: // KARN LIBERATED 2
sb.append("Exile target permanent.");
effects.add(new ExileTargetEffect());
target = new TargetPermanent();
break;
case 11: // (altered) GARRUK CALLER OF BEASTS 1
sb.append("Reveal the top five cards of your library. You may put all creature cards and/or land cards from among them into your hand. Put the rest into your graveyard.");
effects.add(new RevealLibraryPutIntoHandEffect(5, filter3, Zone.LIBRARY));
break;
case 12: // (altered) LILIANA VESS 2
sb.append("Search your library for a card and put that card into your hand. Then shuffle your library.");
effects.add(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(new FilterCard("a card")), false, true));
break;
case 13: // (double) LILIANA OF THE VEIL 2
sb.append("Target player sacrifices two creatures.");
effects.add(new SacrificeEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 2, "Target player"));
target = new TargetPlayer();
break;
case 14: // OB NIXILIS OF THE BLACK OATH 2
sb.append("Create a 5/5 black Demon creature token with flying. You lose 2 life.");
effects.add(new CreateTokenEffect(new DemonToken()));
effects.add(new LoseLifeSourceControllerEffect(2));
break;
case 15: // (gold) SARKHAN UNBROKEN 2
sb.append("Create a 4/4 gold Dragon creature token with flying.");
effects.add(new CreateTokenEffect(new DragonTokenGold(), 1));
break;
case 16: // SORIN MARKOV 2
sb.append("Target players life total becomes 10.");
effects.add(new mage.cards.s.SorinMarkov(controller.getId(), setInfo).getAbilities().get(3).getEffects().get(0));
target = new TargetPlayer();
break;
case 17: // VRASKA 2
sb.append("Destroy target nonland permanent.");
effects.add(new DestroyTargetEffect());
target = new TargetNonlandPermanent();
break;
case 18: // UNIQUE
sb.append("Return target permanent from a graveyard to the battlefield under your control.");
effects.add(new ReturnFromGraveyardToBattlefieldTargetEffect());
target = new TargetCardInGraveyard(new FilterPermanentCard());
break;
case 19: // (double) GARRUK WILDSPEAKER 2
sb.append("Create two 3/3 green Beast creature tokens.");
effects.add(new CreateTokenEffect(new BeastToken(), 2));
break;
case 20: // UNIQUE
sb.append("Draw four cards and discard two cards.");
effects.add(new DrawCardSourceControllerEffect(4));
effects.add(new DiscardControllerEffect(2));
}
break;
// ABILITY -6
case 3:
switch (result) {
case 1: // NICOL BOLAS PLANESWALKER 3
sb.append("Urza deals 7 damage to target player. That player discards seven cards, then sacrifices seven permanents.");
effects.add(new DamageTargetEffect(7));
effects.add(new DiscardTargetEffect(7));
effects.add(new SacrificeEffect(new FilterPermanent(), 7, "then"));
target = new TargetPlayerOrPlaneswalker();
break;
case 2: // AJANI STEADFAST 3
sb.append("You get an emblem with “If a source would deal damage to you or a planeswalker you control, prevent all but 1 of that damage.”");
effects.add(new GetEmblemEffect(new AjaniSteadfastEmblem()));
break;
case 3: // AJANI VENGEANT 3
sb.append("Destroy all lands target player controls.");
effects.add(new DestroyAllControlledTargetEffect(new FilterLandPermanent()));
target = new TargetPlayer();
break;
case 4: // AJANI CALLER OF THE PRIDE 3
sb.append("Create X 2/2 white Cat creature tokens, where X is your life total.");
effects.add(new CreateTokenEffect(new CatToken(), ControllerLifeCount.instance));
break;
case 5: // AJANI MENTOR OF HEROES 3
sb.append("You gain 100 life.");
effects.add(new GainLifeEffect(100));
break;
case 6: // CHANDRA NALAAR 3
sb.append("Urza deals 10 damage to target player and each creature he or she controls.");
effects.add(new DamageTargetEffect(10));
effects.add(new DamageAllControlledTargetEffect(10, new FilterCreaturePermanent()));
target = new TargetPlayerOrPlaneswalker();
break;
case 7: // DOMRI RADE 3
sb.append("You get an emblem with “Creatures you control have double strike, trample, hexproof, and haste.”");
effects.add(new GetEmblemEffect(new DomriRadeEmblem()));
break;
case 8: // ELSPETH KNIGHT ERRANT 3
sb.append("You get an emblem with “Artifacts, creatures, enchantments, and lands you control have indestructible.”");
effects.add(new GetEmblemEffect(new ElspethKnightErrantEmblem()));
break;
case 9: // GARRUK PRIMAL HUNTER 3
sb.append("Create a 6/6 green Wurm creature token for each land you control.");
effects.add(new CreateTokenEffect(new WurmToken(), new PermanentsOnBattlefieldCount(new FilterControlledLandPermanent())));
break;
case 10: // JACE THE LIVING GUILDPACT 3
sb.append("Each player shuffles his or her hand and graveyard into his or her library. You draw seven cards.");
effects.add(new ShuffleHandGraveyardAllEffect());
effects.add(new DrawCardSourceControllerEffect(7));
break;
case 11: // SORIN LORD OF INNISTRAD 3
sb.append("Destroy up to three target creatures and/or other planeswalkers. Return each card put into a graveyard this way to the battlefield under your control.");
effects.add(new mage.cards.s.SorinLordOfInnistrad(controller.getId(), setInfo).getAbilities().get(4).getEffects().get(0));
target = new TargetPermanent(0, 3, filter4, false);
break;
case 12: // VENSER 3
sb.append("You get an emblem with “Whenever you cast a spell, exile target permanent.”");
effects.add(new GetEmblemEffect(new VenserTheSojournerEmblem()));
break;
case 13: // KIORA MASTER OF THE DEPTHS 3
sb.append("You get an emblem with “Whenever a creature enters the battlefield under your control, you may have it fight target creature.” Then create three 8/8 blue Octopus creature tokens.");
effects.add(new CreateTokenEffect(new OctopusToken(), 3));
effects.add(new GetEmblemEffect(new KioraMasterOfTheDepthsEmblem()));
break;
case 14: // SORIN MARKOV 3
sb.append("You control target player during that players next turn.");
effects.add(new ControlTargetPlayerNextTurnEffect());
target = new TargetPlayer();
break;
case 15: // JACE THE MIND SCULPTOR 4
sb.append("Exile all cards from target players library, then that player shuffles his or her hand into his or her library.");
effects.add(new mage.cards.j.JaceTheMindSculptor(controller.getId(), setInfo).getAbilities().get(5).getEffects().get(0));
target = new TargetPlayer();
break;
case 16: // VRASKA 3
sb.append("Create three 1/1 black Assassin creature tokens with “Whenever this creature deals combat damage to a player, that player loses the game.”");
effects.add(new CreateTokenEffect(new AssassinToken()));
break;
case 17: // LILIANA VESS 3
sb.append("Put all creature cards from all graveyards onto the battlefield under your control.");
effects.add(new mage.cards.l.LilianaVess(controller.getId(), setInfo).getAbilities().get(4).getEffects().get(0));
break;
case 18: // NISSA VOICE OF ZENDIKAR 3
sb.append("You gain X life and draw X cards, where X is the number of lands you control.");
effects.add(new GainLifeEffect(new PermanentsOnBattlefieldCount(new FilterControlledLandPermanent())));
effects.add(new DrawCardSourceControllerEffect(new PermanentsOnBattlefieldCount(new FilterControlledLandPermanent())));
break;
case 19: // RAL ZAREK 3
sb.append("Flip five coins. Take an extra turn after this one for each coin that comes up heads.");
effects.add(new mage.cards.r.RalZarek(controller.getId(), setInfo).getAbilities().get(4).getEffects().get(0));
break;
case 20: // UGIN 3
sb.append("You gain 7 life, draw seven cards, then put up to seven permanent cards from your hand onto the battlefield.");
effects.add(new mage.cards.u.UginTheSpiritDragonEffect3());
}
}
game.informPlayers(sb.toString());
if (target != null) {
if (target.canChoose(source.getSourceId(), controller.getId(), game) && controller.canRespond()) {
target.chooseTarget(outcome, controller.getId(), source, game);
} else {
// 1/19/2018 (...) If the ability that comes up requires a target and there are no legal targets available, click again until thats not true.
game.informPlayers("[URZA] Target can't be chosen, picking next ability...");
result = RandomUtil.nextInt(20) + 1;
effects.clear();
target = null;
sb = new StringBuilder("[URZA] ");
continue;
}
source.addTarget(target);
}
if (target == null || target.isChosen()) {
for (Effect effect : effects) {
if (effect instanceof ContinuousEffect) {
game.addEffect((ContinuousEffect) effect, source);
} else {
effect.apply(game, source);
}
}
return true;
}
break;
}
}
return false;
}
@Override
public UrzaAcademyHeadmasterRandomEffect copy() {
return new UrzaAcademyHeadmasterRandomEffect(this);
}
}
class UrzaAcademyHeadmasterManaEffect extends OneShotEffect {
public UrzaAcademyHeadmasterManaEffect() {
super(Outcome.PutManaInPool);
}
public UrzaAcademyHeadmasterManaEffect(final UrzaAcademyHeadmasterManaEffect effect) {
super(effect);
}
@Override
public UrzaAcademyHeadmasterManaEffect copy() {
return new UrzaAcademyHeadmasterManaEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
int x = game.getBattlefield().count(new FilterControlledCreaturePermanent(), source.getSourceId(), source.getControllerId(), game);
Choice manaChoice = new ChoiceImpl();
Set<String> choices = new LinkedHashSet<>();
choices.add("White");
choices.add("Blue");
choices.add("Black");
choices.add("Red");
choices.add("Green");
manaChoice.setChoices(choices);
manaChoice.setMessage("Select color of mana to add");
for (int i = 0; i < x; i++) {
Mana mana = new Mana();
if (!player.choose(Outcome.Benefit, manaChoice, game)) {
return false;
}
if (manaChoice.getChoice() == null) { // can happen if player leaves game
return false;
}
switch (manaChoice.getChoice()) {
case "White":
mana.increaseWhite();
break;
case "Blue":
mana.increaseBlue();
break;
case "Black":
mana.increaseBlack();
break;
case "Red":
mana.increaseRed();
break;
case "Green":
mana.increaseGreen();
break;
}
player.getManaPool().addMana(mana, game, source);
}
return true;
}
return false;
}
}
class UrzaAcademyHeadmasterBrainstormEffect extends OneShotEffect {
public UrzaAcademyHeadmasterBrainstormEffect() {
super(Outcome.DrawCard);
staticText = "draw three cards, then put a card from your hand on top of your library";
}
public UrzaAcademyHeadmasterBrainstormEffect(final UrzaAcademyHeadmasterBrainstormEffect effect) {
super(effect);
}
@Override
public UrzaAcademyHeadmasterBrainstormEffect copy() {
return new UrzaAcademyHeadmasterBrainstormEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
player.drawCards(3, game);
putOnLibrary(player, source, game);
return true;
}
return false;
}
private boolean putOnLibrary(Player player, Ability source, Game game) {
TargetCardInHand target = new TargetCardInHand();
if (target.canChoose(source.getSourceId(), player.getId(), game)) {
player.chooseTarget(Outcome.ReturnToHand, target, source, game);
Card card = player.getHand().get(target.getFirstTarget(), game);
if (card != null) {
return player.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.HAND, true, false);
}
}
return false;
}
}

View file

@ -1,7 +1,5 @@
package mage.cards.v;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.cards.CardImpl;
@ -10,25 +8,26 @@ import mage.constants.CardType;
import mage.target.common.TargetArtifactPermanent;
import mage.target.common.TargetLandPermanent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class Vandalize extends CardImpl {
public Vandalize(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{R}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{R}");
// Choose one or both - Destroy target artifact; or Destroy target land.
this.getSpellAbility().getModes().setMinModes(1);
this.getSpellAbility().getModes().setMaxModes(2);
this.getSpellAbility().addTarget(new TargetArtifactPermanent());
// Destroy target artifact
this.getSpellAbility().addEffect(new DestroyTargetEffect());
this.getSpellAbility().addTarget(new TargetArtifactPermanent().withChooseHint("destroy"));
// Destroy target land
Mode mode1 = new Mode();
mode1.addTarget(new TargetLandPermanent());
mode1.addEffect(new DestroyTargetEffect());
mode1.addTarget(new TargetLandPermanent().withChooseHint("destroy"));
this.getSpellAbility().addMode(mode1);
}

View file

@ -1,6 +1,6 @@
package mage.cards.v;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.costs.common.DiscardXTargetCost;
import mage.abilities.effects.Effect;
@ -9,15 +9,12 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterAttackingCreature;
import mage.game.Game;
import mage.target.Target;
import mage.target.TargetPermanent;
import mage.target.targetadjustment.TargetAdjuster;
import java.util.UUID;
/**
* @author fireshoes
*/
@ -48,11 +45,10 @@ public final class VengefulDreams extends CardImpl {
enum VengefulDreamsAdjuster implements TargetAdjuster {
instance;
private static final FilterPermanent filter = new FilterAttackingCreature();
@Override
public void adjustTargets(Ability ability, Game game) {
Target target = new TargetPermanent(0, ability.getManaCostsToPay().getX(), filter, false);
Target target = new TargetPermanent(ability.getCosts().getVariableCosts().get(0).getAmount(), new FilterAttackingCreature());
ability.addTarget(target);
}
}
}

View file

@ -1,7 +1,5 @@
package mage.cards.v;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.Mode;
@ -19,8 +17,9 @@ import mage.filter.predicate.mageobject.AnotherTargetPredicate;
import mage.target.Target;
import mage.target.common.TargetOpponent;
import java.util.UUID;
/**
*
* @author anonymous
*/
public final class VindictiveLich extends CardImpl {
@ -33,37 +32,37 @@ public final class VindictiveLich extends CardImpl {
this.toughness = new MageInt(1);
// When Vindictive Lich dies, choose one or more. Each mode must target a different player.
// *Target opponent sacrifices a creature.
// * Target opponent sacrifices a creature.
Ability ability = new DiesTriggeredAbility(new SacrificeEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 1, "target opponent"));
ability.getModes().setMinModes(1);
ability.getModes().setMaxModes(3);
ability.getModes().setEachModeOnlyOnce(true);
ability.getModes().setMaxModesFilter(new FilterOpponent("a different player"));
FilterOpponent filter = new FilterOpponent("opponent (sacrifice)");
FilterOpponent filter = new FilterOpponent();
filter.add(new AnotherTargetPredicate(1, true));
Target target = new TargetOpponent(filter, false);
Target target = new TargetOpponent(filter, false).withChooseHint("who sacrifice a creature");
target.setTargetTag(1);
ability.addTarget(target);
// *Target opponent discards two cards.
// * Target opponent discards two cards.
Mode mode = new Mode();
mode.addEffect(new DiscardTargetEffect(2, false));
filter = new FilterOpponent("opponent (discard)");
filter = new FilterOpponent();
filter.add(new AnotherTargetPredicate(2, true));
target = new TargetOpponent(filter, false);
target.setTargetTag(2);
mode.addTarget(target);
mode.addTarget(target.withChooseHint("who discard a card"));
ability.addMode(mode);
// *Target opponent loses 5 life.
// * Target opponent loses 5 life.
mode = new Mode();
mode.addEffect(new LoseLifeTargetEffect(5));
filter = new FilterOpponent("opponent (life loss)");
filter = new FilterOpponent();
filter.add(new AnotherTargetPredicate(3, true));
target = new TargetOpponent(filter, false);
target.setTargetTag(3);
mode.addTarget(target);
mode.addTarget(target.withChooseHint("who lose 5 life"));
ability.addMode(mode);
this.addAbility(ability);
}

View file

@ -1,24 +1,24 @@
package mage.cards.w;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.common.LookLibraryAndPickControllerEffect;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.CrewAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.HistoricPredicate;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class Weatherlight extends CardImpl {
@ -44,9 +44,11 @@ public final class Weatherlight extends CardImpl {
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(
new LookLibraryAndPickControllerEffect(
new StaticValue(5), false, new StaticValue(1), filter,
Zone.LIBRARY, false, true, false, Zone.HAND, true, false, false
), false
Zone.LIBRARY, false, true, false, Zone.HAND,
true, false, false
).setBackInRandomOrder(true), false
));
// Crew 3
this.addAbility(new CrewAbility(3));
}

View file

@ -1,7 +1,5 @@
package mage.cards.w;
import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.TapTargetEffect;
@ -10,26 +8,27 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class Winterflame extends CardImpl {
public Winterflame(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}{R}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}{R}");
// Choose one or both -
this.getSpellAbility().getModes().setMinModes(1);
this.getSpellAbility().getModes().setMaxModes(2);
// *Tap target creature
// * Tap target creature
this.getSpellAbility().addEffect(new TapTargetEffect());
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
// *Winterflame deals 2 damage to target creature
this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("tap"));
// * Winterflame deals 2 damage to target creature
Mode mode = new Mode();
mode.addEffect(new DamageTargetEffect(2));
mode.addTarget(new TargetCreaturePermanent());
mode.addTarget(new TargetCreaturePermanent().withChooseHint("deals 2 damage to"));
this.getSpellAbility().addMode(mode);
}

View file

@ -119,6 +119,7 @@ public final class Legends extends ExpansionSet {
cards.add(new SetCardInfo("Giant Slug", 99, Rarity.COMMON, mage.cards.g.GiantSlug.class));
cards.add(new SetCardInfo("Giant Strength", 149, Rarity.COMMON, mage.cards.g.GiantStrength.class));
cards.add(new SetCardInfo("Giant Turtle", 188, Rarity.COMMON, mage.cards.g.GiantTurtle.class));
cards.add(new SetCardInfo("Glyph of Delusion", 60, Rarity.COMMON, mage.cards.g.GlyphOfDelusion.class));
cards.add(new SetCardInfo("Glyph of Destruction", 150, Rarity.COMMON, mage.cards.g.GlyphOfDestruction.class));
cards.add(new SetCardInfo("Glyph of Doom", 100, Rarity.COMMON, mage.cards.g.GlyphOfDoom.class));
cards.add(new SetCardInfo("Glyph of Life", 15, Rarity.COMMON, mage.cards.g.GlyphOfLife.class));
@ -145,6 +146,7 @@ public final class Legends extends ExpansionSet {
cards.add(new SetCardInfo("Horror of Horrors", 106, Rarity.UNCOMMON, mage.cards.h.HorrorOfHorrors.class));
cards.add(new SetCardInfo("Hunding Gjornersen", 231, Rarity.UNCOMMON, mage.cards.h.HundingGjornersen.class));
cards.add(new SetCardInfo("Hyperion Blacksmith", 152, Rarity.UNCOMMON, mage.cards.h.HyperionBlacksmith.class));
cards.add(new SetCardInfo("Ichneumon Druid", 191, Rarity.UNCOMMON, mage.cards.i.IchneumonDruid.class));
cards.add(new SetCardInfo("Immolation", 153, Rarity.COMMON, mage.cards.i.Immolation.class));
cards.add(new SetCardInfo("Imprison", 107, Rarity.RARE, mage.cards.i.Imprison.class));
cards.add(new SetCardInfo("In the Eye of Chaos", 61, Rarity.RARE, mage.cards.i.InTheEyeOfChaos.class));
@ -165,6 +167,7 @@ public final class Legends extends ExpansionSet {
cards.add(new SetCardInfo("Kei Takahashi", 238, Rarity.RARE, mage.cards.k.KeiTakahashi.class));
cards.add(new SetCardInfo("Killer Bees", 192, Rarity.RARE, mage.cards.k.KillerBees.class));
cards.add(new SetCardInfo("Kismet", 25, Rarity.UNCOMMON, mage.cards.k.Kismet.class));
cards.add(new SetCardInfo("Knowledge Vault", 281, Rarity.RARE, mage.cards.k.KnowledgeVault.class));
cards.add(new SetCardInfo("Kobold Drill Sergeant", 154, Rarity.UNCOMMON, mage.cards.k.KoboldDrillSergeant.class));
cards.add(new SetCardInfo("Kobold Overlord", 155, Rarity.RARE, mage.cards.k.KoboldOverlord.class));
cards.add(new SetCardInfo("Kobold Taskmaster", 156, Rarity.UNCOMMON, mage.cards.k.KoboldTaskmaster.class));
@ -178,6 +181,7 @@ public final class Legends extends ExpansionSet {
cards.add(new SetCardInfo("Land's Edge", 158, Rarity.RARE, mage.cards.l.LandsEdge.class));
cards.add(new SetCardInfo("Lesser Werewolf", 110, Rarity.UNCOMMON, mage.cards.l.LesserWerewolf.class));
cards.add(new SetCardInfo("Life Chisel", 283, Rarity.UNCOMMON, mage.cards.l.LifeChisel.class));
cards.add(new SetCardInfo("Life Matrix", 284, Rarity.RARE, mage.cards.l.LifeMatrix.class));
cards.add(new SetCardInfo("Lifeblood", 27, Rarity.RARE, mage.cards.l.Lifeblood.class));
cards.add(new SetCardInfo("Living Plane", 193, Rarity.RARE, mage.cards.l.LivingPlane.class));
cards.add(new SetCardInfo("Livonya Silone", 242, Rarity.RARE, mage.cards.l.LivonyaSilone.class));

View file

@ -269,7 +269,7 @@ public final class StarWars extends ExpansionSet {
cards.add(new SetCardInfo("Repurpose", 85, Rarity.COMMON, mage.cards.r.Repurpose.class));
cards.add(new SetCardInfo("Resistance", 310, Rarity.UNCOMMON, mage.cards.r.Resistance.class));
cards.add(new SetCardInfo("Resistance Bomber", 515, Rarity.UNCOMMON, mage.cards.r.ResistanceBomber.class));
cards.add(new SetCardInfo("Revenge", 117, Rarity.COMMON, mage.cards.r.Revenge.class));
cards.add(new SetCardInfo("Revenge", 117, Rarity.COMMON, mage.cards.r.RevengeStarWars.class));
cards.add(new SetCardInfo("Rey", 410, Rarity.RARE, mage.cards.r.Rey.class));
cards.add(new SetCardInfo("Riding Ronto", 28, Rarity.UNCOMMON, mage.cards.r.RidingRonto.class));
cards.add(new SetCardInfo("Riot Trooper", 411, Rarity.COMMON, mage.cards.r.RiotTrooper.class));

View file

@ -76,6 +76,7 @@ public final class Unstable extends ExpansionSet {
cards.add(new SetCardInfo("Target Minotaur", "98d", Rarity.COMMON, mage.cards.t.TargetMinotaur.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Big Idea", 76, Rarity.RARE, mage.cards.t.TheBigIdea.class));
cards.add(new SetCardInfo("Time Out", 48, Rarity.COMMON, mage.cards.t.TimeOut.class));
cards.add(new SetCardInfo("Urza, Academy Headmaster", 136, Rarity.MYTHIC, mage.cards.u.UrzaAcademyHeadmaster.class));
cards.add(new SetCardInfo("Very Cryptic Command", "49d", Rarity.RARE, mage.cards.v.VeryCrypticCommandD.class));
cards.add(new SetCardInfo("Willing Test Subject", 126, Rarity.COMMON, mage.cards.w.WillingTestSubject.class));
cards.add(new SetCardInfo("capital offense", 52, Rarity.COMMON, mage.cards.c.CapitalOffense.class));

View file

@ -29,7 +29,7 @@ import java.util.Locale;
*/
public class PlayGameTest extends MageTestBase {
private final static List<String> colorChoices = Arrays.asList("bu", "bg", "br", "bw", "ug", "ur", "uw", "gr", "gw", "rw", "bur", "buw", "bug", "brg", "brw", "bgw", "wur", "wug", "wrg", "rgu");
private final static List<String> colorChoices = new ArrayList<>(Arrays.asList("bu", "bg", "br", "bw", "ug", "ur", "uw", "gr", "gw", "rw", "bur", "buw", "bug", "brg", "brw", "bgw", "wur", "wug", "wrg", "rgu"));
@Ignore
@Test

View file

@ -28,7 +28,7 @@ import java.util.Locale;
*/
public class TestPlayRandomGame extends MageTestBase {
private final static List<String> colorChoices = Arrays.asList("bu", "bg", "br", "bw", "ug", "ur", "uw", "gr", "gw", "rw", "bur", "buw", "bug", "brg", "brw", "bgw", "wur", "wug", "wrg", "rgu");
private final static List<String> colorChoices = new ArrayList<>(Arrays.asList("bu", "bg", "br", "bw", "ug", "ur", "uw", "gr", "gw", "rw", "bur", "buw", "bug", "brg", "brw", "bgw", "wur", "wug", "wrg", "rgu"));
@Test
@Ignore

View file

@ -33,7 +33,7 @@ public class BoosterGenerationTest extends MageTestBase {
CardScanner.scan();
}
private static final List<String> basics = Arrays.asList("Plains", "Island", "Swamp", "Mountain", "Forest");
private static final List<String> basics = new ArrayList<>(Arrays.asList("Plains", "Island", "Swamp", "Mountain", "Forest"));
private void checkOnePartnerBoost() {
List<Card> booster = Battlebond.getInstance().createBooster();
@ -64,11 +64,11 @@ public class BoosterGenerationTest extends MageTestBase {
@Test
public void testFateReforged() {
List<String> tapland = Arrays.asList(
List<String> tapland = new ArrayList<>(Arrays.asList(
"Bloodfell Caves", "Blossoming Sands", "Dismal Backwater", "Jungle Hollow", "Rugged Highlands",
"Scoured Barrens", "Swiftwater Cliffs", "Thornwood Falls", "Tranquil Cove", "Wind-Scarred Crag");
List<String> fetchland = Arrays.asList(
"Bloodstained Mire", "Flooded Strand", "Polluted Delta", "Windswept Heath", "Wooded Foothills");
"Scoured Barrens", "Swiftwater Cliffs", "Thornwood Falls", "Tranquil Cove", "Wind-Scarred Crag"));
List<String> fetchland = new ArrayList<>(Arrays.asList(
"Bloodstained Mire", "Flooded Strand", "Polluted Delta", "Windswept Heath", "Wooded Foothills"));
List<Card> booster = FateReforged.getInstance().createBooster();
assertTrue(str(booster), contains(booster, tapland, "FRF") || contains(booster, fetchland, "KTK")
@ -78,13 +78,13 @@ public class BoosterGenerationTest extends MageTestBase {
@Test
public void testMastersEditionII() {
List<String> snowCoveredLand = Arrays.asList(
List<String> snowCoveredLand = new ArrayList<>(Arrays.asList(
"Snow-Covered Plains",
"Snow-Covered Island",
"Snow-Covered Swamp",
"Snow-Covered Mountain",
"Snow-Covered Forest"
);
));
List<Card> booster = MastersEditionII.getInstance().createBooster();
assertTrue(str(booster), contains(booster, snowCoveredLand, "ME2"));
assertFalse(str(booster), contains(booster, basics, null));
@ -93,11 +93,11 @@ public class BoosterGenerationTest extends MageTestBase {
@Test
public void testMastersEditionIV_UrzaSpecialLandsList() {
List<String> needUrzaList = Arrays.asList(
List<String> needUrzaList = new ArrayList<>(Arrays.asList(
"Urza's Mine",
"Urza's Power Plant",
"Urza's Tower"
);
));
List<CardInfo> setOrzaList = MastersEditionIV.getInstance().getSpecialLand();
Assert.assertEquals("Urza special lands must have 4 variation for each of 3 card", 3 * 4, setOrzaList.size());
@ -117,11 +117,11 @@ public class BoosterGenerationTest extends MageTestBase {
public void testMastersEditionIV_UrzaSpecialLandInBoosters() {
// ME4 replace all basic lands with special (1 per booster)
// https://mtg.gamepedia.com/Masters_Edition_IV
List<String> urzaLand = Arrays.asList(
List<String> urzaLand = new ArrayList<>(Arrays.asList(
"Urza's Mine",
"Urza's Power Plant",
"Urza's Tower"
);
));
for (int i = 1; i <= 5; i++) {
List<Card> booster = MastersEditionIV.getInstance().createBooster();

View file

@ -28,7 +28,7 @@ public class DeckBuilderTest {
public void testAllArtifacts() {
final List<Card> spellCardPool = new ArrayList<>();
final UUID owner = UUID.randomUUID();
final List<ColoredManaSymbol> allowedColors = Arrays.asList(ColoredManaSymbol.U);
final List<ColoredManaSymbol> allowedColors = new ArrayList<>(Arrays.asList(ColoredManaSymbol.U));
final List<String> setsToUse = new ArrayList<>();
final List<Card> landCardPool = null;
final RateCallback rateCallback = new RateCallback() {

View file

@ -1,14 +1,14 @@
package mage.abilities;
import java.io.Serializable;
import java.util.UUID;
import mage.abilities.effects.Effect;
import mage.abilities.effects.Effects;
import mage.target.Target;
import mage.target.Targets;
import java.io.Serializable;
import java.util.UUID;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class Mode implements Serializable {
@ -53,7 +53,14 @@ public class Mode implements Serializable {
}
public void addTarget(Target target) {
this.addTarget(target, false);
}
public void addTarget(Target target, Boolean addChooseHintFromEffect) {
targets.add(target);
if (addChooseHintFromEffect) {
target.withChooseHint(this.getEffects().getText(this));
}
}
public Effects getEffects() {

View file

@ -20,7 +20,7 @@ public class OneOrMoreCountersAddedTriggeredAbility extends TriggeredAbilityImpl
}
public OneOrMoreCountersAddedTriggeredAbility(Effect effect, boolean optional, CounterType counterType) {
super(Zone.BATTLEFIELD, effect, true);
super(Zone.ALL, effect, true);
this.counterType = counterType;
}

View file

@ -5,8 +5,6 @@
*/
package mage.abilities.effects.common.ruleModifying;
import java.util.List;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbility;
@ -14,6 +12,7 @@ import mage.abilities.SpellAbility;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.game.Game;
import mage.game.events.GameEvent;
@ -22,11 +21,14 @@ import mage.game.stack.StackObject;
import mage.players.Player;
import mage.target.Target;
import java.util.List;
import java.util.UUID;
/**
* 6/8/2016 If a spell or ability's targets are changed, or if a copy of a spell
* or ability is put onto the stack and has new targets chosen, it doesn't have
* to target a Flagbearer.
*
* <p>
* 3/16/2017 A Flagbearer only requires targeting of itself when choosing targets
* as a result of casting a spell or activating an ability. Notably, triggered
* abilities are exempt from this targeting restriction (in addition to the note
@ -37,15 +39,22 @@ import mage.target.Target;
public class TargetsHaveToTargetPermanentIfAbleEffect extends ContinuousRuleModifyingEffectImpl {
private final FilterPermanent filter;
private static final FilterPermanent flagbearerFilter = new FilterPermanent(SubType.FLAGBEARER, "one Flagbearer");
public TargetsHaveToTargetPermanentIfAbleEffect() {
this(flagbearerFilter);
}
public TargetsHaveToTargetPermanentIfAbleEffect(FilterPermanent filter) {
super(Duration.WhileOnBattlefield, Outcome.Detriment);
this.filter = filter;
staticText = "While choosing targets as part of casting a spell or activating an ability, your opponents must choose at least " + this.filter.getMessage() + " on the battlefield if able";
staticText = "While an opponent is choosing targets as part of casting a spell they control " +
"or activating an ability they control, that player must choose at least " +
this.filter.getMessage() + " on the battlefield if able";
}
public TargetsHaveToTargetPermanentIfAbleEffect(final TargetsHaveToTargetPermanentIfAbleEffect effect) {
private TargetsHaveToTargetPermanentIfAbleEffect(final TargetsHaveToTargetPermanentIfAbleEffect effect) {
super(effect);
this.filter = effect.filter;
}
@ -83,7 +92,11 @@ public class TargetsHaveToTargetPermanentIfAbleEffect extends ContinuousRuleModi
Ability stackAbility = stackObject.getStackAbility();
// Ensure that this ability is activated or a cast spell, because Flag Bearer effects don't require triggered abilities to choose a Standard Bearer
if (!(stackAbility instanceof ActivatedAbility) &&
!(stackAbility instanceof SpellAbility)) {
!(stackAbility instanceof SpellAbility)) {
return false;
}
// Also check that targeting player controls the ability
if (!stackAbility.isControlledBy(targetingPlayer.getId())) {
return false;
}
Ability ability = (Ability) getValue("targetAbility");

View file

@ -70,12 +70,14 @@ public class AddManaOfAnyColorEffect extends BasicManaEffect {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
String mes = String.format("Select color of %d mana to add it", this.amount);
ChoiceColor choice = new ChoiceColor(true, mes, game.getObject(source.getSourceId()));
if (controller.choose(outcome, choice, game)) {
if (choice.getColor() != null) {
Mana mana = choice.getMana(amount);
mana.setFlag(setFlag);
return mana;
if (mes != null) {
ChoiceColor choice = new ChoiceColor(true, mes, game.getObject(source.getSourceId()));
if (controller.choose(outcome, choice, game)) {
if (choice.getColor() != null) {
Mana mana = choice.getMana(amount);
mana.setFlag(setFlag);
return mana;
}
}
}
}

View file

@ -17,13 +17,13 @@ public class Constructed extends DeckValidator {
private static final Logger logger = Logger.getLogger(DeckValidator.class);
protected static final List<String> anyNumberCardsAllowed = Arrays.asList(
protected static final List<String> anyNumberCardsAllowed = new ArrayList<>(Arrays.asList(
"Relentless Rats", "Shadowborn Apostle", "Rat Colony", "Persistent Petitioners"
);
protected static final List<String> basicLandNames = Arrays.asList(
));
protected static final List<String> basicLandNames = new ArrayList<>(Arrays.asList(
"Forest", "Island", "Mountain", "Swamp", "Plains", "Wastes", "Snow-Covered Forest",
"Snow-Covered Island", "Snow-Covered Mountain", "Snow-Covered Swamp", "Snow-Covered Plains"
);
));
protected List<String> banned = new ArrayList<>();
protected List<String> restricted = new ArrayList<>();
protected List<String> setCodes = new ArrayList<>();

View file

@ -36,7 +36,7 @@ public enum CardRepository {
// raise this if db structure was changed
private static final long CARD_DB_VERSION = 51;
// raise this if new cards were added to the server
private static final long CARD_CONTENT_VERSION = 214;
private static final long CARD_CONTENT_VERSION = 215;
private Dao<CardInfo, Object> cardDao;
private Set<String> classNames;
private RepositoryEventSource eventSource = new RepositoryEventSource();

View file

@ -411,6 +411,7 @@ public enum SubType {
TEZZERET("Tezzeret", SubTypeSet.PlaneswalkerType),
TIBALT("Tibalt", SubTypeSet.PlaneswalkerType),
UGIN("Ugin", SubTypeSet.PlaneswalkerType),
URZA("Urza", SubTypeSet.PlaneswalkerType, true), // Unstable
VENSER("Venser", SubTypeSet.PlaneswalkerType),
VIVIEN("Vivien", SubTypeSet.PlaneswalkerType),
VRASKA("Vraska", SubTypeSet.PlaneswalkerType),

View file

@ -1,4 +1,3 @@
package mage.game;
import java.util.Map;
@ -44,18 +43,20 @@ public abstract class GameCommanderImpl extends GameImpl {
for (UUID playerId : state.getPlayerList(startingPlayerId)) {
Player player = getPlayer(playerId);
if (player != null) {
while (!player.getSideboard().isEmpty()) {
Card commander = this.getCard(player.getSideboard().iterator().next());
if (commander != null) {
player.addCommanderId(commander.getId());
commander.moveToZone(Zone.COMMAND, null, this, true);
commander.getAbilities().setControllerId(player.getId());
ability.addEffect(new CommanderReplacementEffect(commander.getId(), alsoHand, alsoLibrary));
ability.addEffect(new CommanderCostModification(commander.getId()));
getState().setValue(commander.getId() + "_castCount", 0);
CommanderInfoWatcher watcher = new CommanderInfoWatcher(commander.getId(), checkCommanderDamage);
getState().addWatcher(watcher);
watcher.addCardInfoToCommander(this);
if (player.getSideboard().isEmpty()) { // needed for restart game of e.g. Karn Liberated
for (UUID commanderId : player.getCommandersIds()) {
Card commander = this.getCard(commanderId);
if (commander != null) {
initCommander(commander, ability, player);
}
}
} else {
while (!player.getSideboard().isEmpty()) {
Card commander = this.getCard(player.getSideboard().iterator().next());
if (commander != null) {
player.addCommanderId(commander.getId());
initCommander(commander, ability, player);
}
}
}
}
@ -67,6 +68,17 @@ public abstract class GameCommanderImpl extends GameImpl {
}
}
private void initCommander(Card commander, Ability ability, Player player) {
commander.moveToZone(Zone.COMMAND, null, this, true);
commander.getAbilities().setControllerId(player.getId());
ability.addEffect(new CommanderReplacementEffect(commander.getId(), alsoHand, alsoLibrary));
ability.addEffect(new CommanderCostModification(commander.getId()));
getState().setValue(commander.getId() + "_castCount", 0);
CommanderInfoWatcher watcher = new CommanderInfoWatcher(commander.getId(), checkCommanderDamage);
getState().addWatcher(watcher);
watcher.addCardInfoToCommander(this);
}
//20130711
/*903.8. The Commander variant uses an alternate mulligan rule.
* Each time a player takes a mulligan, rather than shuffling their entire hand of cards into their library, that player exiles any number of cards from their hand face down.

View file

@ -1,21 +1,21 @@
package mage.game.permanent.token;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.MageInt;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.IndestructibleAbility;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
/**
*
* @author spjspj
*/
public final class MaritLageToken extends TokenImpl {
public MaritLageToken() {
super("Marit Lage", "legendary 20/20 black Avatar creature token with flying and indestructible named Marit Lage");
super("Marit Lage", "Marit Lage, a legendary 20/20 black Avatar creature token with flying and indestructible");
this.setOriginalExpansionSetCode("CSP");
cardType.add(CardType.CREATURE);
subtype.add(SubType.AVATAR);

View file

@ -1,5 +1,9 @@
package mage.players;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;
import mage.ConditionalMana;
import mage.MageObject;
import mage.MageObjectReference;
@ -65,11 +69,6 @@ import mage.util.GameLog;
import mage.util.RandomUtil;
import org.apache.log4j.Logger;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;
public abstract class PlayerImpl implements Player, Serializable {
private static final Logger logger = Logger.getLogger(PlayerImpl.class);
@ -1405,21 +1404,37 @@ public abstract class PlayerImpl implements Player, Serializable {
if (zone != Zone.HAND) {
if (Zone.GRAVEYARD == zone && canPlayCardsFromGraveyard()) {
for (ActivatedAbility ability : candidateAbilites.getPlayableAbilities(Zone.HAND)) {
if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
if (canUse
|| ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
if (ability.canActivate(playerId, game).canActivate()) {
output.put(ability.getId(), ability);
}
}
}
}
if (zone != Zone.BATTLEFIELD
&& null != game.getContinuousEffects().asThough(object.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, this.getId(), game)) {
if (zone != Zone.BATTLEFIELD) {
for (Ability ability : candidateAbilites) {
if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
ability.setControllerId(this.getId());
if (ability instanceof ActivatedAbility && ability.getZone().match(Zone.HAND)
&& ((ActivatedAbility) ability).canActivate(playerId, game).canActivate()) {
output.put(ability.getId(), (ActivatedAbility) ability);
if (game.getContinuousEffects().asThough(object.getId(),
AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE,
null,
this.getId(),
game)
!= null
// if anyone sees an issue with this code, please report it. Worked in my testing.
|| game.getContinuousEffects().asThough(object.getId(),
AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE,
ability,
this.getId(),
game)
!= null) {
if (canUse
|| ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
ability.setControllerId(this.getId());
if (ability instanceof ActivatedAbility
&& ability.getZone().match(Zone.HAND)
&& ((ActivatedAbility) ability).canActivate(playerId, game).canActivate()) {
output.put(ability.getId(), (ActivatedAbility) ability);
}
}
}
}
@ -2566,7 +2581,8 @@ public abstract class PlayerImpl implements Player, Serializable {
* @param game
* @param winnable
* @param appliedEffects
* @return if winnable, true if player won the toss, if not winnable, true for heads and false for tails
* @return if winnable, true if player won the toss, if not winnable, true
* for heads and false for tails
*/
@Override
public boolean flipCoin(Ability source, Game game, boolean winnable, ArrayList<UUID> appliedEffects) {
@ -2620,7 +2636,7 @@ public abstract class PlayerImpl implements Player, Serializable {
/**
* @param game
* @param appliedEffects
* @param numSides Number of sides the dice has
* @param numSides Number of sides the dice has
* @return the number that the player rolled
*/
@Override
@ -2654,10 +2670,10 @@ public abstract class PlayerImpl implements Player, Serializable {
/**
* @param game
* @param appliedEffects
* @param numberChaosSides The number of chaos sides the planar die
* currently has (normally 1 but can be 5)
* @param numberChaosSides The number of chaos sides the planar die
* currently has (normally 1 but can be 5)
* @param numberPlanarSides The number of chaos sides the planar die
* currently has (normally 1)
* currently has (normally 1)
* @return the outcome that the player rolled. Either ChaosRoll, PlanarRoll
* or NilRoll
*/
@ -2814,7 +2830,7 @@ public abstract class PlayerImpl implements Player, Serializable {
/**
* @param ability
* @param available if null, it won't be checked if enough mana is available
* @param available if null, it won't be checked if enough mana is available
* @param sourceObject
* @param game
* @return
@ -3364,7 +3380,7 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public boolean canPaySacrificeCost(Permanent permanent, UUID sourceId,
UUID controllerId, Game game
UUID controllerId, Game game
) {
return sacrificeCostFilter == null || !sacrificeCostFilter.match(permanent, sourceId, controllerId, game);
}
@ -3512,8 +3528,8 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public boolean moveCards(Card card, Zone toZone,
Ability source, Game game,
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
Ability source, Game game,
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
) {
Set<Card> cardList = new HashSet<>();
if (card != null) {
@ -3524,22 +3540,22 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public boolean moveCards(Cards cards, Zone toZone,
Ability source, Game game
Ability source, Game game
) {
return moveCards(cards.getCards(game), toZone, source, game);
}
@Override
public boolean moveCards(Set<Card> cards, Zone toZone,
Ability source, Game game
Ability source, Game game
) {
return moveCards(cards, toZone, source, game, false, false, false, null);
}
@Override
public boolean moveCards(Set<Card> cards, Zone toZone,
Ability source, Game game,
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
Ability source, Game game,
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
) {
if (cards.isEmpty()) {
return true;
@ -3625,8 +3641,8 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public boolean moveCardsToExile(Card card, Ability source,
Game game, boolean withName, UUID exileId,
String exileZoneName
Game game, boolean withName, UUID exileId,
String exileZoneName
) {
Set<Card> cards = new HashSet<>();
cards.add(card);
@ -3635,8 +3651,8 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public boolean moveCardsToExile(Set<Card> cards, Ability source,
Game game, boolean withName, UUID exileId,
String exileZoneName
Game game, boolean withName, UUID exileId,
String exileZoneName
) {
if (cards.isEmpty()) {
return true;
@ -3651,14 +3667,14 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public boolean moveCardToHandWithInfo(Card card, UUID sourceId,
Game game
Game game
) {
return this.moveCardToHandWithInfo(card, sourceId, game, true);
}
@Override
public boolean moveCardToHandWithInfo(Card card, UUID sourceId,
Game game, boolean withName
Game game, boolean withName
) {
boolean result = false;
Zone fromZone = game.getState().getZone(card.getId());
@ -3683,7 +3699,7 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public Set<Card> moveCardsToGraveyardWithInfo(Set<Card> allCards, Ability source,
Game game, Zone fromZone
Game game, Zone fromZone
) {
UUID sourceId = source == null ? null : source.getSourceId();
Set<Card> movedCards = new LinkedHashSet<>();
@ -3691,7 +3707,7 @@ public abstract class PlayerImpl implements Player, Serializable {
// identify cards from one owner
Cards cards = new CardsImpl();
UUID ownerId = null;
for (Iterator<Card> it = allCards.iterator(); it.hasNext(); ) {
for (Iterator<Card> it = allCards.iterator(); it.hasNext();) {
Card card = it.next();
if (cards.isEmpty()) {
ownerId = card.getOwnerId();
@ -3752,7 +3768,7 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId,
Game game, Zone fromZone
Game game, Zone fromZone
) {
if (card == null) {
return false;
@ -3781,8 +3797,8 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId,
Game game, Zone fromZone,
boolean toTop, boolean withName
Game game, Zone fromZone,
boolean toTop, boolean withName
) {
if (card == null) {
return false;
@ -3816,7 +3832,7 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public boolean moveCardToExileWithInfo(Card card, UUID exileId, String exileName, UUID sourceId,
Game game, Zone fromZone, boolean withName) {
Game game, Zone fromZone, boolean withName) {
if (card == null) {
return false;
}

View file

@ -1,10 +1,5 @@
package mage.target;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import mage.abilities.Ability;
import mage.constants.Outcome;
import mage.constants.Zone;
@ -12,8 +7,12 @@ import mage.filter.Filter;
import mage.game.Game;
import mage.players.Player;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.UUID;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public interface Target extends Serializable {
@ -30,7 +29,7 @@ public interface Target extends Serializable {
* controls if it will be checked, if the target can be targeted from source
*
* @param notTarget true = do not check for protection, false = check for
* protection
* protection
*/
void setNotTarget(boolean notTarget);
@ -136,4 +135,5 @@ public interface Target extends Serializable {
// used for cards like Spellskite
void setTargetAmount(UUID targetId, int amount, Game game);
Target withChooseHint(String chooseHint);
}

View file

@ -1,16 +1,5 @@
package mage.target;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.cards.Card;
@ -23,6 +12,8 @@ import mage.game.events.GameEvent.EventType;
import mage.players.Player;
import mage.util.RandomUtil;
import java.util.*;
/**
* @author BetaSteward_at_googlemail.com
*/
@ -45,6 +36,7 @@ public abstract class TargetImpl implements Target {
protected UUID abilityController = null; // only used if target controller != ability controller
protected int targetTag; // can be set if other target check is needed (AnotherTargetPredicate)
protected String chooseHint = null; // UI choose hints after target name
@Override
public abstract TargetImpl copy();
@ -72,6 +64,7 @@ public abstract class TargetImpl implements Target {
this.targetController = target.targetController;
this.abilityController = target.abilityController;
this.targetTag = target.targetTag;
this.chooseHint = target.chooseHint;
}
@Override
@ -101,12 +94,11 @@ public abstract class TargetImpl implements Target {
@Override
public String getMessage() {
// UI choose message
String suffix = "";
// if (targetController != null) {
// // Hint for the selecting player that the targets must be valid from the point of the ability controller
// // e.g. select opponent text may be misleading otherwise
// suffix = " (target controlling!)";
// }
if (this.chooseHint != null) {
suffix = " (" + this.chooseHint + ")";
}
if (getMaxNumberOfTargets() != 1) {
StringBuilder sb = new StringBuilder();
sb.append("Select ").append(targetName);
@ -401,7 +393,7 @@ public abstract class TargetImpl implements Target {
for (int K = minK; K <= maxK; K++) {
// get the combination by index
// e.g. 01 --> AB , 23 --> CD
int combination[] = new int[K];
int[] combination = new int[K];
// position of current index
// if (r = 1) r*
@ -544,4 +536,9 @@ public abstract class TargetImpl implements Target {
rememberZoneChangeCounter(targetId, game);
}
@Override
public Target withChooseHint(String chooseHint) {
this.chooseHint = chooseHint;
return this;
}
}