This commit is contained in:
brodee 2018-11-28 23:01:47 -08:00
commit 4c94938c14
146 changed files with 4424 additions and 1541 deletions

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<groupId>org.mage</groupId>

View file

@ -1,6 +0,0 @@
XMage.de 1 (Europe/Germany) fast :xmage.de:17171
old xmage.de (Europe/Germany) :185.3.232.200:17171
XMage Players MTG:xmageplayersmtg.ddns.net:17171
XMage.tahiti :xmage.tahiti.one:443
Seedds Server (Asia) :115.29.203.80:17171
localhost -> connect to your local server (must be started):localhost:17171

View file

@ -1,4 +1,3 @@
package mage.client.deck.generator;
import java.util.ArrayList;
@ -7,6 +6,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import mage.cards.Card;
import mage.cards.decks.Deck;
import mage.cards.repository.CardCriteria;
@ -123,9 +123,9 @@ public final class DeckGenerator {
* non-creatures, lands (including non-basic). Fixes the deck, adjusting for
* size and color of the cards retrieved.
*
* @param deckSize how big the deck is to generate.
* @param deckSize how big the deck is to generate.
* @param allowedColors which colors are allowed in the deck.
* @param setsToUse which sets to use to retrieve cards for this deck.
* @param setsToUse which sets to use to retrieve cards for this deck.
* @return the final deck to use.
*/
private static Deck generateDeck(int deckSize, List<ColoredManaSymbol> allowedColors, List<String> setsToUse) {
@ -180,9 +180,9 @@ public final class DeckGenerator {
* non-creatures are retrieved separately to ensure the deck contains a
* reasonable mix of both.
*
* @param criteria the criteria to search for in the database.
* @param criteria the criteria to search for in the database.
* @param spellCount the number of spells that match the criteria needed in
* the deck.
* the deck.
*/
private static void generateSpells(CardCriteria criteria, int spellCount) {
List<CardInfo> cardPool = CardRepository.instance.findCards(criteria);
@ -233,7 +233,7 @@ public final class DeckGenerator {
* in this deck. Usually the lands will be well balanced relative to the
* color of cards.
*
* @param criteria the criteria of the lands to search for in the database.
* @param criteria the criteria of the lands to search for in the database.
* @param landsCount the amount of lands required for this deck.
* @param basicLands information about the basic lands from the sets used.
*/
@ -310,10 +310,10 @@ public final class DeckGenerator {
* filled.
*
* @param landsNeeded how many remaining lands are needed.
* @param percentage the percentage needed for each color in the final deck.
* @param count how many of each color can be produced by non-basic lands.
* @param basicLands list of information about basic lands from the
* database.
* @param percentage the percentage needed for each color in the final deck.
* @param count how many of each color can be produced by non-basic lands.
* @param basicLands list of information about basic lands from the
* database.
*/
private static void addBasicLands(int landsNeeded, Map<String, Double> percentage, Map<String, Integer> count, Map<String, List<CardInfo>> basicLands) {
@ -360,15 +360,14 @@ public final class DeckGenerator {
/**
* Return a random basic land of the chosen color.
*
* @param color the color the basic land should produce.
* @param color the color the basic land should produce.
* @param basicLands list of information about basic lands from the
* database.
* database.
* @return a single basic land that produces the color needed.
*/
private static Card getBasicLand(ColoredManaSymbol color, Map<String, List<CardInfo>> basicLands) {
String landName = DeckGeneratorPool.getBasicLandName(color.toString());
List<CardInfo> basicLandsInfo = basicLands.get(landName);
return basicLandsInfo.get(RandomUtil.nextInt(basicLandsInfo.size() - 1)).getMockCard().copy();
return basicLandsInfo.get(RandomUtil.nextInt(basicLandsInfo.size())).getMockCard().copy();
}
}

View file

@ -3,15 +3,28 @@ package mage.client.deckeditor;
import mage.util.StreamUtils;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.*;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Optional;
import javax.swing.*;
public class DeckImportFromClipboardDialog extends JDialog {
private static final String FORMAT_TEXT =
"// Example:\n" +
"//1 Library of Congress\n" +
"//1 Cryptic Gateway\n" +
"//1 Azami, Lady of Scrolls\n" +
"// NB: This is slow as, and will lock your screen :)\n" +
"\n" +
"// Your current clipboard:\n";
private JPanel contentPane;
private JButton buttonOK;
private JButton buttonCancel;
@ -21,6 +34,9 @@ public class DeckImportFromClipboardDialog extends JDialog {
public DeckImportFromClipboardDialog() {
initComponents();
onRefreshClipboard();
setContentPane(contentPane);
setModal(true);
getRootPane().setDefaultButton(buttonOK);
@ -40,6 +56,15 @@ public class DeckImportFromClipboardDialog extends JDialog {
contentPane.registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
}
private Optional<String> getClipboardStringData() {
try {
return Optional.of((String)Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.stringFlavor));
} catch (HeadlessException | UnsupportedFlavorException | IOException e) {
//e.printStackTrace();
}
return Optional.empty();
}
private void onOK() {
BufferedWriter bw = null;
try {
@ -60,6 +85,10 @@ public class DeckImportFromClipboardDialog extends JDialog {
dispose();
}
private void onRefreshClipboard() {
txtDeckList.setText(FORMAT_TEXT + getClipboardStringData().orElse(""));
}
public String getTmpPath() {
return tmpPath;
}
@ -143,7 +172,7 @@ public class DeckImportFromClipboardDialog extends JDialog {
txtDeckList.setMinimumSize(new Dimension(250, 400));
txtDeckList.setPreferredSize(new Dimension(550, 400));
txtDeckList.setText("// Example:\n//1 Library of Congress\n//1 Cryptic Gateway\n//1 Azami, Lady of Scrolls\n// NB: This is slow as, and will lock your screen :)");
txtDeckList.setText(FORMAT_TEXT);
JScrollPane txtScrollableDeckList = new JScrollPane(txtDeckList);
panel3.add(txtScrollableDeckList, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,

View file

@ -340,8 +340,8 @@
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/flags/us.png"/>
</Property>
<Property name="text" type="java.lang.String" value="W"/>
<Property name="toolTipText" type="java.lang.String" value="Connect to vaporservermtg.com (USA)"/>
<Property name="text" type="java.lang.String" value="P"/>
<Property name="toolTipText" type="java.lang.String" value="Connect to mtg.powersofwar.com (USA)"/>
<Property name="actionCommand" type="java.lang.String" value="connectXmageus"/>
<Property name="alignmentY" type="float" value="0.0"/>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">

View file

@ -270,8 +270,8 @@ public class ConnectDialog extends MageDialog {
});
btnFind3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/flags/us.png"))); // NOI18N
btnFind3.setText("W");
btnFind3.setToolTipText("Connect to vaporservermtg.com (USA)");
btnFind3.setText("P");
btnFind3.setToolTipText("Connect to mtg.powersofwar.com (USA)");
btnFind3.setActionCommand("connectXmageus");
btnFind3.setAlignmentY(0.0F);
btnFind3.setMargin(new java.awt.Insets(2, 2, 2, 2));
@ -688,7 +688,7 @@ public class ConnectDialog extends MageDialog {
}//GEN-LAST:event_btnFind2findPublicServerActionPerformed
private void connectXmageus(java.awt.event.ActionEvent evt) {
String serverAddress = "vapormtgserver.com";
String serverAddress = "mtg.powersofwar.com";
this.txtServer.setText(serverAddress);
this.txtPort.setText("17171");
// Update userName and password according to the chosen server.

View file

@ -51,6 +51,7 @@ public class NewTableDialog extends MageDialog {
this.spnNumWins.setModel(new SpinnerNumberModel(1, 1, 5, 1));
this.spnFreeMulligans.setModel(new SpinnerNumberModel(0, 0, 5, 1));
this.spnQuitRatio.setModel(new SpinnerNumberModel(100, 0, 100, 5));
this.spnMinimumRating.setModel(new SpinnerNumberModel(0, 0, 3000, 10));
this.spnEdhPowerLevel.setModel(new SpinnerNumberModel(100, 0, 100, 5));
MageFrame.getUI().addButton(MageComponents.NEW_TABLE_OK_BUTTON, btnOK);
}
@ -102,8 +103,10 @@ public class NewTableDialog extends MageDialog {
btnPreviousConfiguration2 = new javax.swing.JButton();
btnCancel = new javax.swing.JButton();
lblQuitRatio = new javax.swing.JLabel();
lblMinimumRating = new javax.swing.JLabel();
lblEdhPowerLevel = new javax.swing.JLabel();
spnQuitRatio = new javax.swing.JSpinner();
spnMinimumRating = new javax.swing.JSpinner();
spnEdhPowerLevel = new javax.swing.JSpinner();
setTitle("New Table");
@ -186,9 +189,11 @@ public class NewTableDialog extends MageDialog {
btnCancel.addActionListener(evt -> btnCancelActionPerformed(evt));
lblQuitRatio.setText("Allowed quit %");
lblMinimumRating.setText("Minimum rating");
lblEdhPowerLevel.setText("EDH power level");
spnQuitRatio.setToolTipText("Players with quit % more than this value can't join this table");
spnMinimumRating.setToolTipText("Players with rating less than this value can't join this table");
spnEdhPowerLevel.setToolTipText("Players with decks with a higher power level can't join this table");
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
@ -239,9 +244,10 @@ public class NewTableDialog extends MageDialog {
.addComponent(lblQuitRatio)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblEdhPowerLevel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(lblMinimumRating)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(spnEdhPowerLevel, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addComponent(jLabel1, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel2, javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
@ -270,7 +276,11 @@ public class NewTableDialog extends MageDialog {
.addGap(18, 18, 18)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblNumWins)
.addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblEdhPowerLevel)
.addComponent(spnEdhPowerLevel, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addComponent(jSeparator2)
.addComponent(player1Panel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(pnlOtherPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
@ -297,14 +307,13 @@ public class NewTableDialog extends MageDialog {
.addComponent(cbTimeLimit, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(cbDeckType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lbDeckType)
.addComponent(cbDeckType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(chkRated)
.addComponent(lblQuitRatio)
.addComponent(chkRated)
.addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblEdhPowerLevel)
.addComponent(chkRated)
.addComponent(spnEdhPowerLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(lblMinimumRating)
.addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
@ -326,6 +335,7 @@ public class NewTableDialog extends MageDialog {
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblSkillLevel)
.addComponent(lblNumWins)
.addComponent(lblEdhPowerLevel)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblRange)
.addComponent(lblAttack)))
@ -334,7 +344,8 @@ public class NewTableDialog extends MageDialog {
.addComponent(cbRange, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(cbAttackOption, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(cbSkillLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(spnEdhPowerLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@ -394,6 +405,7 @@ public class NewTableDialog extends MageDialog {
options.setFreeMulligans((Integer) this.spnFreeMulligans.getValue());
options.setPassword(this.txtPassword.getText());
options.setQuitRatio((Integer) this.spnQuitRatio.getValue());
options.setMinimumRating((Integer) this.spnMinimumRating.getValue());
options.setEdhPowerLevel((Integer) this.spnEdhPowerLevel.getValue());
String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> "");
options.setBannedUsers(IgnoreList.ignoreList(serverAddress));
@ -695,6 +707,7 @@ public class NewTableDialog extends MageDialog {
}
this.spnQuitRatio.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_QUIT_RATIO, "100")));
this.spnMinimumRating.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_MINIMUM_RATING + versionStr, "0")));
this.spnEdhPowerLevel.setValue(0);
}
@ -729,6 +742,7 @@ public class NewTableDialog extends MageDialog {
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_SPECTATORS_ALLOWED + versionStr, options.isSpectatorsAllowed() ? "Yes" : "No");
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_PLANECHASE + versionStr, options.isPlaneChase() ? "Yes" : "No");
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_QUIT_RATIO + versionStr, Integer.toString(options.getQuitRatio()));
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_MINIMUM_RATING + versionStr, Integer.toString(options.getMinimumRating()));
StringBuilder playerTypesString = new StringBuilder();
for (Object player : players) {
if (playerTypesString.length() > 0) {
@ -770,6 +784,7 @@ public class NewTableDialog extends MageDialog {
private javax.swing.JLabel lblNumWins;
private javax.swing.JLabel lblPassword;
private javax.swing.JLabel lblQuitRatio;
private javax.swing.JLabel lblMinimumRating;
private javax.swing.JLabel lblEdhPowerLevel;
private javax.swing.JLabel lblRange;
private javax.swing.JLabel lblSkillLevel;
@ -779,6 +794,7 @@ public class NewTableDialog extends MageDialog {
private javax.swing.JSpinner spnNumPlayers;
private javax.swing.JSpinner spnNumWins;
private javax.swing.JSpinner spnQuitRatio;
private javax.swing.JSpinner spnMinimumRating;
private javax.swing.JSpinner spnEdhPowerLevel;
private javax.swing.JTextField txtName;
private javax.swing.JTextField txtPassword;

View file

@ -75,6 +75,7 @@ public class NewTournamentDialog extends MageDialog {
this.spnConstructTime.setModel(new SpinnerNumberModel(10, CONSTRUCTION_TIME_MIN, CONSTRUCTION_TIME_MAX, 2));
this.spnNumRounds.setModel(new SpinnerNumberModel(2, 2, 10, 1));
this.spnQuitRatio.setModel(new SpinnerNumberModel(100, 0, 100, 5));
this.spnMinimumRating.setModel(new SpinnerNumberModel(0, 0, 3000, 10));
}
public void showDialog(UUID roomId) {
@ -165,6 +166,8 @@ public class NewTournamentDialog extends MageDialog {
pnlRandomPacks = new javax.swing.JPanel();
lblQuitRatio = new javax.swing.JLabel();
spnQuitRatio = new javax.swing.JSpinner();
lblMinimumRating = new javax.swing.JLabel();
spnMinimumRating = new javax.swing.JSpinner();
setTitle("New Tournament");
@ -315,8 +318,10 @@ public class NewTournamentDialog extends MageDialog {
pnlRandomPacks.setLayout(new javax.swing.BoxLayout(pnlRandomPacks, javax.swing.BoxLayout.Y_AXIS));
lblQuitRatio.setText("Allowed quit %:");
lblMinimumRating.setText("Minimum rating:");
spnQuitRatio.setToolTipText("Players with quit % more than this value can't join this table");
spnMinimumRating.setToolTipText("Players with rating less than this value can't join this table");
spnNumSeats.setToolTipText("The number of seats for each duel. If more than 2, will set number of wins to 1");
spnNumPlayers.setToolTipText("The total number of players who will draft");
@ -386,11 +391,15 @@ public class NewTournamentDialog extends MageDialog {
.addComponent(lblNumWins)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(lblQuitRatio)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(lblMinimumRating)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(chkRated))
.addComponent(cbTournamentType, javax.swing.GroupLayout.PREFERRED_SIZE, 290, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGroup(layout.createSequentialGroup()
@ -444,6 +453,8 @@ public class NewTournamentDialog extends MageDialog {
.addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblQuitRatio)
.addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblMinimumRating)
.addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(chkRated))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
@ -522,6 +533,7 @@ public class NewTournamentDialog extends MageDialog {
tOptions.setWatchingAllowed(cbAllowSpectators.isSelected());
tOptions.setPlaneChase(cbPlaneChase.isSelected());
tOptions.setQuitRatio((Integer) spnQuitRatio.getValue());
tOptions.setMinimumRating((Integer) spnMinimumRating.getValue());
for (TournamentPlayerPanel player : players) {
tOptions.getPlayerTypes().add((PlayerType) player.getPlayerType().getSelectedItem());
}
@ -1065,6 +1077,7 @@ public class NewTournamentDialog extends MageDialog {
this.spnFreeMulligans.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_OF_FREE_MULLIGANS + versionStr, "0")));
this.spnNumWins.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_OF_WINS + versionStr, "2")));
this.spnQuitRatio.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_QUIT_RATIO + versionStr, "100")));
this.spnMinimumRating.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_MINIMUM_RATING + versionStr, "0")));
TournamentTypeView tournamentType = (TournamentTypeView) cbTournamentType.getSelectedItem();
activatePanelElements(tournamentType);
@ -1150,6 +1163,7 @@ public class NewTournamentDialog extends MageDialog {
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_OF_FREE_MULLIGANS + versionStr, Integer.toString(tOptions.getMatchOptions().getFreeMulligans()));
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_OF_WINS + versionStr, Integer.toString(tOptions.getMatchOptions().getWinsNeeded()));
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_QUIT_RATIO + versionStr, Integer.toString(tOptions.getQuitRatio()));
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_MINIMUM_RATING + versionStr, Integer.toString(tOptions.getMinimumRating()));
if (tOptions.getTournamentType().startsWith("Sealed")) {
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_PACKS_SEALED + versionStr, tOptions.getLimitedOptions().getSetCodes().toString());
@ -1221,6 +1235,7 @@ public class NewTournamentDialog extends MageDialog {
private javax.swing.JLabel lblPassword;
private javax.swing.JLabel lblPlayer1;
private javax.swing.JLabel lblQuitRatio;
private javax.swing.JLabel lblMinimumRating;
private javax.swing.JLabel lblTournamentType;
private mage.client.table.NewPlayerPanel player1Panel;
private javax.swing.JPanel pnlDraftOptions;
@ -1235,6 +1250,7 @@ public class NewTournamentDialog extends MageDialog {
private javax.swing.JSpinner spnNumRounds;
private javax.swing.JSpinner spnNumWins;
private javax.swing.JSpinner spnQuitRatio;
private javax.swing.JSpinner spnMinimumRating;
private javax.swing.JTextField txtName;
private javax.swing.JTextField txtPassword;
private org.jdesktop.beansbinding.BindingGroup bindingGroup;

View file

@ -222,6 +222,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
public static final String KEY_NEW_TABLE_NUMBER_PLAYERS = "newTableNumberPlayers";
public static final String KEY_NEW_TABLE_PLAYER_TYPES = "newTablePlayerTypes";
public static final String KEY_NEW_TABLE_QUIT_RATIO = "newTableQuitRatio";
public static final String KEY_NEW_TABLE_MINIMUM_RATING = "newTableMinimumRating";
public static final String KEY_NEW_TABLE_RATED = "newTableRated";
// pref setting for new tournament dialog
@ -243,6 +244,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
public static final String KEY_NEW_TOURNAMENT_ALLOW_ROLLBACKS = "newTournamentAllowRollbacks";
public static final String KEY_NEW_TOURNAMENT_DECK_FILE = "newTournamentDeckFile";
public static final String KEY_NEW_TOURNAMENT_QUIT_RATIO = "newTournamentQuitRatio";
public static final String KEY_NEW_TOURNAMENT_MINIMUM_RATING = "newTournamentMinimumRating";
public static final String KEY_NEW_TOURNAMENT_RATED = "newTournamentRated";
// pref setting for deck generator

View file

@ -26,6 +26,8 @@ import mage.view.CardView;
import mage.view.PermanentView;
import net.xeoh.plugins.base.PluginManager;
import net.xeoh.plugins.base.impl.PluginManagerFactory;
import net.xeoh.plugins.base.util.uri.ClassURI;
import org.apache.log4j.Logger;
import org.mage.plugins.card.CardPluginImpl;
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
@ -46,13 +48,15 @@ public enum Plugins implements MagePlugins {
@Override
public void loadPlugins() {
LOGGER.info("Loading plugins...");
pm = PluginManagerFactory.createPluginManager();
pm.addPluginsFrom(new File(PLUGINS_DIRECTORY + File.separator).toURI());
this.cardPlugin = new CardPluginImpl();
pm.addPluginsFrom(new ClassURI(CardPluginImpl.class).toURI());
pm.addPluginsFrom(new ClassURI(ThemePluginImpl.class).toURI());
this.cardPlugin = pm.getPlugin(CardPlugin.class);
this.counterPlugin = pm.getPlugin(CounterPlugin.class);
this.themePlugin = new ThemePluginImpl();
this.themePlugin = pm.getPlugin(ThemePlugin.class);
LOGGER.info("Done.");
}

View file

@ -1,163 +1,193 @@
/*
* TablesPanel.java
*
* Created on 15-Dec-2009, 10:54:01 PM
*/
package mage.client.table;
* TablesPanel.java
*
* Created on 15-Dec-2009, 10:54:01 PM
*/
package mage.client.table;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyVetoException;
import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import mage.cards.decks.importer.DeckImporterUtil;
import mage.client.MageFrame;
import mage.client.SessionHandler;
import mage.client.chat.ChatPanelBasic;
import mage.client.components.MageComponents;
import mage.client.dialog.*;
import static mage.client.dialog.PreferencesDialog.KEY_TABLES_COLUMNS_ORDER;
import static mage.client.dialog.PreferencesDialog.KEY_TABLES_COLUMNS_WIDTH;
import static mage.client.dialog.PreferencesDialog.KEY_TABLES_FILTER_SETTINGS;
import static mage.client.dialog.PreferencesDialog.KEY_TABLES_DIVIDER_LOCATION_1;
import static mage.client.dialog.PreferencesDialog.KEY_TABLES_DIVIDER_LOCATION_2;
import static mage.client.dialog.PreferencesDialog.KEY_TABLES_DIVIDER_LOCATION_3;
import mage.client.util.ButtonColumn;
import mage.client.util.GUISizeHelper;
import mage.client.util.IgnoreList;
import mage.client.util.MageTableRowSorter;
import mage.client.util.URLHandler;
import mage.client.util.gui.GuiDisplayUtil;
import mage.client.util.gui.TableUtil;
import mage.constants.*;
import mage.game.match.MatchOptions;
import mage.players.PlayerType;
import mage.remote.MageRemoteException;
import mage.view.MatchView;
import mage.view.RoomUsersView;
import mage.view.TableView;
import mage.view.UserRequestMessage;
import org.apache.log4j.Logger;
import org.ocpsoft.prettytime.Duration;
import org.ocpsoft.prettytime.PrettyTime;
import org.ocpsoft.prettytime.units.JustNow;
import mage.cards.decks.importer.DeckImporterUtil;
import mage.client.MageFrame;
import mage.client.SessionHandler;
import mage.client.chat.ChatPanelBasic;
import mage.client.components.MageComponents;
import mage.client.dialog.*;
import mage.client.util.*;
import mage.client.util.gui.GuiDisplayUtil;
import mage.client.util.gui.TableUtil;
import mage.constants.*;
import mage.game.match.MatchOptions;
import mage.players.PlayerType;
import mage.remote.MageRemoteException;
import mage.view.MatchView;
import mage.view.RoomUsersView;
import mage.view.TableView;
import mage.view.UserRequestMessage;
import org.apache.log4j.Logger;
import org.mage.card.arcane.CardRendererUtils;
import org.ocpsoft.prettytime.Duration;
import org.ocpsoft.prettytime.PrettyTime;
import org.ocpsoft.prettytime.units.JustNow;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class TablesPanel extends javax.swing.JPanel {
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyVetoException;
import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
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};
import static mage.client.dialog.PreferencesDialog.*;
private final TableTableModel tableModel;
private final MatchesTableModel matchesModel;
private UUID roomId;
private UpdateTablesTask updateTablesTask;
private UpdatePlayersTask updatePlayersTask;
private UpdateMatchesTask updateMatchesTask;
private JoinTableDialog joinTableDialog;
private NewTableDialog newTableDialog;
private NewTournamentDialog newTournamentDialog;
private final GameChooser gameChooser;
private java.util.List<String> messages;
private int currentMessage;
private final MageTableRowSorter activeTablesSorter;
private final MageTableRowSorter completedTablesSorter;
/**
* @author BetaSteward_at_googlemail.com
*/
public class TablesPanel extends javax.swing.JPanel {
private final ButtonColumn actionButton1;
private final ButtonColumn actionButton2;
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};
final JToggleButton[] filterButtons;
private final TableTableModel tableModel;
private final MatchesTableModel matchesModel;
private UUID roomId;
private UpdateTablesTask updateTablesTask;
private UpdatePlayersTask updatePlayersTask;
private UpdateMatchesTask updateMatchesTask;
private JoinTableDialog joinTableDialog;
private NewTableDialog newTableDialog;
private NewTournamentDialog newTournamentDialog;
private final GameChooser gameChooser;
private java.util.List<String> messages;
private int currentMessage;
private final MageTableRowSorter activeTablesSorter;
private final MageTableRowSorter completedTablesSorter;
// time formater
private PrettyTime timeFormater = new PrettyTime();
private final ButtonColumn actionButton1;
private final ButtonColumn actionButton2;
// time ago renderer
TableCellRenderer timeAgoCellRenderer = 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);
Date d = (Date) value;
label.setText(timeFormater.format(d));
return label;
}
};
final JToggleButton[] filterButtons;
// duration renderer
TableCellRenderer durationCellRenderer = 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);
Long ms = (Long) value;
// time formater
private PrettyTime timeFormater = new PrettyTime();
if (ms != 0) {
Duration dur = timeFormater.approximateDuration(new Date(ms));
label.setText((timeFormater.formatDuration(dur)));
} else {
label.setText("");
}
return label;
}
};
// time ago renderer
TableCellRenderer timeAgoCellRenderer = 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);
Date d = (Date) value;
label.setText(timeFormater.format(d));
return label;
}
};
// datetime render
TableCellRenderer datetimeCellRenderer = new DefaultTableCellRenderer() {
DateFormat datetimeFormater = new SimpleDateFormat("HH:mm:ss");
// duration renderer
TableCellRenderer durationCellRenderer = 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);
Long ms = (Long) value;
@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);
Date d = (Date) value;
if (d != null) {
label.setText(datetimeFormater.format(d));
} else {
label.setText("");
}
if (ms != 0) {
Duration dur = timeFormater.approximateDuration(new Date(ms));
label.setText((timeFormater.formatDuration(dur)));
} else {
label.setText("");
}
return label;
}
};
return label;
}
};
// datetime render
TableCellRenderer datetimeCellRenderer = new DefaultTableCellRenderer() {
DateFormat datetimeFormater = new SimpleDateFormat("HH:mm:ss");
/**
* Creates new form TablesPanel
*/
public TablesPanel() {
@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);
Date d = (Date) value;
if (d != null) {
label.setText(datetimeFormater.format(d));
} else {
label.setText("");
}
tableModel = new TableTableModel();
matchesModel = new MatchesTableModel();
gameChooser = new GameChooser();
return label;
}
};
initComponents();
// tableModel.setSession(session);
// skill renderer
TableCellRenderer skillCellRenderer = new DefaultTableCellRenderer() {
// formater
timeFormater.setLocale(Locale.ENGLISH);
JustNow jn = timeFormater.getUnit(JustNow.class);
jn.setMaxQuantity(1000L * 30L); // 30 seconds gap (show "just now" from 0 to 30 secs)
// base panel to render
private JPanel renderPanel = new JPanel();
private ImageIcon skillIcon = new ImageIcon(this.getClass().getResource("/info/yellow_star_16.png"));
// 1. TABLE CURRENT
tableTables.createDefaultColumnsFromModel();
activeTablesSorter = new MageTableRowSorter(tableModel);
tableTables.setRowSorter(activeTablesSorter);
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
// get table text cell settings
DefaultTableCellRenderer baseRenderer = (DefaultTableCellRenderer) table.getDefaultRenderer(String.class);
JLabel baseComp = (JLabel) baseRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
String skillCode = baseComp.getText();
// apply settings to render panel from parent
renderPanel.setOpaque(baseComp.isOpaque());
renderPanel.setForeground(CardRendererUtils.copyColor(baseComp.getForeground()));
renderPanel.setBackground(CardRendererUtils.copyColor(baseComp.getBackground()));
renderPanel.setBorder(baseComp.getBorder());
// create each skill symbol as child label
renderPanel.removeAll();
renderPanel.setLayout(new BoxLayout(renderPanel, BoxLayout.X_AXIS));
for (char skillSymbol : skillCode.toCharArray()) {
JLabel symbolLabel = new JLabel();
symbolLabel.setBorder(new EmptyBorder(0, 3, 0, 0));
symbolLabel.setIcon(skillIcon);
renderPanel.add(symbolLabel);
}
return renderPanel;
}
};
/**
* Creates new form TablesPanel
*/
public TablesPanel() {
tableModel = new TableTableModel();
matchesModel = new MatchesTableModel();
gameChooser = new GameChooser();
initComponents();
// tableModel.setSession(session);
// formater
timeFormater.setLocale(Locale.ENGLISH);
JustNow jn = timeFormater.getUnit(JustNow.class);
jn.setMaxQuantity(1000L * 30L); // 30 seconds gap (show "just now" from 0 to 30 secs)
// 1. TABLE CURRENT
tableTables.createDefaultColumnsFromModel();
activeTablesSorter = new MageTableRowSorter(tableModel);
tableTables.setRowSorter(activeTablesSorter);
// time ago
tableTables.getColumnModel().getColumn(TableTableModel.COLUMN_CREATED).setCellRenderer(timeAgoCellRenderer);
// skill level
tableTables.getColumnModel().getColumn(TableTableModel.COLUMN_SKILL).setCellRenderer(skillCellRenderer);
// time ago
tableTables.getColumnModel().getColumn(TableTableModel.COLUMN_CREATED).setCellRenderer(timeAgoCellRenderer);
/* date sorter (not need, default is good - see getColumnClass)
activeTablesSorter.setComparator(TableTableModel.COLUMN_CREATED, new Comparator<Date>() {
@Override
@ -166,6 +196,7 @@ public class TablesPanel extends javax.swing.JPanel {
}
});*/
// default sort by created date (last games from above)
ArrayList list = new ArrayList();
list.add(new RowSorter.SortKey(TableTableModel.COLUMN_CREATED, SortOrder.DESCENDING));
@ -322,17 +353,22 @@ public class TablesPanel extends javax.swing.JPanel {
addTableDoubleClickListener(tableCompleted, closedTableAction);
}
private void addTableDoubleClickListener(JTable table, Action action) {
table.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int row = table.convertRowIndexToModel(table.getSelectedRow());
if (e.getClickCount() == 2 && row != -1) {
action.actionPerformed(new ActionEvent(e.getSource(), e.getID(), "" + row));
}
}
});
}
private void addTableDoubleClickListener(JTable table, Action action) {
table.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
int selRow = table.getSelectedRow();
if (selRow != -1) {
int dataRow = table.convertRowIndexToModel(selRow);
if (dataRow != -1) {
action.actionPerformed(new ActionEvent(e.getSource(), e.getID(), "" + dataRow));
}
}
}
}
});
}
public void cleanUp() {
saveGuiSettings();
@ -620,15 +656,16 @@ public class TablesPanel extends javax.swing.JPanel {
formatFilterList.add(RowFilter.regexFilter("^Momir Basic|^Constructed - Pauper|^Constructed - Frontier|^Constructed - Extended|^Constructed - Eternal|^Constructed - Historical|^Constructed - Super|^Constructed - Freeform|^Australian Highlander|^Canadian Highlander|^Constructed - Old", TableTableModel.COLUMN_DECK_TYPE));
}
// skill
java.util.List<RowFilter<Object, Object>> skillFilterList = new ArrayList<>();
if (btnSkillBeginner.isSelected()) {
skillFilterList.add(RowFilter.regexFilter(SkillLevel.BEGINNER.toString(), TableTableModel.COLUMN_SKILL));
skillFilterList.add(RowFilter.regexFilter(this.tableModel.getSkillLevelAsCode(SkillLevel.BEGINNER, true), TableTableModel.COLUMN_SKILL));
}
if (btnSkillCasual.isSelected()) {
skillFilterList.add(RowFilter.regexFilter(SkillLevel.CASUAL.toString(), TableTableModel.COLUMN_SKILL));
if (btnSkillCasual.isSelected()) {
skillFilterList.add(RowFilter.regexFilter(this.tableModel.getSkillLevelAsCode(SkillLevel.CASUAL, true), TableTableModel.COLUMN_SKILL));
}
if (btnSkillSerious.isSelected()) {
skillFilterList.add(RowFilter.regexFilter(SkillLevel.SERIOUS.toString(), TableTableModel.COLUMN_SKILL));
skillFilterList.add(RowFilter.regexFilter(this.tableModel.getSkillLevelAsCode(SkillLevel.SERIOUS, true), TableTableModel.COLUMN_SKILL));
}
String ratedMark = TableTableModel.RATED_VALUE_YES;
@ -1221,6 +1258,7 @@ public class TablesPanel extends javax.swing.JPanel {
options.setSkillLevel(SkillLevel.CASUAL);
options.setRollbackTurnsAllowed(true);
options.setQuitRatio(100);
options.setMinimumRating(0);
String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> "");
options.setBannedUsers(IgnoreList.ignoreList(serverAddress));
table = SessionHandler.createTable(roomId, options);
@ -1335,14 +1373,15 @@ class TableTableModel extends AbstractTableModel {
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 ACTION_COLUMN = 11; // column the action is located (starting with 0)
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 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", "Rating", "Quit %", "Action"};
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 TableView[] tables = new TableView[0];
@ -1354,6 +1393,31 @@ class TableTableModel extends AbstractTableModel {
this.fireTableDataChanged();
}
public String getSkillLevelAsCode(SkillLevel skill, boolean asRegExp) {
String res;
switch (skill) {
case BEGINNER:
res = "*";
break;
case CASUAL:
res = "**";
break;
case SERIOUS:
res = "***";
break;
default:
res = "";
break;
}
// regexp format for search table rows
if (asRegExp) {
res = String.format("^%s$", res.replace("*", "\\*"));
}
return res;
}
@Override
public int getRowCount() {
return tables.length;
@ -1384,12 +1448,14 @@ class TableTableModel extends AbstractTableModel {
case 7:
return tables[arg0].getCreateTime(); // use cell render, not format here
case 8:
return tables[arg0].getSkillLevel();
return this.getSkillLevelAsCode(tables[arg0].getSkillLevel(), false);
case 9:
return tables[arg0].isRated() ? RATED_VALUE_YES : RATED_VALUE_NO;
case 10:
return tables[arg0].getQuitRatio();
case 11:
return tables[arg0].getMinimumRating();
case 12:
switch (tables[arg0].getTableState()) {
case WAITING:
@ -1419,14 +1485,14 @@ class TableTableModel extends AbstractTableModel {
default:
return "";
}
case 12:
return tables[arg0].isTournament();
case 13:
return tables[arg0].isTournament();
case 14:
if (!tables[arg0].getGames().isEmpty()) {
return tables[arg0].getGames().get(0);
}
return null;
case 14:
case 15:
return tables[arg0].getTableId();
}
return "";

View file

@ -1,8 +1,3 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.mage.card.arcane;
import java.awt.*;
@ -63,26 +58,26 @@ public final class CardRendererUtils {
int plus_b = (int) ((255 - b) / 2);
return new Color(r + plus_r,
g + plus_g,
b + plus_b,
alpha);
g + plus_g,
b + plus_b,
alpha);
}
public static Color abitdarker(Color c) {
int r = c.getRed();
int g = c.getGreen();
int b = c.getBlue();
int alpha = c.getAlpha();
int plus_r = (int) (Math.min (255 - r, r) / 2);
int plus_g = (int) (Math.min (255 - g, g) / 2);
int plus_b = (int) (Math.min (255 - b, b) / 2);
int plus_r = (int) (Math.min(255 - r, r) / 2);
int plus_g = (int) (Math.min(255 - g, g) / 2);
int plus_b = (int) (Math.min(255 - b, b) / 2);
return new Color(r - plus_r,
g - plus_g,
b - plus_b,
alpha);
}
g - plus_g,
b - plus_b,
alpha);
}
// Draw a rounded box with a 2-pixel border
// Used on various card parts.
@ -192,4 +187,12 @@ public final class CardRendererUtils {
.replaceAll("<i>", "")
.replaceAll("</i>", "");
}
public static Color copyColor(Color color) {
if (color != null) {
return new Color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
} else {
return null;
}
}
}

View file

@ -9,10 +9,13 @@ import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.StringTokenizer;
/**
* @author JayDi85
*/
public final class ManaSymbolsCellRenderer extends DefaultTableCellRenderer {
// base panel to render
private JPanel manaPanel = new JPanel();
private JPanel renderPanel = new JPanel();
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
@ -20,47 +23,47 @@ public final class ManaSymbolsCellRenderer extends DefaultTableCellRenderer {
// get table text cell settings
DefaultTableCellRenderer baseRenderer = (DefaultTableCellRenderer) table.getDefaultRenderer(String.class);
JLabel baseLabel = (JLabel)baseRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
JLabel baseComp = (JLabel) baseRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
// apply settings to mana panel from parent
manaPanel.setOpaque(baseLabel.isOpaque());
manaPanel.setForeground(baseLabel.getForeground());
manaPanel.setBackground(baseLabel.getBackground());
renderPanel.setOpaque(baseComp.isOpaque());
renderPanel.setForeground(CardRendererUtils.copyColor(baseComp.getForeground()));
renderPanel.setBackground(CardRendererUtils.copyColor(baseComp.getBackground()));
renderPanel.setBorder(baseComp.getBorder());
// icons size with margin
int symbolWidth = GUISizeHelper.symbolTableSize;
int symbolHorizontalMargin = 2;
// create each mana symbol as child label
String manaCost = (String)value;
manaPanel.removeAll();
manaPanel.setLayout(new BoxLayout(manaPanel, BoxLayout.X_AXIS));
if(manaCost != null){
String manaCost = (String) value;
renderPanel.removeAll();
renderPanel.setLayout(new BoxLayout(renderPanel, BoxLayout.X_AXIS));
if (manaCost != null) {
StringTokenizer tok = new StringTokenizer(manaCost, " ");
while (tok.hasMoreTokens()) {
String symbol = tok.nextToken();
JLabel symbolLabel = new JLabel();
//symbolLabel.setBorder(new LineBorder(new Color(150, 150, 150))); // debug
symbolLabel.setBorder(new EmptyBorder(0, symbolHorizontalMargin,0, 0));
symbolLabel.setBorder(new EmptyBorder(0, symbolHorizontalMargin, 0, 0));
BufferedImage image = ManaSymbols.getSizedManaSymbol(symbol, symbolWidth);
if (image != null){
if (image != null) {
// icon
symbolLabel.setIcon(new ImageIcon(image));
}else
{
} else {
// text
symbolLabel.setText("{" + symbol + "}");
symbolLabel.setOpaque(baseLabel.isOpaque());
symbolLabel.setForeground(baseLabel.getForeground());
symbolLabel.setBackground(baseLabel.getBackground());
symbolLabel.setOpaque(baseComp.isOpaque());
symbolLabel.setForeground(baseComp.getForeground());
symbolLabel.setBackground(baseComp.getBackground());
}
manaPanel.add(symbolLabel);
renderPanel.add(symbolLabel);
}
}
return manaPanel;
return renderPanel;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 658 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 931 B

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-common</artifactId>

View file

@ -13,8 +13,8 @@ public class MageVersion implements Serializable, Comparable<MageVersion> {
*/
public final static int MAGE_VERSION_MAJOR = 1;
public final static int MAGE_VERSION_MINOR = 4;
public final static int MAGE_VERSION_PATCH = 31;
public final static String MAGE_VERSION_MINOR_PATCH = "V4";
public final static int MAGE_VERSION_PATCH = 32;
public final static String MAGE_VERSION_MINOR_PATCH = "V0";
public final static String MAGE_VERSION_INFO = "";
private final int major;

View file

@ -36,6 +36,7 @@ public class TableView implements Serializable {
private List<SeatView> seats = new ArrayList<>();
private List<UUID> games = new ArrayList<>();
private final String quitRatio;
private final String minimumRating;
private final boolean limited;
private final boolean rated;
private final boolean passworded;
@ -111,6 +112,7 @@ public class TableView implements Serializable {
this.additionalInfo = addInfo.toString();
this.skillLevel = table.getMatch().getOptions().getSkillLevel();
this.quitRatio = Integer.toString(table.getMatch().getOptions().getQuitRatio());
this.minimumRating = Integer.toString(table.getMatch().getOptions().getMinimumRating());
this.limited = table.getMatch().getOptions().isLimited();
this.rated = table.getMatch().getOptions().isRated();
this.passworded = !table.getMatch().getOptions().getPassword().isEmpty();
@ -159,6 +161,7 @@ public class TableView implements Serializable {
this.deckType = table.getDeckType() + ' ' + table.getTournament().getBoosterInfo() + (tableNameInfo != null ? tableNameInfo : "");
this.skillLevel = table.getTournament().getOptions().getMatchOptions().getSkillLevel();
this.quitRatio = Integer.toString(table.getTournament().getOptions().getQuitRatio());
this.minimumRating = Integer.toString(table.getTournament().getOptions().getMinimumRating());
this.limited = table.getTournament().getOptions().getMatchOptions().isLimited();
this.rated = table.getTournament().getOptions().getMatchOptions().isRated();
this.passworded = !table.getTournament().getOptions().getPassword().isEmpty();
@ -223,9 +226,9 @@ public class TableView implements Serializable {
return skillLevel;
}
public String getQuitRatio() {
return quitRatio;
}
public String getQuitRatio() { return quitRatio; }
public String getMinimumRating() { return minimumRating; }
public boolean isLimited() {
return limited;

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-counter-plugin</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-plugins</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<groupId>org.mage</groupId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-deck-constructed</artifactId>

View file

@ -45,6 +45,7 @@ public class CanadianHighlander extends Constructed {
pointMap.put("Personal Tutor", 1);
pointMap.put("Protean Hulk", 3);
pointMap.put("Sol Ring", 3);
pointMap.put("Spellseeker", 1);
pointMap.put("Stoneforge Mystic", 1);
pointMap.put("Strip Mine", 2);
pointMap.put("Summoner's Pact", 2);

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-deck-limited</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-game-brawlduel</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-game-brawlfreeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-game-canadianhighlanderduel</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-game-commanderduel</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-game-commanderfreeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-game-freeforall</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-game-freeformcommanderfreeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-game-momirduel</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-game-momirfreeforall</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-game-pennydreadfulcommanderfreeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-game-tinyleadersduel</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-game-twoplayerduel</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-player-ai-draftbot</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-player-ai-ma</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-player-ai</artifactId>

View file

@ -861,6 +861,19 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
return target.isChosen();
}
if (target.getOriginalTarget() instanceof TargetCardInGraveyardOrBattlefield) {
List<Card> cards = new ArrayList<>();
for (Player player : game.getPlayers().values()) {
cards.addAll(player.getGraveyard().getCards(game));
cards.addAll(game.getBattlefield().getAllActivePermanents(new FilterPermanent(), player.getId(), game));
}
Card card = pickTarget(cards, outcome, target, source, game);
if (card != null) {
target.addTarget(card.getId(), source, game);
return true;
}
}
throw new IllegalStateException("Target wasn't handled. class:" + target.getClass().toString());
} //end of chooseTarget method

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-player-ai-mcts</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-player-aiminimax</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-player-human</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-tournament-boosterdraft</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-tournament-constructed</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-tournament-sealed</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-server-plugins</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<artifactId>mage-server</artifactId>

View file

@ -227,6 +227,20 @@ public class MageServerImpl implements MageServer {
user.showUserMessage("Create tournament", message);
throw new MageException("No message");
}
// check if the user satisfies the minimumRating requirement.
int minimumRating = options.getMinimumRating();
int userRating;
if (options.getMatchOptions().isLimited()) {
userRating = user.getUserData().getLimitedRating();
} else {
userRating = user.getUserData().getConstructedRating();
}
if (userRating < minimumRating) {
String message = new StringBuilder("Your rating ").append(userRating)
.append(" is lower than the table requirement ").append(minimumRating).toString();
user.showUserMessage("Create tournament", message);
throw new MageException("No message");
}
Optional<GamesRoom> room = GamesRoomManager.instance.getRoom(roomId);
if (!room.isPresent()) {
@ -1386,7 +1400,19 @@ public class MageServerImpl implements MageServer {
user.showUserMessage("Create table", "Your quit ratio " + user.getMatchQuitRatio() + "% is higher than the table requirement " + quitRatio + '%');
throw new MageException("No message");
}
// check if the user satisfies the minimumRating requirement.
int minimumRating = options.getMinimumRating();
int userRating;
if (options.isLimited()) {
userRating = user.getUserData().getLimitedRating();
} else {
userRating = user.getUserData().getConstructedRating();
}
if (userRating < minimumRating) {
String message = new StringBuilder("Your rating ").append(userRating).append(" is lower than the table requirement ").append(minimumRating).toString();
user.showUserMessage("Create table", message);
throw new MageException("No message");
}
Optional<GamesRoom> room = GamesRoomManager.instance.getRoom(roomId);
if (room.isPresent()) {
TableView table = room.get().createTable(userId, options);

View file

@ -172,6 +172,21 @@ public class TableController {
return false;
}
// Check minimum rating.
int minimumRating = table.getTournament().getOptions().getMinimumRating();
int userRating;
if (table.getTournament().getOptions().getMatchOptions().isLimited()) {
userRating = user.getUserData().getLimitedRating();
} else {
userRating = user.getUserData().getConstructedRating();
}
if (userRating < minimumRating) {
String message = new StringBuilder("Your rating ").append(userRating)
.append(" is lower than the table requirement ").append(minimumRating).toString();
user.showUserMessage("Join Table", message);
return false;
}
Optional<Player> playerOptional = createPlayer(name, seat.getPlayerType(), skill);
if (playerOptional.isPresent()) {
Player player = playerOptional.get();
@ -272,6 +287,21 @@ public class TableController {
return false;
}
// Check minimum rating.
int minimumRating = table.getMatch().getOptions().getMinimumRating();
int userRating;
if (table.getMatch().getOptions().isLimited()) {
userRating = user.getUserData().getLimitedRating();
} else {
userRating = user.getUserData().getConstructedRating();
}
if (userRating < minimumRating) {
String message = new StringBuilder("Your rating ").append(userRating)
.append(" is lower than the table requirement ").append(minimumRating).toString();
user.showUserMessage("Join Table", message);
return false;
}
// Check power level for table (currently only used for EDH/Commander table)
int edhPowerLevel = table.getMatch().getOptions().getEdhPowerLevel();
if (edhPowerLevel > 0 && table.getValidator().getName().toLowerCase(Locale.ENGLISH).equals("commander")) {

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.31</version>
<version>1.4.32</version>
</parent>
<groupId>org.mage</groupId>

View file

@ -1,10 +1,9 @@
package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.effects.common.LoseLifeOpponentsEffect;
import mage.abilities.effects.common.LoseLifeAllPlayersEffect;
import mage.abilities.keyword.MenaceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -18,7 +17,7 @@ import mage.constants.SubType;
public final class AdroitHateflayer extends CardImpl {
public AdroitHateflayer(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{U}{B}{R}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{B}{R}");
this.subtype.add(SubType.NAUTOLAN);
this.subtype.add(SubType.SITH);
this.power = new MageInt(3);
@ -26,9 +25,9 @@ public final class AdroitHateflayer extends CardImpl {
// Menace
this.addAbility(new MenaceAbility());
// Whenever Adroit Hateflayer attacks, each opponent loses 2 life.
this.addAbility(new AttacksTriggeredAbility(new LoseLifeOpponentsEffect(2), false));
// Whenever Adroit Hateflayer attacks, each player loses 2 life.
this.addAbility(new AttacksTriggeredAbility(new LoseLifeAllPlayersEffect(2), false));
}
public AdroitHateflayer(final AdroitHateflayer card) {

View file

@ -44,7 +44,7 @@ public class AminatouTheFateShifter extends CardImpl {
}
public AminatouTheFateShifter(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.PLANESWALKER},"{W}{U}{B}");
super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{W}{U}{B}");
this.addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.AMINATOU);
@ -56,7 +56,7 @@ public class AminatouTheFateShifter extends CardImpl {
// -1: Exile another target permanent you own, then return it to the battlefield under your control.
ability = new LoyaltyAbility(new ExileTargetForSourceEffect(), -1);
ability.addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect());
ability.addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect(true));
ability.addTarget(new TargetPermanent(filter));
this.addAbility(ability);
@ -68,6 +68,7 @@ public class AminatouTheFateShifter extends CardImpl {
// Aminatou, the Fateshifter can be your commander.
this.addAbility(CanBeYourCommanderAbility.getInstance());
}
public AminatouTheFateShifter(final AminatouTheFateShifter card) {
super(card);
}
@ -79,6 +80,7 @@ public class AminatouTheFateShifter extends CardImpl {
}
class AminatouPlusEffect extends OneShotEffect {
public AminatouPlusEffect() {
super(Outcome.DrawCard);
staticText = "draw a card, then put a card from your hand on top of your library";
@ -118,10 +120,11 @@ class AminatouPlusEffect extends OneShotEffect {
}
class AminatouUltimateEffect extends OneShotEffect {
public AminatouUltimateEffect (){
public AminatouUltimateEffect() {
super(Outcome.Benefit);
staticText = "Choose left or right. Each player gains control of all nonland permanents other than Aminatou," +
" the Fateshifter controlled by the next player in the chosen direction.";
staticText = "Choose left or right. Each player gains control of all nonland permanents other than Aminatou,"
+ " the Fateshifter controlled by the next player in the chosen direction.";
}
public AminatouUltimateEffect(final AminatouUltimateEffect effect) {
@ -129,7 +132,9 @@ class AminatouUltimateEffect extends OneShotEffect {
}
@Override
public AminatouUltimateEffect copy(){return new AminatouUltimateEffect(this);}
public AminatouUltimateEffect copy() {
return new AminatouUltimateEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
@ -154,7 +159,7 @@ class AminatouUltimateEffect extends OneShotEffect {
return false;
}
// skip players out of range
if (!game.getState().getPlayersInRange(controller.getId(), game).contains(nextPlayer)){
if (!game.getState().getPlayersInRange(controller.getId(), game).contains(nextPlayer)) {
continue;
}
// save first next player to check for iteration stop
@ -164,7 +169,7 @@ class AminatouUltimateEffect extends OneShotEffect {
FilterNonlandPermanent nextPlayerNonlandPermanentsFilter = new FilterNonlandPermanent();
nextPlayerNonlandPermanentsFilter.add(new ControllerIdPredicate(nextPlayer));
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(nextPlayerNonlandPermanentsFilter, game)) {
if (permanent.getId().equals(source.getSourceId())){
if (permanent.getId().equals(source.getSourceId())) {
continue;
}
ContinuousEffect effect = new GainControlTargetEffect(Duration.EndOfGame, currentPlayer);
@ -188,4 +193,3 @@ class AminatouUltimateEffect extends OneShotEffect {
return nextPlayerId;
}
}

View file

@ -1,43 +1,34 @@
package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
import mage.abilities.common.ZoneChangeTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ExileTargetForSourceEffect;
import mage.abilities.effects.common.ReturnFromExileForSourceEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.common.FilterCreatureCard;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.AnotherPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardIdPredicate;
import mage.target.Target;
import mage.target.common.TargetCardInGraveyard;
import mage.target.common.TargetCreaturePermanent;
import mage.util.CardUtil;
import mage.target.common.TargetCardInGraveyardOrBattlefield;
/**
*
* @author LevelX2
*/
public final class AngelOfSerenity extends CardImpl {
private static final String rule = "you may exile up to three other target creatures from the battlefield and/or creature cards from graveyards.";
public AngelOfSerenity(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{W}{W}{W}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}{W}");
this.subtype.add(SubType.ANGEL);
this.power = new MageInt(5);
@ -47,7 +38,12 @@ public final class AngelOfSerenity extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// When Angel of Serenity enters the battlefield, you may exile up to three other target creatures from the battlefield and/or creature cards from graveyards.
this.addAbility(new AngelOfSerenityTriggeredAbility());
FilterCreatureCard filter = new FilterCreatureCard("creatures from the battlefield and/or a graveyard");
filter.add(Predicates.not(new CardIdPredicate(this.getId())));
Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect().setText(rule), true);
Target target = new TargetCardInGraveyardOrBattlefield(0, 3, filter);
ability.addTarget(target);
this.addAbility(ability);
// When Angel of Serenity leaves the battlefield, return the exiled cards to their owners' hands.
this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.HAND, false, true), false));
@ -62,92 +58,3 @@ public final class AngelOfSerenity extends CardImpl {
return new AngelOfSerenity(this);
}
}
class AngelOfSerenityTriggeredAbility extends ZoneChangeTriggeredAbility {
public AngelOfSerenityTriggeredAbility() {
super(Zone.BATTLEFIELD, new AngelOfSerenityEnterEffect(), "When {this} enters the battlefield, ", true);
}
public AngelOfSerenityTriggeredAbility(AngelOfSerenityTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (super.checkTrigger(event, game)) {
getTargets().clear();
FilterCreaturePermanent filter = new FilterCreaturePermanent("up to three other target creatures");
filter.add(new AnotherPredicate());
TargetCreaturePermanent target1 = new TargetCreaturePermanent(0, 3, filter, false);
game.getPlayer(getControllerId()).chooseTarget(Outcome.Exile, target1, this, game);
if (!target1.getTargets().isEmpty()) {
getTargets().add(target1);
}
int leftTargets = 3 - target1.getTargets().size();
if (leftTargets > 0) {
FilterCard filter2 = new FilterCreatureCard("up to " + leftTargets + " target creature card" + (leftTargets > 1 ? "s" : "") + " from graveyards");
TargetCardInGraveyard target2 = new TargetCardInGraveyard(0, leftTargets, filter2);
game.getPlayer(getControllerId()).chooseTarget(Outcome.Exile, target2, this, game);
if (!target2.getTargets().isEmpty()) {
getTargets().add(target2);
}
}
return true;
}
return false;
}
@Override
public AngelOfSerenityTriggeredAbility copy() {
return new AngelOfSerenityTriggeredAbility(this);
}
}
class AngelOfSerenityEnterEffect extends OneShotEffect {
public AngelOfSerenityEnterEffect() {
super(Outcome.ReturnToHand);
this.staticText = "you may exile up to three other target creatures from the battlefield and/or creature cards from graveyards";
}
public AngelOfSerenityEnterEffect(final AngelOfSerenityEnterEffect effect) {
super(effect);
}
@Override
public AngelOfSerenityEnterEffect copy() {
return new AngelOfSerenityEnterEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
boolean result = true;
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source.getSourceId());
if (controller != null && sourceObject != null && !source.getTargets().isEmpty()) {
UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
for (Target target : source.getTargets()) {
if (target instanceof TargetCreaturePermanent) {
for (UUID permanentId : target.getTargets()) {
Permanent permanent = game.getPermanent(permanentId);
if (permanent != null) {
result |= controller.moveCardToExileWithInfo(permanent, exileZoneId, sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true);
}
}
} else if (target instanceof TargetCardInGraveyard) {
for (UUID cardId : target.getTargets()) {
Card card = game.getCard(cardId);
if (card != null) {
result |= controller.moveCardToExileWithInfo(card, exileZoneId, sourceObject.getIdName(), source.getSourceId(), game, Zone.GRAVEYARD, true);
}
}
}
}
}
return result;
}
}

View file

@ -0,0 +1,67 @@
package mage.cards.a;
import java.util.UUID;
import mage.constants.SubType;
import mage.target.common.TargetCreaturePermanent;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.dynamicvalue.common.CountersSourceCount;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.constants.Outcome;
import mage.target.TargetPermanent;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AttachmentType;
import mage.constants.CardType;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.target.common.TargetAttackingOrBlockingCreature;
/**
*
* @author jeffwadsworth
*/
public final class ArcheryTraining extends CardImpl {
private static final String rule = "This creature deals X damage to target attacking or blocking creature, where X is the number of arrow counters on {this}.";
public ArcheryTraining(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}");
this.subtype.add(SubType.AURA);
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature));
Ability ability = new EnchantAbility(auraTarget.getTargetName());
this.addAbility(ability);
// At the beginning of your upkeep, you may put an arrow counter on Archery Training.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD,
new AddCountersSourceEffect(CounterType.ARROW.createInstance(), true), TargetController.YOU, true));
// Enchanted creature has "{tap}: This creature deals X damage to target attacking or blocking creature, where X is the number of arrow counters on Archery Training."
Ability gainedAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new CountersSourceCount(CounterType.ARROW)).setText(rule), new TapSourceCost());
gainedAbility.addTarget(new TargetAttackingOrBlockingCreature());
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(gainedAbility, AttachmentType.AURA)));
}
public ArcheryTraining(final ArcheryTraining card) {
super(card);
}
@Override
public ArcheryTraining copy() {
return new ArcheryTraining(this);
}
}

View file

@ -1,14 +1,14 @@
package mage.cards.b;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.effects.common.SkipNextCombatEffect;
import mage.abilities.effects.common.SkipCombatStepEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
/**
@ -16,26 +16,28 @@ import mage.constants.SubType;
* @author Plopman
*/
public final class BlindingAngel extends CardImpl {
public BlindingAngel(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}{W}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}");
this.subtype.add(SubType.ANGEL);
this.power = new MageInt(2);
this.toughness = new MageInt(4);
// Flying
this.addAbility(FlyingAbility.getInstance());
// Whenever Blinding Angel deals combat damage to a player, that player skips their next combat phase.
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new SkipNextCombatEffect(), false, true));
}
// Whenever Blinding Angel deals combat damage to a player, that player skips their next combat phase.
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new SkipCombatStepEffect(Duration.OneUse).setText("that player skips their next combat phase."), false, true));
}
public BlindingAngel(final BlindingAngel card) {
super(card);
}
@Override
public BlindingAngel copy() {
return new BlindingAngel(this);
}
}
}

View file

@ -0,0 +1,91 @@
package mage.cards.b;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.decorator.ConditionalReplacementEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.PreventAllDamageToSourceEffect;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.Spell;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.permanent.AnotherPredicate;
import mage.target.Target;
/**
*
* @author L_J
*/
public final class BronzeHorse extends CardImpl {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent();
static {
filter.add(new AnotherPredicate());
}
public BronzeHorse(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT, CardType.CREATURE},"{7}");
this.subtype.add(SubType.HORSE);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
// Trample
this.addAbility(TrampleAbility.getInstance());
// As long as you control another creature, prevent all damage that would be dealt to Bronze Horse by spells that target it.
Effect effect = new ConditionalReplacementEffect(new PreventDamageToSourceBySpellsThatTargetIt(), new PermanentsOnTheBattlefieldCondition(filter));
effect.setText("As long as you control another creature, prevent all damage that would be dealt to {this} by spells that target it.");
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
}
public BronzeHorse(final BronzeHorse card) {
super(card);
}
@Override
public BronzeHorse copy() {
return new BronzeHorse(this);
}
}
class PreventDamageToSourceBySpellsThatTargetIt extends PreventAllDamageToSourceEffect {
public PreventDamageToSourceBySpellsThatTargetIt() {
super(Duration.WhileOnBattlefield);
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (super.applies(event, source, game)) {
if (event.getTargetId().equals(source.getSourceId())) {
Spell spell = game.getStack().getSpell(event.getSourceId());
if (spell != null) {
for (UUID modeId : spell.getStackAbility().getModes().getSelectedModes()) {
Mode mode = spell.getStackAbility().getModes().get(modeId);
for (Target target : mode.getTargets()) {
for (UUID targetId : target.getTargets()) {
if (targetId.equals(source.getSourceId())) {
return true;
}
}
}
}
}
}
}
return false;
}
}

View file

@ -0,0 +1,52 @@
package mage.cards.c;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.InfoEffect;
import mage.abilities.effects.common.PutOnLibraryTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.target.common.TargetCardInYourGraveyard;
/**
*
* @author L_J
*/
public final class CanalDredger extends CardImpl {
public CanalDredger(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}");
this.subtype.add(SubType.CONSTRUCT);
this.power = new MageInt(1);
this.toughness = new MageInt(5);
// TODO: Draft specific abilities not implemented
// Draft Canal Dredger face up.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft Canal Dredger face up.")));
// Each player passes the last card from each booster pack to a player who drafted a card named Canal Dredger.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Each player passes the last card from each booster pack to a player who drafted a card named Canal Dredger.")));
// {T}: Put target card from your graveyard on the bottom of your library.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutOnLibraryTargetEffect(false), new TapSourceCost());
ability.addTarget(new TargetCardInYourGraveyard());
this.addAbility(ability);
}
public CanalDredger(final CanalDredger card) {
super(card);
}
@Override
public CanalDredger copy() {
return new CanalDredger(this);
}
}

View file

@ -0,0 +1,93 @@
package mage.cards.c;
import java.util.UUID;
import mage.constants.SubType;
import mage.target.common.TargetCreaturePermanent;
import mage.abilities.Ability;
import mage.abilities.common.AttacksAttachedTriggeredAbility;
import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.ReturnToHandSourceEffect;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.constants.Outcome;
import mage.target.TargetPermanent;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.targetpointer.FixedTarget;
/**
*
* @author jeffwadsworth
*/
public final class Contempt extends CardImpl {
public Contempt(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}");
this.subtype.add(SubType.AURA);
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature));
Ability ability = new EnchantAbility(auraTarget.getTargetName());
this.addAbility(ability);
// Whenever enchanted creature attacks, return it and Contempt to their owners' hands at end of combat.
this.addAbility(new AttacksAttachedTriggeredAbility(new ContemptEffect()));
}
public Contempt(final Contempt card) {
super(card);
}
@Override
public Contempt copy() {
return new Contempt(this);
}
}
class ContemptEffect extends OneShotEffect {
ContemptEffect() {
super(Outcome.Detriment);
this.staticText = "return it and {this} to their owners' hands at end of combat.";
}
ContemptEffect(final ContemptEffect effect) {
super(effect);
}
@Override
public ContemptEffect copy() {
return new ContemptEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent contempt = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (contempt != null) {
Permanent attachedToPermanent = game.getPermanent(contempt.getAttachedTo());
if (attachedToPermanent != null) {
Effect effect = new ReturnToHandTargetEffect();
effect.setTargetPointer(new FixedTarget(
attachedToPermanent.getId())).setText("return "
+ attachedToPermanent.getName() + " to owner's hand.");
AtTheEndOfCombatDelayedTriggeredAbility ability = new AtTheEndOfCombatDelayedTriggeredAbility(effect);
game.addDelayedTriggeredAbility(ability, source);
}
Effect effect = new ReturnToHandSourceEffect();
AtTheEndOfCombatDelayedTriggeredAbility ability = new AtTheEndOfCombatDelayedTriggeredAbility(effect);
game.addDelayedTriggeredAbility(ability, source);
return true;
}
return false;
}
}

View file

@ -0,0 +1,50 @@
package mage.cards.d;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.DrawDiscardControllerEffect;
import mage.abilities.effects.common.InfoEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
/**
*
* @author L_J
*/
public final class DealBroker extends CardImpl {
public DealBroker(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT, CardType.CREATURE},"{3}");
this.subtype.add(SubType.CONSTRUCT);
this.power = new MageInt(2);
this.toughness = new MageInt(3);
// TODO: Draft specific abilities not implemented
// Draft Deal Broker face up.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft Deal Broker face up.")));
// Immediately after the draft, you may reveal a card in your card pool. Each other player may offer you one card in their card pool in exchange. You may accept any one offer.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Immediately after the draft, you may reveal a card in your card pool. "
+ "Each other player may offer you one card in their card pool in exchange. You may accept any one offer.")));
// {T}: Draw a card, then discard a card.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawDiscardControllerEffect(), new TapSourceCost()));
}
public DealBroker(final DealBroker card) {
super(card);
}
@Override
public DealBroker copy() {
return new DealBroker(this);
}
}

View file

@ -0,0 +1,87 @@
package mage.cards.d;
import java.util.UUID;
import mage.constants.SubType;
import mage.target.common.TargetCreaturePermanent;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.AttachEffect;
import mage.constants.Outcome;
import mage.target.TargetPermanent;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
/**
*
* @author jeffwadsworth
*/
public final class Disappear extends CardImpl {
public Disappear(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}");
this.subtype.add(SubType.AURA);
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature));
Ability ability = new EnchantAbility(auraTarget.getTargetName());
this.addAbility(ability);
// {U}: Return enchanted creature and Disappear to their owners' hands.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new DisappearEffect(), new ManaCostsImpl("{U}")));
}
public Disappear(final Disappear card) {
super(card);
}
@Override
public Disappear copy() {
return new Disappear(this);
}
}
class DisappearEffect extends OneShotEffect {
public DisappearEffect() {
super(Outcome.ReturnToHand);
staticText = "Return enchanted creature and {this} to their owners' hands";
}
public DisappearEffect(final DisappearEffect effect) {
super(effect);
}
@Override
public DisappearEffect copy() {
return new DisappearEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent aura = (Permanent) game.getPermanentOrLKIBattlefield(source.getSourceId());
Player controller = game.getPlayer(source.getControllerId());
if (controller != null
&& aura != null
&& aura.getAttachedTo() != null) {
Permanent enchantedCreature = game.getPermanent(aura.getAttachedTo());
controller.moveCards(aura, Zone.HAND, source, game);
if (enchantedCreature != null) {
controller.moveCards(enchantedCreature, Zone.HAND, source, game);
}
return true;
}
return false;
}
}

View file

@ -0,0 +1,200 @@
package mage.cards.d;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.BeginningOfYourEndStepTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.discard.DiscardControllerEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.Player;
import mage.util.CardUtil;
/**
*
* @author jeffwadsworth
*/
public final class Duplicity extends CardImpl {
public Duplicity(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}");
// When Duplicity enters the battlefield, exile the top five cards of your library face down.
this.addAbility(new EntersBattlefieldTriggeredAbility(new DuplicityEffect(), false));
// At the beginning of your upkeep, you may exile all cards from your hand face down. If you do, put all other cards you own exiled with Duplicity into your hand.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DuplicityExileHandEffect(), TargetController.YOU, true));
// At the beginning of your end step, discard a card.
this.addAbility(new BeginningOfYourEndStepTriggeredAbility(new DiscardControllerEffect(1), false));
// When you lose control of Duplicity, put all cards exiled with Duplicity into their owner's graveyard.
this.addAbility(new LoseControlDuplicity());
}
public Duplicity(final Duplicity card) {
super(card);
}
@Override
public Duplicity copy() {
return new Duplicity(this);
}
}
class DuplicityEffect extends OneShotEffect {
public DuplicityEffect() {
super(Outcome.Exile);
staticText = "exile the top five cards of your library face down";
}
public DuplicityEffect(final DuplicityEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source.getSourceId());
if (controller != null
&& sourceObject != null) {
if (controller.getLibrary().hasCards()) {
UUID exileId = CardUtil.getCardExileZoneId(game, source);
Set<Card> cardsToExile = controller.getLibrary().getTopCards(game, 5);
for (Card card : cardsToExile) {
controller.moveCardsToExile(card, source, game, true, exileId, sourceObject.getName());
card.setFaceDown(true, game);
}
}
return true;
}
return false;
}
@Override
public DuplicityEffect copy() {
return new DuplicityEffect(this);
}
}
class DuplicityExileHandEffect extends OneShotEffect {
public DuplicityExileHandEffect() {
super(Outcome.Exile);
staticText = "you may exile all cards from your hand face down. If you do, put all other cards you own exiled with {this} into your hand";
}
public DuplicityExileHandEffect(final DuplicityExileHandEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source.getSourceId());
if (controller != null
&& sourceObject != null) {
if (!controller.getHand().isEmpty()) {
UUID exileId = CardUtil.getCardExileZoneId(game, source);
Set<Card> cardsFromHandToExile = controller.getHand().getCards(game);
for (Card card : cardsFromHandToExile) {
controller.moveCardsToExile(card, source, game, true, exileId, sourceObject.getName());
card.setFaceDown(true, game);
}
Set<Card> cardsInExile = game.getExile().getExileZone(exileId).getCards(game);
Set<Card> cardsToReturnToHandFromExile = new HashSet<>();
for (Card card : cardsInExile) {
if (!cardsFromHandToExile.contains(card)) {
cardsToReturnToHandFromExile.add(card);
}
}
controller.moveCards(cardsToReturnToHandFromExile, Zone.HAND, source, game);
}
return true;
}
return false;
}
@Override
public DuplicityExileHandEffect copy() {
return new DuplicityExileHandEffect(this);
}
}
class LoseControlDuplicity extends DelayedTriggeredAbility {
public LoseControlDuplicity() {
super(new PutExiledCardsInOwnersGraveyard(), Duration.EndOfGame, false);
}
public LoseControlDuplicity(final LoseControlDuplicity ability) {
super(ability);
}
@Override
public LoseControlDuplicity copy() {
return new LoseControlDuplicity(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.LOST_CONTROL;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return event.getPlayerId().equals(controllerId);
}
@Override
public String getRule() {
return "When you lose control of {this}, put all cards exiled with {this} into their owner's graveyard.";
}
}
class PutExiledCardsInOwnersGraveyard extends OneShotEffect {
public PutExiledCardsInOwnersGraveyard() {
super(Outcome.Neutral);
staticText = " put all cards exiled with {this} into their owner's graveyard.";
}
public PutExiledCardsInOwnersGraveyard(final PutExiledCardsInOwnersGraveyard effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source.getSourceId());
if (controller != null
&& sourceObject != null) {
UUID exileId = CardUtil.getCardExileZoneId(game, source);
Set<Card> cardsInExile = game.getExile().getExileZone(exileId).getCards(game);
controller.moveCardsToGraveyardWithInfo(cardsInExile, source, game, Zone.EXILED);
return true;
}
return false;
}
@Override
public PutExiledCardsInOwnersGraveyard copy() {
return new PutExiledCardsInOwnersGraveyard(this);
}
}

View file

@ -0,0 +1,102 @@
package mage.cards.e;
import java.util.UUID;
import mage.MageInt;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleEvasionAbility;
import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect;
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.filter.common.FilterControlledPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetControlledPermanent;
/**
*
* @author L_J
*/
public final class ElderSpawn extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("red creatures");
static {
filter.add(new ColorPredicate(ObjectColor.RED));
}
public ElderSpawn(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}{U}");
this.subtype.add(SubType.SPAWN);
this.power = new MageInt(6);
this.toughness = new MageInt(6);
// At the beginning of your upkeep, unless you sacrifice an Island, sacrifice Elder Spawn and it deals 6 damage to you.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new ElderSpawnEffect(), TargetController.YOU, false));
// Elder Spawn can't be blocked by red creatures.
this.addAbility(new SimpleEvasionAbility(new CantBeBlockedByCreaturesSourceEffect(filter, Duration.WhileOnBattlefield)));
}
public ElderSpawn(final ElderSpawn card) {
super(card);
}
@Override
public ElderSpawn copy() {
return new ElderSpawn(this);
}
}
class ElderSpawnEffect extends OneShotEffect {
private static final FilterControlledPermanent filter = new FilterControlledPermanent("an Island");
static {
filter.add(new SubtypePredicate(SubType.ISLAND));
}
public ElderSpawnEffect() {
super(Outcome.Sacrifice);
staticText = "unless you sacrifice an Island, sacrifice {this} and it deals 6 damage to you";
}
public ElderSpawnEffect(final ElderSpawnEffect effect) {
super(effect);
}
@Override
public ElderSpawnEffect copy() {
return new ElderSpawnEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (controller != null && sourcePermanent != null) {
TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true);
SacrificeTargetCost cost = new SacrificeTargetCost(target);
if (!controller.chooseUse(Outcome.AIDontUseIt, "Do you wish to sacrifice an Island?", source, game)
|| !cost.canPay(source, source.getSourceId(), source.getControllerId(), game)
|| !cost.pay(source, game, source.getSourceId(), source.getControllerId(), true)) {
sourcePermanent.sacrifice(source.getSourceId(), game);
controller.damage(6, sourcePermanent.getId(), game, false, true);
}
return true;
}
return false;
}
}

View file

@ -1,11 +1,11 @@
package mage.cards.e;
import java.util.UUID;
import mage.abilities.effects.common.SkipNextCombatEffect;
import mage.abilities.effects.common.SkipCombatStepEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.target.common.TargetOpponent;
/**
@ -15,10 +15,10 @@ import mage.target.common.TargetOpponent;
public final class EmptyCityRuse extends CardImpl {
public EmptyCityRuse(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{W}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{W}");
// Target opponent skips all combat phases of their next turn.
this.getSpellAbility().addEffect(new SkipNextCombatEffect());
this.getSpellAbility().addEffect(new SkipCombatStepEffect(Duration.UntilYourNextTurn).setText("Target opponent skips all combat phases of their next turn."));
this.getSpellAbility().addTarget(new TargetOpponent());
}
@ -30,4 +30,4 @@ public final class EmptyCityRuse extends CardImpl {
public EmptyCityRuse copy() {
return new EmptyCityRuse(this);
}
}
}

View file

@ -0,0 +1,79 @@
package mage.cards.e;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.PreventAllDamageToSourceEffect;
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.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
/**
*
* @author L_J
*/
public final class EnchantedBeing extends CardImpl {
public EnchantedBeing(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}");
this.subtype.add(SubType.HUMAN);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Prevent all damage that would be dealt to Enchanted Being by enchanted creatures.
Effect effect = new PreventDamageToSourceByEnchantedCreatures();
effect.setText("Prevent all damage that would be dealt to {this} by enchanted creatures.");
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
}
public EnchantedBeing(final EnchantedBeing card) {
super(card);
}
@Override
public EnchantedBeing copy() {
return new EnchantedBeing(this);
}
}
class PreventDamageToSourceByEnchantedCreatures extends PreventAllDamageToSourceEffect {
public PreventDamageToSourceByEnchantedCreatures() {
super(Duration.WhileOnBattlefield);
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (super.applies(event, source, game)) {
if (isEnchantedCreature(game.getObject(event.getSourceId()), game)) {
if (event.getTargetId().equals(source.getSourceId())) {
return true;
}
}
}
return false;
}
public boolean isEnchantedCreature(MageObject input, Game game) {
if (input == null || input.isCreature()) {
return false;
}
for (UUID attachmentId : ((Permanent) input).getAttachments()) {
Permanent attachment = game.getPermanent(attachmentId);
if (attachment != null && attachment.isEnchantment()) {
return true;
}
}
return false;
}
}

View file

@ -1,11 +1,11 @@
package mage.cards.f;
import java.util.UUID;
import mage.abilities.effects.common.SkipNextCombatEffect;
import mage.abilities.effects.common.SkipCombatStepEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.target.TargetPlayer;
/**
@ -13,19 +13,19 @@ import mage.target.TargetPlayer;
* @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
*/
public final class FalsePeace extends CardImpl {
public FalsePeace(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{W}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{W}");
// Target player skips all combat phases of their next turn.
this.getSpellAbility().addEffect(new SkipNextCombatEffect());
this.getSpellAbility().addEffect(new SkipCombatStepEffect(Duration.UntilYourNextTurn).setText("Target player skips all combat phases of their next turn."));
this.getSpellAbility().addTarget(new TargetPlayer());
}
public FalsePeace(final FalsePeace card) {
super(card);
}
@Override
public FalsePeace copy() {
return new FalsePeace(this);

View file

@ -0,0 +1,36 @@
package mage.cards.f;
import java.util.UUID;
import mage.abilities.effects.common.SkipNextDrawStepTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.target.TargetPlayer;
/**
*
* @author jeffwadsworth
*/
public final class Fatigue extends CardImpl {
private static final String rule = "Target player skips his or her next draw step.";
public Fatigue(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}");
// Target player skips his or her next draw step.
this.getSpellAbility().addEffect(new SkipNextDrawStepTargetEffect().setText(rule));
this.getSpellAbility().addTarget(new TargetPlayer());
}
public Fatigue(final Fatigue card) {
super(card);
}
@Override
public Fatigue copy() {
return new Fatigue(this);
}
}

View file

@ -0,0 +1,41 @@
package mage.cards.f;
import java.util.UUID;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.PreventDamageByTargetEffect;
import mage.abilities.keyword.CyclingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author jeffwadsworth
*/
public final class FendOff extends CardImpl {
private static final String rule = "Prevent all combat damage that would be dealt by target creature this turn.";
public FendOff(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}");
// Prevent all combat damage that would be dealt by target creature this turn.
this.getSpellAbility().addEffect(new PreventDamageByTargetEffect(Duration.EndOfTurn, true).setText(rule));
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
// Cycling {2}
this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}")));
}
public FendOff(final FendOff card) {
super(card);
}
@Override
public FendOff copy() {
return new FendOff(this);
}
}

View file

@ -156,39 +156,44 @@ class FlickerformReturnEffect extends OneShotEffect {
}
ExileZone exileZone = game.getExile().getExileZone(exileZoneId);
Card enchantedCard = exileZone.get(enchantedCardId, game);
//skip if exiled card is missing
if (enchantedCard != null) {
controller.moveCards(enchantedCard, Zone.BATTLEFIELD, source, game);
Permanent newPermanent = game.getPermanent(enchantedCardId);
if (newPermanent != null) {
Set<Card> toBattlefieldAttached = new HashSet<Card>();
for (Card enchantment : exileZone.getCards(game)) {
if (filterAura.match(enchantment, game)) {
boolean canTarget = false;
for (Target target : enchantment.getSpellAbility().getTargets()) {
Filter filter = target.getFilter();
if (filter.match(newPermanent, game)) {
canTarget = true;
break;
Player owner = game.getPlayer(enchantedCard.getOwnerId());
//skip if card's owner is missing
if (owner != null) {
owner.moveCards(enchantedCard, Zone.BATTLEFIELD, source, game);
Permanent newPermanent = game.getPermanent(enchantedCardId);
if (newPermanent != null) {
Set<Card> toBattlefieldAttached = new HashSet<Card>();
for (Card enchantment : exileZone.getCards(game)) {
if (filterAura.match(enchantment, game)) {
boolean canTarget = false;
for (Target target : enchantment.getSpellAbility().getTargets()) {
Filter filter = target.getFilter();
if (filter.match(newPermanent, game)) {
canTarget = true;
break;
}
}
if (!canTarget) {
// Aura stays exiled
continue;
}
game.getState().setValue("attachTo:" + enchantment.getId(), newPermanent);
}
toBattlefieldAttached.add(enchantment);
}
if (!toBattlefieldAttached.isEmpty()) {
controller.moveCards(toBattlefieldAttached, Zone.BATTLEFIELD, source, game);
for (Card card : toBattlefieldAttached) {
if (game.getState().getZone(card.getId()) == Zone.BATTLEFIELD) {
newPermanent.addAttachment(card.getId(), game);
}
}
if (!canTarget) {
// Aura stays exiled
continue;
}
game.getState().setValue("attachTo:" + enchantment.getId(), newPermanent);
}
toBattlefieldAttached.add(enchantment);
}
if (!toBattlefieldAttached.isEmpty()) {
controller.moveCards(toBattlefieldAttached, Zone.BATTLEFIELD, source, game);
for (Card card : toBattlefieldAttached) {
if (game.getState().getZone(card.getId()) == Zone.BATTLEFIELD) {
newPermanent.addAttachment(card.getId(), game);
}
}
}
return true;
}
return true;
}
return false;
}

View file

@ -0,0 +1,91 @@
package mage.cards.f;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent;
/**
*
* @author L_J
*/
public final class ForethoughtAmulet extends CardImpl {
public ForethoughtAmulet(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}");
// At the beginning of your upkeep, sacrifice Forethought Amulet unless you pay {3}.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new GenericManaCost(3)), TargetController.YOU, false));
// If an instant or sorcery source would deal 3 or more damage to you, it deals 2 damage to you instead.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ForethoughtAmuletEffect()));
}
public ForethoughtAmulet(final ForethoughtAmulet card) {
super(card);
}
@Override
public ForethoughtAmulet copy() {
return new ForethoughtAmulet(this);
}
}
class ForethoughtAmuletEffect extends ReplacementEffectImpl {
public ForethoughtAmuletEffect() {
super(Duration.WhileOnBattlefield, Outcome.Neutral);
staticText = "If an instant or sorcery source would deal 3 or more damage to you, it deals 2 damage to you instead";
}
public ForethoughtAmuletEffect(final ForethoughtAmuletEffect effect) {
super(effect);
}
@Override
public ForethoughtAmuletEffect copy() {
return new ForethoughtAmuletEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DAMAGE_PLAYER;
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getAmount() >= 3) {
MageObject object = game.getObject(event.getSourceId());
return object != null && (object.isInstant() || object.isSorcery());
}
return false;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
if (event.getTargetId().equals(source.getControllerId())) {
event.setAmount(2);
}
return false;
}
}

View file

@ -1,4 +1,3 @@
package mage.cards.g;
import java.util.UUID;
@ -16,7 +15,6 @@ import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.filter.common.FilterBasicLandCard;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
@ -30,7 +28,7 @@ import mage.target.common.TargetLandPermanent;
public final class GhostQuarter extends CardImpl {
public GhostQuarter(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// {T}: Add {C}.
this.addAbility(new ColorlessManaAbility());

View file

@ -77,9 +77,9 @@ class GoblinMachinistEffect extends OneShotEffect {
break;
}
}
controller.revealCards(source, cards, game);
controller.putCardsOnBottomOfLibrary(cards, game, source, true);
}
controller.revealCards(source, cards, game);
controller.putCardsOnBottomOfLibrary(cards, game, source, true);
return true;
}
return false;

View file

@ -71,7 +71,10 @@ class HiddenPredatorsStateTriggeredAbility extends StateTriggeredAbility {
@Override
public boolean checkInterveningIfClause(Game game) {
return this.getSourcePermanentIfItStillExists(game).getCardType().contains(CardType.ENCHANTMENT);
if (getSourcePermanentIfItStillExists(game) != null) {
return getSourcePermanentIfItStillExists(game).isEnchantment();
}
return false;
}
@Override

View file

@ -59,14 +59,16 @@ class IcequakeEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null && controller != null) {
permanent.destroy(source.getSourceId(), game, false);
if (permanent.isSnow()) {
controller.damage(1, source.getSourceId(), game, false, true);
if (permanent != null) {
Player controller = game.getPlayer(permanent.getControllerId());
if(controller != null) {
permanent.destroy(source.getSourceId(), game, false);
if (permanent.isSnow()) {
controller.damage(1, source.getSourceId(), game, false, true);
}
return true;
}
return true;
}
return false;
}

View file

@ -0,0 +1,65 @@
package mage.cards.i;
import java.util.UUID;
import mage.constants.SubType;
import mage.target.common.TargetCreaturePermanent;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.DiesAttachedTriggeredAbility;
import mage.abilities.dynamicvalue.common.CountersSourceCount;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.constants.Outcome;
import mage.target.TargetPermanent;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.target.common.TargetCreatureOrPlayer;
/**
*
* @author jeffwadsworth
*/
public final class Incendiary extends CardImpl {
private static final String rule = "{this} deals X damage to any target, where X is the number of fuse counters on {this}.";
public Incendiary(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}");
this.subtype.add(SubType.AURA);
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature));
Ability ability = new EnchantAbility(auraTarget.getTargetName());
this.addAbility(ability);
// At the beginning of your upkeep, you may put a fuse counter on Incendiary.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD,
new AddCountersSourceEffect(CounterType.FUSE.createInstance(), true), TargetController.YOU, true));
// When enchanted creature dies, Incendiary deals X damage to any target, where X is the number of fuse counters on Incendiary.
Effect effect = new DamageTargetEffect(new CountersSourceCount(CounterType.FUSE)).setText(rule);
Ability ability2 = new DiesAttachedTriggeredAbility(effect, "enchanted creature");
ability.addTarget(new TargetCreatureOrPlayer());
this.addAbility(ability2);
}
public Incendiary(final Incendiary card) {
super(card);
}
@Override
public Incendiary copy() {
return new Incendiary(this);
}
}

View file

@ -1,7 +1,8 @@
package mage.cards.j;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import mage.MageObjectReference;
@ -9,7 +10,6 @@ import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.LoyaltyAbility;
import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.cards.Card;
@ -24,7 +24,10 @@ import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.FilterPlayer;
import mage.filter.common.FilterNonlandCard;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.other.PlayerIdPredicate;
import mage.game.ExileZone;
import mage.game.Game;
import mage.game.events.GameEvent;
@ -32,6 +35,7 @@ import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.TargetPlayer;
import mage.target.common.TargetCardInExile;
import mage.target.common.TargetCardInLibrary;
import mage.target.common.TargetOpponent;
@ -119,9 +123,9 @@ class JaceArchitectOfThoughtDelayedTriggeredAbility extends DelayedTriggeredAbil
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (game.getOpponents(getControllerId()).contains(event.getPlayerId())) {
for (Effect effect : getEffects()) {
getEffects().forEach((effect) -> {
effect.setTargetPointer(new FixedTarget(event.getSourceId()));
}
});
return true;
}
return false;
@ -180,7 +184,6 @@ class JaceArchitectOfThoughtEffect2 extends OneShotEffect {
if (opponent == null) {
opponent = game.getPlayer(opponents.iterator().next());
}
TargetCard target = new TargetCard(0, allCards.size(), Zone.LIBRARY, new FilterCard("cards to put in the first pile"));
target.setNotTarget(true);
opponent.choose(Outcome.Neutral, allCards, target, game);
@ -206,9 +209,9 @@ class JaceArchitectOfThoughtEffect2 extends OneShotEffect {
private void postPileToLog(String pileName, Set<Card> cards, Game game) {
StringBuilder message = new StringBuilder(pileName).append(": ");
for (Card card : cards) {
cards.forEach((card) -> {
message.append(card.getName()).append(' ');
}
});
if (cards.isEmpty()) {
message.append(" (empty)");
}
@ -239,30 +242,65 @@ class JaceArchitectOfThoughtEffect3 extends OneShotEffect {
if (controller == null || sourcePermanent == null) {
return false;
}
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
Player player = game.getPlayer(playerId);
String playerName = new StringBuilder(player.getLogName()).append("'s").toString();
if (source.isControlledBy(player.getId())) {
playerName = "your";
}
TargetCardInLibrary target = new TargetCardInLibrary(new FilterNonlandCard(new StringBuilder("nonland card from ").append(playerName).append(" library").toString()));
if (controller.searchLibrary(target, game, playerId)) {
UUID targetId = target.getFirstTarget();
Card card = player.getLibrary().remove(targetId, game);
if (card != null) {
controller.moveCardToExileWithInfo(card, CardUtil.getCardExileZoneId(game, source), sourcePermanent.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true);
}
}
player.shuffleLibrary(source, game);
if (controller.chooseUse(Outcome.Benefit, "Look at all players' libraries before card select?", null, game)) {
game.informPlayers(controller.getLogName() + " is looking at all players' libraries.");
controller.lookAtAllLibraries(source, game);
}
List<UUID> playerList = new ArrayList<>();
playerList.addAll(game.getState().getPlayersInRange(controller.getId(), game));
Set<UUID> checkList = new HashSet<>();
while (!playerList.isEmpty()) {
FilterPlayer filter = new FilterPlayer();
List<PlayerIdPredicate> playerPredicates = new ArrayList<>();
playerList.forEach((playerId) -> {
playerPredicates.add(new PlayerIdPredicate(playerId));
});
filter.add(Predicates.or(playerPredicates));
TargetPlayer targetPlayer = new TargetPlayer(1, 1, true, filter);
targetPlayer.setRequired(!checkList.containsAll(playerList));
if (controller.chooseTarget(outcome, targetPlayer, source, game)) {
UUID playerId = targetPlayer.getFirstTarget();
Player player = game.getPlayer(playerId);
if (player != null) {
String playerName = new StringBuilder(player.getLogName()).append("'s").toString();
if (source.isControlledBy(player.getId())) {
playerName = "your";
}
TargetCardInLibrary target = new TargetCardInLibrary(new FilterNonlandCard(new StringBuilder("nonland card from ").append(playerName).append(" library").toString()));
if (controller.searchLibrary(target, game, playerId, !checkList.contains(playerId))) {
checkList.add(playerId);
UUID targetId = target.getFirstTarget();
Card card = player.getLibrary().remove(targetId, game);
if (card != null) {
controller.moveCardsToExile(card, source, game, true, CardUtil.getCardExileZoneId(game, source), sourcePermanent.getName());
playerList.remove(playerId);
}
} else {
playerList.remove(playerId);
}
} else {
playerList.remove(playerId);
}
} else {
break;
}
playerList.stream().map((playerId) -> game.getPlayer(playerId)).filter((player) -> (player == null
|| !player.canRespond())).forEachOrdered((player) -> {
playerList.remove(player.getId());
});
}
checkList.stream().map((playerId) -> game.getPlayer(playerId)).filter((player) -> (player != null)).forEachOrdered((player) -> {
player.shuffleLibrary(source, game);
});
ExileZone jaceExileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source));
if (jaceExileZone == null) {
return true;
}
FilterCard filter = new FilterCard("card to cast without mana costs");
TargetCardInExile target = new TargetCardInExile(filter, source.getSourceId());
while (jaceExileZone.count(filter, game) > 0 && controller.choose(Outcome.PlayForFree, jaceExileZone, target, game)) {
while (jaceExileZone.count(filter, game) > 0
&& controller.chooseUse(Outcome.Benefit, "Cast another spell from exile zone for free?", source, game)) {
controller.choose(Outcome.PlayForFree, jaceExileZone, target, game);
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
if (controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) {

View file

@ -0,0 +1,49 @@
package mage.cards.k;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.dynamicvalue.common.TargetConvertedManaCost;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.PreventDamageByTargetEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Zone;
import mage.target.common.TargetControlledCreaturePermanent;
/**
*
* @author L_J
*/
public final class KryShield extends CardImpl {
public KryShield(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}");
// {2}, {T}: Prevent all damage that would be dealt this turn by target creature you control. That creature gets +0/+X until end of turn, where X is its converted mana cost.
Effect effect = new PreventDamageByTargetEffect(Duration.EndOfTurn);
effect.setText("Prevent all damage that would be dealt this turn by target creature you control");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new GenericManaCost(2));
ability.addEffect(new BoostTargetEffect(new StaticValue(0), new TargetConvertedManaCost(), Duration.EndOfTurn, true)
.setText("That creature gets +0/+X until end of turn, where X is its converted mana cost"));
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetControlledCreaturePermanent());
this.addAbility(ability);
}
public KryShield(final KryShield card) {
super(card);
}
@Override
public KryShield copy() {
return new KryShield(this);
}
}

View file

@ -0,0 +1,130 @@
package mage.cards.l;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.StateTriggeredAbility;
import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.token.TokenImpl;
/**
*
* @author jeffwadsworth
*/
public final class LurkingJackals extends CardImpl {
public LurkingJackals(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}");
// When an opponent has 10 or less life, if Lurking Jackals is an enchantment, it becomes a 3/2 Hound creature.
this.addAbility(new LurkingJackalsStateTriggeredAbility());
}
public LurkingJackals(final LurkingJackals card) {
super(card);
}
@Override
public LurkingJackals copy() {
return new LurkingJackals(this);
}
}
class LurkingJackalsStateTriggeredAbility extends StateTriggeredAbility {
public LurkingJackalsStateTriggeredAbility() {
super(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new LurkingJackalsToken(), "", Duration.Custom, true, false));
}
public LurkingJackalsStateTriggeredAbility(final LurkingJackalsStateTriggeredAbility ability) {
super(ability);
}
@Override
public LurkingJackalsStateTriggeredAbility copy() {
return new LurkingJackalsStateTriggeredAbility(this);
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (game.getOpponents(getControllerId()) != null) {
for (UUID opponentId : game.getOpponents(getControllerId())) {
if (game.getPlayer(opponentId).getLife() <= 10) {
return true;
}
}
}
return false;
}
@Override
public boolean checkInterveningIfClause(Game game) {
if (getSourcePermanentIfItStillExists(game) != null) {
return getSourcePermanentIfItStillExists(game).isEnchantment();
}
return false;
}
@Override
public boolean canTrigger(Game game) {
//20100716 - 603.8
Boolean triggered = (Boolean) game.getState().getValue(getSourceId().toString() + "triggered");
if (triggered == null) {
triggered = Boolean.FALSE;
}
return !triggered;
}
@Override
public void trigger(Game game, UUID controllerId) {
//20100716 - 603.8
game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.TRUE);
super.trigger(game, controllerId);
}
@Override
public boolean resolve(Game game) {
//20100716 - 603.8
boolean result = super.resolve(game);
game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.FALSE);
return result;
}
@Override
public void counter(Game game) {
game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.FALSE);
}
@Override
public String getRule() {
return new StringBuilder("When an opponent has 10 or less life, if {this} is an enchantment, ").append(super.getRule()).toString();
}
}
class LurkingJackalsToken extends TokenImpl {
public LurkingJackalsToken() {
super("Hound", "3/2 Hound creature");
cardType.add(CardType.CREATURE);
subtype.add(SubType.HOUND);
power = new MageInt(3);
toughness = new MageInt(2);
}
public LurkingJackalsToken(final LurkingJackalsToken token) {
super(token);
}
@Override
public LurkingJackalsToken copy() {
return new LurkingJackalsToken(this);
}
}

View file

@ -0,0 +1,47 @@
package mage.cards.m;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.EnchantedSourceCondition;
import mage.abilities.decorator.ConditionalRestrictionEffect;
import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect;
import mage.constants.SubType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
/**
*
* @author jeffwadsworth
*/
public final class MetathranElite extends CardImpl {
private static final String rule = "{this} is unblockable as long as it's enchanted.";
public MetathranElite(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{U}");
this.subtype.add(SubType.METATHRAN);
this.subtype.add(SubType.SOLDIER);
this.power = new MageInt(2);
this.toughness = new MageInt(3);
// Metathran Elite is unblockable as long as it's enchanted.
ConditionalRestrictionEffect effect = new ConditionalRestrictionEffect(
new CantBeBlockedSourceEffect(), new EnchantedSourceCondition());
effect.setText(rule);
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
}
public MetathranElite(final MetathranElite card) {
super(card);
}
@Override
public MetathranElite copy() {
return new MetathranElite(this);
}
}

View file

@ -1,17 +1,10 @@
package mage.cards.m;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.FilterCard;
@ -20,8 +13,11 @@ import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetDiscard;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class MindBomb extends CardImpl {
@ -67,6 +63,7 @@ class MindBombEffect extends OneShotEffect {
if (controller != null && sourceObject != null) {
Map<UUID, Cards> cardsToDiscard = new HashMap<>();
// choose
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
Player player = game.getPlayer(playerId);
if (player != null) {
@ -77,6 +74,8 @@ class MindBombEffect extends OneShotEffect {
cardsToDiscard.put(playerId, cards);
}
}
// discard
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
Player player = game.getPlayer(playerId);
if (player != null) {
@ -91,31 +90,17 @@ class MindBombEffect extends OneShotEffect {
}
}
}
// damage
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
Player player = game.getPlayer(playerId);
if (player != null) {
Cards cardsPlayer = cardsToDiscard.get(playerId);
if (cardsPlayer != null && !cardsPlayer.isEmpty()) {
if (cardsPlayer != null) {
player.damage(3 - cardsPlayer.size(), source.getId(), game, false, true);
}
}
}
// reveal the searched lands, put in hands, and shuffle
// for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
// Player player = game.getPlayer(playerId);
// if (player != null) {
// Cards cardsPlayer = cardsToReveal.get(playerId);
// if (cardsPlayer != null) {
// for (UUID cardId : cardsPlayer) {
// Cards cards = new CardsImpl(game.getCard(cardId));
// Card card = game.getCard(cardId);
// player.revealCards(sourceObject.getIdName() + " (" + player.getName() + ')', cards, game);
// player.moveCards(card, Zone.HAND, source, game);
// player.shuffleLibrary(source, game);
// }
// }
// }
// }
return true;
}
return false;

View file

@ -10,10 +10,11 @@ import mage.constants.*;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.Player;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import mage.abilities.effects.AsThoughManaEffect;
import mage.players.ManaPoolItem;
/**
* @author TheElk801
@ -69,17 +70,18 @@ class MnemonicBetrayalExileEffect extends OneShotEffect {
}
Cards cards = new CardsImpl();
Map<UUID, Integer> cardMap = new HashMap();
for (UUID playerId : game.getOpponents(source.getControllerId())) {
Player player = game.getPlayer(playerId);
if (player != null) {
cards.addAll(player.getGraveyard());
}
}
for (Card card : cards.getCards(game)) {
game.getOpponents(source.getControllerId()).stream().map((playerId) -> game.getPlayer(playerId)).filter((player) -> (player != null)).forEachOrdered((player) -> {
cards.addAll(player.getGraveyard());
});
cards.getCards(game).stream().map((card) -> {
cardMap.put(card.getId(), card.getZoneChangeCounter(game));
return card;
}).map((card) -> {
game.addEffect(new MnemonicBetrayalCastFromExileEffect(card, game), source);
return card;
}).forEachOrdered((card) -> {
game.addEffect(new MnemonicBetrayalAnyColorEffect(card, game), source);
}
});
controller.moveCardsToExile(cards.getCards(game), source, game, true, source.getSourceId(), source.getSourceObjectIfItStillExists(game).getName());
game.addDelayedTriggeredAbility(new MnemonicBetrayalDelayedTriggeredAbility(cards, cardMap), source);
return true;
@ -125,7 +127,7 @@ class MnemonicBetrayalCastFromExileEffect extends AsThoughEffectImpl {
}
}
class MnemonicBetrayalAnyColorEffect extends AsThoughEffectImpl {
class MnemonicBetrayalAnyColorEffect extends AsThoughEffectImpl implements AsThoughManaEffect {
private final Card card;
private final int zoneCounter;
@ -154,13 +156,21 @@ class MnemonicBetrayalAnyColorEffect extends AsThoughEffectImpl {
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
if (card.getZoneChangeCounter(game) != zoneCounter) {
this.discard();
return false;
if (objectId.equals(card.getId())
&& card.getZoneChangeCounter(game) <= zoneCounter + 1
&& affectedControllerId.equals(source.getControllerId())) {
return true;
} else {
if (objectId.equals(card.getId())) {
this.discard();
}
}
return objectId.equals(card.getId())
&& card.getZoneChangeCounter(game) == zoneCounter
&& affectedControllerId.equals(source.getControllerId());
return false;
}
@Override
public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) {
return mana.getFirstAvailable();
}
}
@ -240,12 +250,10 @@ class MnemonicBetrayalReturnEffect extends OneShotEffect {
return false;
}
Cards cardsToReturn = new CardsImpl();
for (Card card : cards.getCards(game)) {
if (game.getState().getZone(card.getId()) == Zone.EXILED
&& card.getZoneChangeCounter(game) == cardMap.getOrDefault(card.getId(), -5) + 1) {
cardsToReturn.add(card);
}
}
cards.getCards(game).stream().filter((card) -> (game.getState().getZone(card.getId()) == Zone.EXILED
&& card.getZoneChangeCounter(game) == cardMap.getOrDefault(card.getId(), -5) + 1)).forEachOrdered((card) -> {
cardsToReturn.add(card);
});
return player.moveCards(cardsToReturn, Zone.GRAVEYARD, source, game);
}
}

View file

@ -0,0 +1,60 @@
package mage.cards.m;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.SacrificeSourceEffect;
import mage.constants.SubType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.AnotherPredicate;
import mage.target.TargetPlayer;
/**
*
* @author jeffwadsworth
*/
public final class MoggBombers extends CardImpl {
private static final String rule = "When another creature enters the battlefield, sacrifice {this} and it deals 3 damage to target player.";
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature");
static {
filter.add(new AnotherPredicate());
}
public MoggBombers(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}");
this.subtype.add(SubType.GOBLIN);
this.power = new MageInt(3);
this.toughness = new MageInt(4);
// When another creature enters the battlefield, sacrifice Mogg Bombers and it deals 3 damage to target player.
Effect sacrificeMoggBombers = new SacrificeSourceEffect();
Effect damageTargetPlayer = new DamageTargetEffect(3);
Ability ability = new EntersBattlefieldAllTriggeredAbility(
Zone.BATTLEFIELD,
sacrificeMoggBombers,
filter, false, rule);
ability.addEffect(damageTargetPlayer);
ability.addTarget(new TargetPlayer());
this.addAbility(ability);
}
public MoggBombers(final MoggBombers card) {
super(card);
}
@Override
public MoggBombers copy() {
return new MoggBombers(this);
}
}

View file

@ -1,11 +1,11 @@
package mage.cards.m;
import java.util.UUID;
import mage.abilities.effects.common.SkipNextCombatEffect;
import mage.abilities.effects.common.SkipCombatStepEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.target.TargetPlayer;
/**
@ -13,19 +13,19 @@ import mage.target.TargetPlayer;
* @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
*/
public final class MomentOfSilence extends CardImpl {
public MomentOfSilence(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{W}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}");
// Target player skips their next combat phase this turn.
this.getSpellAbility().addEffect(new SkipNextCombatEffect());
this.getSpellAbility().addEffect(new SkipCombatStepEffect(Duration.EndOfTurn).setText("Target player skips their next combat this turn"));
this.getSpellAbility().addTarget(new TargetPlayer());
}
public MomentOfSilence(final MomentOfSilence card) {
super(card);
}
@Override
public MomentOfSilence copy() {
return new MomentOfSilence(this);

View file

@ -54,12 +54,18 @@ class OpalAvengerStateTriggeredAbility extends StateTriggeredAbility {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return game.getState().getPlayer(getControllerId()).getLife() <= 10;
if (game.getState().getPlayer(getControllerId()) != null) {
return game.getState().getPlayer(getControllerId()).getLife() <= 10;
}
return false;
}
@Override
public boolean checkInterveningIfClause(Game game) {
return this.getSourcePermanentIfItStillExists(game).getCardType().contains(CardType.ENCHANTMENT);
if (getSourcePermanentIfItStillExists(game) != null) {
return getSourcePermanentIfItStillExists(game).isEnchantment();
}
return false;
}
@Override

View file

@ -1,4 +1,3 @@
package mage.cards.o;
import java.util.UUID;
@ -30,12 +29,13 @@ public final class OuterRimSlaver extends CardImpl {
this.toughness = new MageInt(3);
// When Outer Rim Slaver enters the battlefield, you may put a bounty counter on target creature. If you do, another target creature fights that creature
Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.BOUNTY.createInstance()), true);
ability.addEffect(new FightTargetsEffect("another target creature fights that creature"));
TargetCreaturePermanent target = new TargetCreaturePermanent();
Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.BOUNTY.createInstance())
.setText("you may put a bounty counter on target creature"), true);
ability.addEffect(new FightTargetsEffect("If you do, another target creature fights that creature"));
TargetCreaturePermanent target = new TargetCreaturePermanent(new FilterCreaturePermanent("creature to put a bounty counter on it"));
target.setTargetTag(1);
ability.addTarget(target);
FilterCreaturePermanent filter = new FilterCreaturePermanent();
FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature to fight that creature that gets the bounty counter");
filter.add(new AnotherTargetPredicate(2));
TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter);
target2.setTargetTag(2);

View file

@ -0,0 +1,60 @@
package mage.cards.p;
import java.util.UUID;
import mage.constants.SubType;
import mage.target.common.TargetCreaturePermanent;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.DiesAttachedTriggeredAbility;
import mage.abilities.dynamicvalue.common.CountersSourceCount;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.constants.Outcome;
import mage.target.TargetPermanent;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.counters.CounterType;
/**
*
* @author jeffwadsworth
*/
public final class PrivateResearch extends CardImpl {
private static final String rule = "draw a card for each page counter on {this}.";
public PrivateResearch(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}");
this.subtype.add(SubType.AURA);
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature));
Ability ability = new EnchantAbility(auraTarget.getTargetName());
this.addAbility(ability);
// At the beginning of your upkeep, you may put a page counter on Private Research.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD,
new AddCountersSourceEffect(CounterType.PAGE.createInstance(), true), TargetController.YOU, true));
// When enchanted creature dies, draw a card for each page counter on Private Research.
this.addAbility(new DiesAttachedTriggeredAbility(new DrawCardSourceControllerEffect(new CountersSourceCount(CounterType.PAGE)).setText(rule), "enchanted creature"));
}
public PrivateResearch(final PrivateResearch card) {
super(card);
}
@Override
public PrivateResearch copy() {
return new PrivateResearch(this);
}
}

View file

@ -1,4 +1,3 @@
package mage.cards.p;
import java.util.UUID;
@ -11,8 +10,8 @@ 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.filter.common.FilterControlledCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
@ -26,7 +25,7 @@ import mage.target.common.TargetControlledPermanent;
public final class ProwlingPangolin extends CardImpl {
public ProwlingPangolin(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}");
this.subtype.add(SubType.BEAST, SubType.PANGOLIN);
this.power = new MageInt(6);
this.toughness = new MageInt(5);

View file

@ -1,4 +1,3 @@
package mage.cards.r;
import java.util.UUID;
@ -8,12 +7,13 @@ import mage.abilities.common.CantBlockAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.ManaWasSpentCondition;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.SkipNextCombatEffect;
import mage.abilities.effects.common.SkipCombatStepEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.ColoredManaSymbol;
import mage.constants.Duration;
import mage.target.TargetPlayer;
import mage.watchers.common.ManaSpentToCastWatcher;
@ -22,26 +22,26 @@ import mage.watchers.common.ManaSpentToCastWatcher;
* @author ilcartographer
*/
public final class RevenantPatriarch extends CardImpl {
public RevenantPatriarch(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}");
this.subtype.add(SubType.SPIRIT);
this.power = new MageInt(4);
this.toughness = new MageInt(3);
// When Revenant Patriarch enters the battlefield, if {W} was spent to cast it, target player skips their next combat phase.
TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new SkipNextCombatEffect(), false);
TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new SkipCombatStepEffect(Duration.OneUse).setText("target player skips their next combat phase."), false);
ability.addTarget(new TargetPlayer());
this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new ManaWasSpentCondition(ColoredManaSymbol.W),
"if {W} was spent to cast it, target player skips their next combat phase."), new ManaSpentToCastWatcher());
// Revenant Patriarch can't block.
this.addAbility(new CantBlockAbility());
}
public RevenantPatriarch(final RevenantPatriarch card) {
super(card);
}
@Override
public RevenantPatriarch copy() {
return new RevenantPatriarch(this);

View file

@ -0,0 +1,105 @@
package mage.cards.r;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.filter.FilterSpell;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.game.Game;
import mage.game.events.DamageEvent;
import mage.game.events.GameEvent;
import mage.game.stack.Spell;
import mage.players.Player;
import mage.target.TargetSpell;
/**
*
* @author L_J
*/
public final class Reverberation extends CardImpl {
private static final FilterSpell filter = new FilterSpell("sorcery spell");
static {
filter.add(new CardTypePredicate(CardType.SORCERY));
}
public Reverberation(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}{U}");
// All damage that would be dealt this turn by target sorcery spell is dealt to that spells controller instead.
this.getSpellAbility().addEffect(new ReverberationEffect());
this.getSpellAbility().addTarget(new TargetSpell(filter));
}
public Reverberation(final Reverberation card) {
super(card);
}
@Override
public Reverberation copy() {
return new Reverberation(this);
}
}
class ReverberationEffect extends ReplacementEffectImpl {
public ReverberationEffect() {
super(Duration.EndOfTurn, Outcome.RedirectDamage);
staticText = "All damage that would be dealt this turn by target sorcery spell is dealt to that spells controller instead";
}
public ReverberationEffect(final ReverberationEffect effect) {
super(effect);
}
@Override
public ReverberationEffect copy() {
return new ReverberationEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DAMAGE_CREATURE ||
event.getType() == GameEvent.EventType.DAMAGE_PLANESWALKER ||
event.getType() == GameEvent.EventType.DAMAGE_PLAYER;
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
DamageEvent damageEvent = (DamageEvent) event;
if (controller != null) {
Spell targetSpell = game.getStack().getSpell(source.getFirstTarget());
if (targetSpell != null) {
Player targetsController = game.getPlayer(targetSpell.getControllerId());
if (targetsController != null) {
targetsController.damage(damageEvent.getAmount(), damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), damageEvent.getAppliedEffects());
return true;
}
}
}
return false;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
DamageEvent damageEvent = (DamageEvent) event;
Spell targetSpell = game.getStack().getSpell(source.getFirstTarget());
if (targetSpell != null) {
return damageEvent.getAmount() > 0;
}
return false;
}
}

View file

@ -0,0 +1,87 @@
package mage.cards.s;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.choices.ChoiceColor;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetOpponent;
/**
*
* @author jeffwadsworth
*/
public final class ScryingGlass extends CardImpl {
public ScryingGlass(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
// {3}, {tap}: Choose a number greater than 0 and a color. Target opponent reveals his or her hand. If that opponent reveals exactly the chosen number of cards of the chosen color, you draw a card.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ScryingGlassEffect(), new ManaCostsImpl("{3}"));
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetOpponent());
this.addAbility(ability);
}
public ScryingGlass(final ScryingGlass card) {
super(card);
}
@Override
public ScryingGlass copy() {
return new ScryingGlass(this);
}
}
class ScryingGlassEffect extends OneShotEffect {
public ScryingGlassEffect() {
super(Outcome.Neutral);
staticText = "Choose a number greater than 0 and a color. Target opponent reveals his or her hand. If that opponent reveals exactly the chosen number of cards of the chosen color, you draw a card";
}
public ScryingGlassEffect(final ScryingGlassEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Player targetOpponent = game.getPlayer(source.getFirstTarget());
ChoiceColor color = new ChoiceColor();
int amount = 0;
if (controller != null
&& targetOpponent != null) {
amount = controller.getAmount(1, Integer.MAX_VALUE, "Choose a number", game);
controller.choose(Outcome.Discard, color, game);
FilterCard filter = new FilterCard();
filter.add(new ColorPredicate(color.getColor()));
targetOpponent.revealCards(source, targetOpponent.getHand(), game);
if (targetOpponent.getHand().count(filter, game) == amount) {
game.informPlayers(controller.getName() + " has chosen the exact number and color of the revealed cards from " + targetOpponent.getName() + "'s hand. They draw a card.");
controller.drawCards(1, game);
return true;
} else {
game.informPlayers(controller.getName() + " has chosen incorrectly and will not draw a card.");
}
}
return false;
}
@Override
public ScryingGlassEffect copy() {
return new ScryingGlassEffect(this);
}
}

View file

@ -0,0 +1,129 @@
package mage.cards.s;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AsEntersBattlefieldAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.Cost;
import mage.abilities.costs.CostImpl;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.CountersSourceCount;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.RegenerateSourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.constants.SubType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
/**
*
* @author jeffwadsworth
*/
public final class SkeletonScavengers extends CardImpl {
public SkeletonScavengers(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}");
this.subtype.add(SubType.SKELETON);
this.power = new MageInt(0);
this.toughness = new MageInt(0);
// Skeleton Scavengers enters the battlefield with a +1/+1 counter on it.
this.addAbility(new AsEntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())));
// Pay {1} for each +1/+1 counter on Skeleton Scavengers: Regenerate Skeleton Scavengers. When it regenerates this way, put a +1/+1 counter on it.
this.addAbility(new SimpleActivatedAbility(new SkeletonScavengersEffect(), new DynamicValueGenericManaCost(new CountersSourceCount(CounterType.P1P1))));
}
public SkeletonScavengers(final SkeletonScavengers card) {
super(card);
}
@Override
public SkeletonScavengers copy() {
return new SkeletonScavengers(this);
}
}
class DynamicValueGenericManaCost extends CostImpl {
DynamicValue amount;
public DynamicValueGenericManaCost(DynamicValue amount) {
this.amount = amount;
setText();
}
public DynamicValueGenericManaCost(DynamicValueGenericManaCost cost) {
super(cost);
this.amount = cost.amount;
}
@Override
public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
Player controller = game.getPlayer(controllerId);
if (controller == null) {
return false;
}
int convertedCost = amount.calculate(game, ability, null);
Cost cost = new GenericManaCost(convertedCost);
return cost.canPay(ability, sourceId, controllerId, game);
}
@Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
Player controller = game.getPlayer(controllerId);
int convertedCost = amount.calculate(game, ability, null);
Cost cost = new GenericManaCost(convertedCost);
if (controller != null) {
paid = cost.pay(ability, game, sourceId, controllerId, noMana);
}
return paid;
}
@Override
public DynamicValueGenericManaCost copy() {
return new DynamicValueGenericManaCost(this);
}
private void setText() {
text = ("Pay {1} for each +1/+1 counter on {this}");
}
}
class SkeletonScavengersEffect extends OneShotEffect {
SkeletonScavengersEffect() {
super(Outcome.Benefit);
this.staticText = "Regenerate {this}. When it regenerates this way, put a +1/+1 counter on it";
}
SkeletonScavengersEffect(final SkeletonScavengersEffect effect) {
super(effect);
}
@Override
public SkeletonScavengersEffect copy() {
return new SkeletonScavengersEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent skeletonScavengers = game.getPermanent(source.getSourceId());
if (skeletonScavengers != null) {
if (new RegenerateSourceEffect().apply(game, source)) {
return new AddCountersSourceEffect(CounterType.P1P1.createInstance()).apply(game, source);
}
}
return false;
}
}

View file

@ -1,6 +1,5 @@
package mage.cards.s;
import mage.abilities.costs.mana.VariableManaCost;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DoUnlessAnyPlayerPaysEffect;
import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect;
@ -11,6 +10,7 @@ import mage.filter.common.FilterCreatureCard;
import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID;
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
/**
* @author jmharmon
@ -23,8 +23,7 @@ public final class SoulStrings extends CardImpl {
// Return two target creature cards from your graveyard to your hand unless any player pays {X}.
Effect effect = new DoUnlessAnyPlayerPaysEffect(
new ReturnFromGraveyardToHandTargetEffect(), new VariableManaCost()
);
new ReturnFromGraveyardToHandTargetEffect(), new ManacostVariableValue());
this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(2, new FilterCreatureCard("creature cards from your graveyard")));
}

View file

@ -1,4 +1,3 @@
package mage.cards.s;
import java.util.UUID;
@ -65,21 +64,22 @@ class StadiumVendorsEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getSourceId());
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
TargetPlayer target = new TargetPlayer(1, 1, true);
if (!controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) {
return false;
if (controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) {
Player player = game.getPlayer(target.getFirstTarget());
ChoiceColor colorChoice = new ChoiceColor(true);
if (player == null
|| !player.choose(Outcome.Benefit, colorChoice, game)) {
return false;
}
Effect effect = new AddManaToManaPoolTargetControllerEffect(colorChoice.getMana(2), "that player's");
effect.setTargetPointer(new FixedTarget(player.getId(), game));
return effect.apply(game, source);
}
Player player = game.getPlayer(target.getFirstTarget());
ChoiceColor colorChoice = new ChoiceColor(true);
if (player == null || !player.choose(Outcome.Benefit, colorChoice, game)) {
return false;
}
Effect effect = new AddManaToManaPoolTargetControllerEffect(colorChoice.getMana(2), "that player's");
effect.setTargetPointer(new FixedTarget(player.getId(), game));
return effect.apply(game, source);
return false;
}
}

View file

@ -1,14 +1,14 @@
package mage.cards.s;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.SkipNextCombatEffect;
import mage.abilities.effects.common.SkipCombatStepEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.target.common.TargetOpponent;
@ -17,27 +17,27 @@ import mage.target.common.TargetOpponent;
* @author nantuko
*/
public final class StonehornDignitary extends CardImpl {
public StonehornDignitary(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}");
this.subtype.add(SubType.RHINO);
this.subtype.add(SubType.SOLDIER);
this.power = new MageInt(1);
this.toughness = new MageInt(4);
// When Stonehorn Dignitary enters the battlefield, target opponent skips their next combat phase.
Ability ability = new EntersBattlefieldTriggeredAbility(new SkipNextCombatEffect());
Ability ability = new EntersBattlefieldTriggeredAbility(new SkipCombatStepEffect(Duration.OneUse).setText("target opponent skips their next combat phase."));
ability.addTarget(new TargetOpponent());
this.addAbility(ability);
}
public StonehornDignitary(final StonehornDignitary card) {
super(card);
}
@Override
public StonehornDignitary copy() {
return new StonehornDignitary(this);
}
}
}

View file

@ -0,0 +1,39 @@
package mage.cards.s;
import java.util.UUID;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.dynamicvalue.common.TargetConvertedManaCost;
import mage.abilities.effects.common.PreventDamageByTargetEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author L_J
*/
public final class Subdue extends CardImpl {
public Subdue(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}");
// Prevent all combat damage that would be dealt by target creature this turn. That creature gets +0/+X until end of turn, where X is its converted mana cost.
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
this.getSpellAbility().addEffect(new PreventDamageByTargetEffect(Duration.EndOfTurn, true));
this.getSpellAbility().addEffect(new BoostTargetEffect(new StaticValue(0), new TargetConvertedManaCost(), Duration.EndOfTurn, true)
.setText("That creature gets +0/+X until end of turn, where X is its converted mana cost"));
}
public Subdue(final Subdue card) {
super(card);
}
@Override
public Subdue copy() {
return new Subdue(this);
}
}

View file

@ -1,4 +1,3 @@
package mage.cards.t;
import java.util.UUID;
@ -13,7 +12,6 @@ import mage.constants.SagaChapter;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate;
@ -35,11 +33,12 @@ public final class TheEldestReborn extends CardImpl {
}
private static final FilterControlledPermanent filterSacrifice = new FilterControlledPermanent("creature or planeswalker");
static {
filterSacrifice.add(Predicates.or(
new CardTypePredicate(CardType.CREATURE),
new CardTypePredicate(CardType.PLANESWALKER)
));
new CardTypePredicate(CardType.CREATURE),
new CardTypePredicate(CardType.PLANESWALKER)
));
}

View file

@ -67,7 +67,10 @@ class VeiledCrocodileStateTriggeredAbility extends StateTriggeredAbility {
@Override
public boolean checkInterveningIfClause(Game game) {
return this.getSourcePermanentIfItStillExists(game).getCardType().contains(CardType.ENCHANTMENT);
if (getSourcePermanentIfItStillExists(game) != null) {
return getSourcePermanentIfItStillExists(game).isEnchantment();
}
return false;
}
@Override

View file

@ -79,7 +79,9 @@ class ViashinoBeyEffect extends OneShotEffect {
} else {
targetDefender.add(game.getOpponents(controller.getId()).iterator().next(), game);
}
controller.declareAttacker(permanent.getId(), targetDefender.getFirstTarget(), game, false);
if (permanent.canAttack(targetDefender.getFirstTarget(), game)) {
controller.declareAttacker(permanent.getId(), targetDefender.getFirstTarget(), game, false);
}
});
}
return false;

View file

@ -0,0 +1,59 @@
package mage.cards.w;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.OpponentControlsPermanentCondition;
import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect;
import mage.abilities.effects.ContinuousRuleModifyingEffect;
import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect;
import mage.abilities.keyword.CantBeBlockedSourceAbility;
import mage.constants.SubType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
/**
*
* @author jeffwadsworth
*/
public final class WalkingDream extends CardImpl {
private static final String rule = "{this} doesn't untap during your untap step if an opponent controls two or more creatures.";
public WalkingDream(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}");
this.subtype.add(SubType.ILLUSION);
this.power = new MageInt(3);
this.toughness = new MageInt(3);
// Walking Dream is unblockable.
this.addAbility(new CantBeBlockedSourceAbility());
// Walking Dream doesn't untap during your untap step if an opponent controls two or more creatures.
ContinuousRuleModifyingEffect dontUntap = new DontUntapInControllersUntapStepSourceEffect(false, true);
dontUntap.setText(rule);
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD,
new ConditionalContinuousRuleModifyingEffect(
dontUntap,
new OpponentControlsPermanentCondition(
new FilterCreaturePermanent(),
ComparisonType.MORE_THAN, 1)));
this.addAbility(ability);
}
public WalkingDream(final WalkingDream card) {
super(card);
}
@Override
public WalkingDream copy() {
return new WalkingDream(this);
}
}

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